duonghoang commited on
Commit
8a2d626
·
1 Parent(s): f8c5450

Restore single-button UI and refine answer formatting

Browse files
Files changed (2) hide show
  1. agent.py +36 -3
  2. app.py +57 -23
agent.py CHANGED
@@ -1,10 +1,11 @@
1
  import asyncio
2
  import os
3
  import re
 
4
  from pathlib import Path
5
  from threading import Thread
6
  from typing import Any
7
- from urllib.parse import quote_plus, urlparse, parse_qs
8
 
9
  import requests
10
 
@@ -34,9 +35,14 @@ or the phrase "FINAL ANSWER". The scoring is exact match, so be concise:
34
  - If the answer is a name, title, date, URL, or short phrase, return only that.
35
  - Preserve capitalization only when it matters for the answer.
36
  - If the question asks for a comma-separated list, use that format exactly.
 
37
  """
38
 
39
 
 
 
 
 
40
  def _read_text_file(path: Path) -> str:
41
  for encoding in ("utf-8", "utf-8-sig", "latin-1"):
42
  try:
@@ -92,10 +98,12 @@ def _summarize_pdf(path: Path) -> str:
92
 
93
  def summarize_attachment(file_path: str | None, file_name: str | None) -> str:
94
  if not file_path:
 
95
  return "No attachment."
96
 
97
  path = Path(file_path)
98
  suffix = path.suffix.lower()
 
99
 
100
  try:
101
  if suffix in {".txt", ".md", ".json", ".html", ".xml", ".py", ".csv"}:
@@ -153,6 +161,7 @@ def _get_youtube_context(question: str) -> str:
153
  if not video_id:
154
  return ""
155
 
 
156
  try:
157
  from youtube_transcript_api import YouTubeTranscriptApi
158
  except ImportError:
@@ -164,6 +173,7 @@ def _get_youtube_context(question: str) -> str:
164
  else:
165
  transcript = YouTubeTranscriptApi().fetch(video_id, languages=["en", "en-US"])
166
  except Exception as exc:
 
167
  return f"YouTube tool: could not fetch transcript for {video_id}: {exc}"
168
 
169
  lines = []
@@ -177,10 +187,12 @@ def _get_youtube_context(question: str) -> str:
177
  text = text.replace("\n", " ").strip()
178
  if text:
179
  lines.append(f"[{start:.1f}s] {text}")
 
180
  return "YouTube transcript:\n" + "\n".join(lines)
181
 
182
 
183
  def _wiki_api_get(params: dict) -> dict:
 
184
  response = requests.get(
185
  "https://en.wikipedia.org/w/api.php",
186
  params={"format": "json", "formatversion": "2", **params},
@@ -236,6 +248,7 @@ def _get_wikipedia_context(question: str) -> str:
236
  if not any(token in lowered for token in ["wikipedia", "featured article", "dinosaur"]):
237
  return ""
238
 
 
239
  queries = [(question, "0")]
240
  if "featured article" in lowered and "dinosaur" in lowered:
241
  queries.extend(
@@ -251,8 +264,10 @@ def _get_wikipedia_context(question: str) -> str:
251
  seen_titles = set()
252
  for query, namespace in queries[:6]:
253
  try:
 
254
  search_results = _wiki_search(query, namespace=namespace, limit="7")
255
  except Exception as exc:
 
256
  parts.append(f"Wikipedia search failed for {query!r}: {exc}")
257
  continue
258
 
@@ -282,10 +297,12 @@ def _get_wikipedia_context(question: str) -> str:
282
  )
283
  for title in ordered_titles[:4]:
284
  try:
 
285
  page_text = _wiki_page_text(title)
286
  if page_text:
287
  parts.append(f"\nPage text: {title}\n{page_text[:3000]}")
288
  except Exception as exc:
 
289
  parts.append(f"Could not fetch page {title!r}: {exc}")
290
 
291
  if "featured article" in lowered and "dinosaur" in lowered:
@@ -322,6 +339,7 @@ def _needs_web_context(question: str) -> bool:
322
 
323
 
324
  def _web_search(query: str, max_results: int = 5) -> list[dict]:
 
325
  try:
326
  from ddgs import DDGS
327
  except ImportError:
@@ -339,7 +357,9 @@ def _web_search(query: str, max_results: int = 5) -> list[dict]:
339
  }
340
  )
341
  except Exception as exc:
 
342
  return [{"title": "Web search failed", "href": "", "body": str(exc)}]
 
343
  return results
344
 
345
 
@@ -347,10 +367,12 @@ def _extract_page_text(url: str, max_chars: int = 5000) -> str:
347
  if not url.startswith(("http://", "https://")):
348
  return ""
349
 
 
350
  try:
351
  response = requests.get(url, headers={"User-Agent": USER_AGENT}, timeout=20)
352
  response.raise_for_status()
353
  except Exception as exc:
 
354
  return f"Could not fetch {url}: {exc}"
355
 
356
  content_type = response.headers.get("content-type", "").lower()
@@ -369,6 +391,7 @@ def _extract_page_text(url: str, max_chars: int = 5000) -> str:
369
 
370
  title = soup.get_text(" ", strip=True)
371
  title = re.sub(r"\s+", " ", title)
 
372
  return title[:max_chars]
373
 
374
 
@@ -376,6 +399,7 @@ def _get_web_context(question: str) -> str:
376
  if not _needs_web_context(question):
377
  return ""
378
 
 
379
  queries = [question]
380
  lowered = question.lower()
381
  if "libretext" in lowered or "libretexts" in lowered or "ck-12" in lowered:
@@ -413,6 +437,7 @@ def _get_web_context(question: str) -> str:
413
 
414
 
415
  def gather_tool_context(question: str) -> str:
 
416
  contexts = []
417
  youtube_context = _get_youtube_context(question)
418
  if youtube_context:
@@ -427,7 +452,9 @@ def gather_tool_context(question: str) -> str:
427
  contexts.append(web_context)
428
 
429
  combined = "\n\n".join(contexts).strip()
 
430
  if len(combined) > MAX_TOOL_CHARS:
 
431
  return combined[:MAX_TOOL_CHARS] + "\n\n[Tool context truncated.]"
432
  return combined or "No external tool context."
433
 
@@ -446,6 +473,8 @@ def clean_final_answer(raw_answer: str) -> str:
446
 
447
  if (answer.startswith('"') and answer.endswith('"')) or (answer.startswith("'") and answer.endswith("'")):
448
  answer = answer[1:-1].strip()
 
 
449
  return answer
450
 
451
 
@@ -531,7 +560,7 @@ class BasicAgent:
531
  "base_url": OPENROUTER_BASE_URL,
532
  }
533
  self.model = model
534
- print(f"BasicAgent initialized with OpenRouter model: {self.model}")
535
 
536
  def _new_agent(self):
537
  # Build a fresh client per task. Reusing the async client across Gradio's
@@ -554,6 +583,7 @@ class BasicAgent:
554
  file_path: str | None = None,
555
  file_name: str | None = None,
556
  ) -> str:
 
557
  attachment_context = summarize_attachment(file_path, file_name)
558
  tool_context = gather_tool_context(question)
559
  prompt = f"""
@@ -571,5 +601,8 @@ External tool context:
571
  Return only the exact final answer.
572
  """
573
 
 
574
  result = _run_coro_sync(self._new_agent().run(prompt))
575
- return clean_final_answer(_result_to_text(result))
 
 
 
1
  import asyncio
2
  import os
3
  import re
4
+ import time
5
  from pathlib import Path
6
  from threading import Thread
7
  from typing import Any
8
+ from urllib.parse import urlparse, parse_qs
9
 
10
  import requests
11
 
 
35
  - If the answer is a name, title, date, URL, or short phrase, return only that.
36
  - Preserve capitalization only when it matters for the answer.
37
  - If the question asks for a comma-separated list, use that format exactly.
38
+ - Do not add a period or any other punctuation at the end unless it is explicitly part of the answer.
39
  """
40
 
41
 
42
+ def log(message: str) -> None:
43
+ print(f"[{time.strftime('%H:%M:%S')}] {message}", flush=True)
44
+
45
+
46
  def _read_text_file(path: Path) -> str:
47
  for encoding in ("utf-8", "utf-8-sig", "latin-1"):
48
  try:
 
98
 
99
  def summarize_attachment(file_path: str | None, file_name: str | None) -> str:
100
  if not file_path:
101
+ log("Attachment tool: no attachment.")
102
  return "No attachment."
103
 
104
  path = Path(file_path)
105
  suffix = path.suffix.lower()
106
+ log(f"Attachment tool: reading {file_name or path.name} ({suffix or 'no extension'}).")
107
 
108
  try:
109
  if suffix in {".txt", ".md", ".json", ".html", ".xml", ".py", ".csv"}:
 
161
  if not video_id:
162
  return ""
163
 
164
+ log(f"YouTube tool: fetching transcript for {video_id}.")
165
  try:
166
  from youtube_transcript_api import YouTubeTranscriptApi
167
  except ImportError:
 
173
  else:
174
  transcript = YouTubeTranscriptApi().fetch(video_id, languages=["en", "en-US"])
175
  except Exception as exc:
176
+ log(f"YouTube tool: failed for {video_id}: {exc}")
177
  return f"YouTube tool: could not fetch transcript for {video_id}: {exc}"
178
 
179
  lines = []
 
187
  text = text.replace("\n", " ").strip()
188
  if text:
189
  lines.append(f"[{start:.1f}s] {text}")
190
+ log(f"YouTube tool: transcript fetched with {len(lines)} line(s).")
191
  return "YouTube transcript:\n" + "\n".join(lines)
192
 
193
 
194
  def _wiki_api_get(params: dict) -> dict:
195
+ log(f"Wikipedia tool: API request {params.get('action')} {params.get('list') or params.get('prop')}.")
196
  response = requests.get(
197
  "https://en.wikipedia.org/w/api.php",
198
  params={"format": "json", "formatversion": "2", **params},
 
248
  if not any(token in lowered for token in ["wikipedia", "featured article", "dinosaur"]):
249
  return ""
250
 
251
+ log("Wikipedia tool: gathering context.")
252
  queries = [(question, "0")]
253
  if "featured article" in lowered and "dinosaur" in lowered:
254
  queries.extend(
 
264
  seen_titles = set()
265
  for query, namespace in queries[:6]:
266
  try:
267
+ log(f"Wikipedia tool: searching namespace {namespace}: {query}")
268
  search_results = _wiki_search(query, namespace=namespace, limit="7")
269
  except Exception as exc:
270
+ log(f"Wikipedia tool: search failed: {exc}")
271
  parts.append(f"Wikipedia search failed for {query!r}: {exc}")
272
  continue
273
 
 
297
  )
298
  for title in ordered_titles[:4]:
299
  try:
300
+ log(f"Wikipedia tool: fetching page text for {title}.")
301
  page_text = _wiki_page_text(title)
302
  if page_text:
303
  parts.append(f"\nPage text: {title}\n{page_text[:3000]}")
304
  except Exception as exc:
305
+ log(f"Wikipedia tool: page fetch failed for {title}: {exc}")
306
  parts.append(f"Could not fetch page {title!r}: {exc}")
307
 
308
  if "featured article" in lowered and "dinosaur" in lowered:
 
339
 
340
 
341
  def _web_search(query: str, max_results: int = 5) -> list[dict]:
342
+ log(f"Web tool: searching: {query}")
343
  try:
344
  from ddgs import DDGS
345
  except ImportError:
 
357
  }
358
  )
359
  except Exception as exc:
360
+ log(f"Web tool: search failed: {exc}")
361
  return [{"title": "Web search failed", "href": "", "body": str(exc)}]
362
+ log(f"Web tool: got {len(results)} result(s).")
363
  return results
364
 
365
 
 
367
  if not url.startswith(("http://", "https://")):
368
  return ""
369
 
370
+ log(f"Web tool: fetching page: {url}")
371
  try:
372
  response = requests.get(url, headers={"User-Agent": USER_AGENT}, timeout=20)
373
  response.raise_for_status()
374
  except Exception as exc:
375
+ log(f"Web tool: fetch failed for {url}: {exc}")
376
  return f"Could not fetch {url}: {exc}"
377
 
378
  content_type = response.headers.get("content-type", "").lower()
 
391
 
392
  title = soup.get_text(" ", strip=True)
393
  title = re.sub(r"\s+", " ", title)
394
+ log(f"Web tool: extracted {min(len(title), max_chars)} char(s) from page.")
395
  return title[:max_chars]
396
 
397
 
 
399
  if not _needs_web_context(question):
400
  return ""
401
 
402
+ log("Web tool: gathering general web context.")
403
  queries = [question]
404
  lowered = question.lower()
405
  if "libretext" in lowered or "libretexts" in lowered or "ck-12" in lowered:
 
437
 
438
 
439
  def gather_tool_context(question: str) -> str:
440
+ log("Tools: gathering external context.")
441
  contexts = []
442
  youtube_context = _get_youtube_context(question)
443
  if youtube_context:
 
452
  contexts.append(web_context)
453
 
454
  combined = "\n\n".join(contexts).strip()
455
+ log(f"Tools: combined context length {len(combined)} char(s).")
456
  if len(combined) > MAX_TOOL_CHARS:
457
+ log(f"Tools: truncating context to {MAX_TOOL_CHARS} char(s).")
458
  return combined[:MAX_TOOL_CHARS] + "\n\n[Tool context truncated.]"
459
  return combined or "No external tool context."
460
 
 
473
 
474
  if (answer.startswith('"') and answer.endswith('"')) or (answer.startswith("'") and answer.endswith("'")):
475
  answer = answer[1:-1].strip()
476
+ if len(answer) > 1 and answer.endswith(".") and not re.search(r"\d\.$", answer):
477
+ answer = answer[:-1].strip()
478
  return answer
479
 
480
 
 
560
  "base_url": OPENROUTER_BASE_URL,
561
  }
562
  self.model = model
563
+ log(f"BasicAgent initialized with OpenRouter model: {self.model}")
564
 
565
  def _new_agent(self):
566
  # Build a fresh client per task. Reusing the async client across Gradio's
 
583
  file_path: str | None = None,
584
  file_name: str | None = None,
585
  ) -> str:
586
+ log(f"Agent: starting task {task_id or 'unknown'}.")
587
  attachment_context = summarize_attachment(file_path, file_name)
588
  tool_context = gather_tool_context(question)
589
  prompt = f"""
 
601
  Return only the exact final answer.
602
  """
603
 
604
+ log(f"Agent: calling OpenRouter model for task {task_id or 'unknown'}.")
605
  result = _run_coro_sync(self._new_agent().run(prompt))
606
+ answer = clean_final_answer(_result_to_text(result))
607
+ log(f"Agent: completed task {task_id or 'unknown'} -> {answer}")
608
+ return answer
app.py CHANGED
@@ -1,5 +1,6 @@
1
  import json
2
  import os
 
3
  from pathlib import Path
4
  from tempfile import TemporaryDirectory
5
  from urllib.parse import quote
@@ -28,6 +29,10 @@ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
28
  CACHE_PATH = Path("answers_cache.json")
29
 
30
 
 
 
 
 
31
  if spaces:
32
  @spaces.GPU(duration=1)
33
  def dummy_gpu():
@@ -49,6 +54,7 @@ def save_cache(cache: dict) -> None:
49
 
50
  def fetch_questions(api_url: str) -> list[dict]:
51
  questions_url = f"{api_url}/questions"
 
52
  response = requests.get(questions_url, timeout=30)
53
  response.raise_for_status()
54
  questions = response.json()
@@ -69,14 +75,17 @@ def download_attachment(item: dict, api_url: str, temp_dir: str) -> tuple[str |
69
  file_url = f"{api_url}/files/{encoded_task_id}"
70
 
71
  try:
 
72
  response = requests.get(file_url, timeout=60)
73
  response.raise_for_status()
74
  except requests.exceptions.HTTPError as exc:
75
  if exc.response is not None and exc.response.status_code == 404:
 
76
  return None, f"Attachment listed as {safe_name}, but the scoring API returned 404 for {file_url}."
77
  raise
78
 
79
  attachment_path.write_bytes(response.content)
 
80
  return str(attachment_path), None
81
 
82
 
@@ -87,6 +96,15 @@ def rows_to_dataframe(rows: list[dict]) -> pd.DataFrame:
87
  )
88
 
89
 
 
 
 
 
 
 
 
 
 
90
  def run_agent(profile: gr.OAuthProfile | None, run_all_questions: bool, use_cache: bool):
91
  if not profile:
92
  return "Please log in to Hugging Face first.", [], rows_to_dataframe([])
@@ -129,10 +147,12 @@ def run_agent(profile: gr.OAuthProfile | None, run_all_questions: bool, use_cach
129
  continue
130
 
131
  cache_key = str(task_id)
 
132
  if use_cache and cache_key in cache:
133
  submitted_answer = cache[cache_key]["submitted_answer"]
134
  source = "cache"
135
  status = "Loaded from answers_cache.json."
 
136
  else:
137
  try:
138
  attachment_path, attachment_error = download_attachment(item, api_url, temp_dir)
@@ -153,10 +173,12 @@ def run_agent(profile: gr.OAuthProfile | None, run_all_questions: bool, use_cach
153
  "submitted_answer": submitted_answer,
154
  }
155
  save_cache(cache)
 
156
  except Exception as exc:
157
  submitted_answer = f"AGENT ERROR: {exc}"
158
  source = "error"
159
  status = str(exc)
 
160
 
161
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
162
  results_log.append(
@@ -169,7 +191,7 @@ def run_agent(profile: gr.OAuthProfile | None, run_all_questions: bool, use_cach
169
  "Status": status,
170
  }
171
  )
172
- print(f"[{index}/{len(questions_data)}] {task_id}: {submitted_answer}")
173
 
174
  status = (
175
  f"Generated {len(answers_payload)} answer(s) for {profile.username}. "
@@ -181,8 +203,12 @@ def run_agent(profile: gr.OAuthProfile | None, run_all_questions: bool, use_cach
181
  def submit_answers(profile: gr.OAuthProfile | None, answers_payload: list[dict] | None):
182
  if not profile:
183
  return "Please log in to Hugging Face first."
 
184
  if not answers_payload:
185
- return "No answers to submit. Run the agent first."
 
 
 
186
 
187
  space_id = os.getenv("SPACE_ID")
188
  if space_id:
@@ -203,6 +229,7 @@ def submit_answers(profile: gr.OAuthProfile | None, answers_payload: list[dict]
203
  return (
204
  "Submission Successful!\n"
205
  f"User: {result_data.get('username')}\n"
 
206
  f"Overall Score: {result_data.get('score', 'N/A')}% "
207
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
208
  f"Message: {result_data.get('message', 'No message received.')}\n"
@@ -219,37 +246,44 @@ def submit_answers(profile: gr.OAuthProfile | None, answers_payload: list[dict]
219
  return f"Submission failed: {exc}"
220
 
221
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  with gr.Blocks() as demo:
223
- gr.Markdown("# Agents Course Unit 4 Runner")
224
  gr.Markdown(
225
- "Generate answers with a Microsoft Agent Framework agent backed by OpenRouter, "
226
- "review them, then submit for scoring."
227
- )
228
 
229
- gr.LoginButton()
 
230
 
231
- answers_state = gr.State([])
 
 
 
 
232
 
233
- with gr.Row():
234
- run_all_checkbox = gr.Checkbox(label="Process all questions", value=True)
235
- use_cache_checkbox = gr.Checkbox(label="Reuse cached answers", value=True)
236
 
237
- run_button = gr.Button("Run Agent")
238
- submit_button = gr.Button("Submit Answers")
239
 
240
- status_output = gr.Textbox(label="Run Status", lines=4, interactive=False)
241
- submit_output = gr.Textbox(label="Submission Result", lines=6, interactive=False)
242
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
243
 
244
  run_button.click(
245
- fn=run_agent,
246
- inputs=[run_all_checkbox, use_cache_checkbox],
247
- outputs=[status_output, answers_state, results_table],
248
- )
249
- submit_button.click(
250
- fn=submit_answers,
251
- inputs=[answers_state],
252
- outputs=[submit_output],
253
  )
254
 
255
 
 
1
  import json
2
  import os
3
+ import time
4
  from pathlib import Path
5
  from tempfile import TemporaryDirectory
6
  from urllib.parse import quote
 
29
  CACHE_PATH = Path("answers_cache.json")
30
 
31
 
32
+ def log(message: str) -> None:
33
+ print(f"[{time.strftime('%H:%M:%S')}] {message}", flush=True)
34
+
35
+
36
  if spaces:
37
  @spaces.GPU(duration=1)
38
  def dummy_gpu():
 
54
 
55
  def fetch_questions(api_url: str) -> list[dict]:
56
  questions_url = f"{api_url}/questions"
57
+ log(f"Fetching questions from {questions_url}")
58
  response = requests.get(questions_url, timeout=30)
59
  response.raise_for_status()
60
  questions = response.json()
 
75
  file_url = f"{api_url}/files/{encoded_task_id}"
76
 
77
  try:
78
+ log(f"Downloading attachment for task {task_id}: {safe_name}")
79
  response = requests.get(file_url, timeout=60)
80
  response.raise_for_status()
81
  except requests.exceptions.HTTPError as exc:
82
  if exc.response is not None and exc.response.status_code == 404:
83
+ log(f"Attachment 404 for task {task_id}: {safe_name}")
84
  return None, f"Attachment listed as {safe_name}, but the scoring API returned 404 for {file_url}."
85
  raise
86
 
87
  attachment_path.write_bytes(response.content)
88
+ log(f"Attachment saved for task {task_id}: {attachment_path}")
89
  return str(attachment_path), None
90
 
91
 
 
96
  )
97
 
98
 
99
+ def cache_to_payload(cache: dict) -> list[dict]:
100
+ payload = []
101
+ for task_id, item in cache.items():
102
+ submitted_answer = item.get("submitted_answer")
103
+ if submitted_answer and not str(submitted_answer).startswith("AGENT ERROR:"):
104
+ payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
105
+ return payload
106
+
107
+
108
  def run_agent(profile: gr.OAuthProfile | None, run_all_questions: bool, use_cache: bool):
109
  if not profile:
110
  return "Please log in to Hugging Face first.", [], rows_to_dataframe([])
 
147
  continue
148
 
149
  cache_key = str(task_id)
150
+ log(f"Task {index}/{len(questions_data)} started: {task_id}")
151
  if use_cache and cache_key in cache:
152
  submitted_answer = cache[cache_key]["submitted_answer"]
153
  source = "cache"
154
  status = "Loaded from answers_cache.json."
155
+ log(f"Task {index}/{len(questions_data)} cache hit: {task_id} -> {submitted_answer}")
156
  else:
157
  try:
158
  attachment_path, attachment_error = download_attachment(item, api_url, temp_dir)
 
173
  "submitted_answer": submitted_answer,
174
  }
175
  save_cache(cache)
176
+ log(f"Task {index}/{len(questions_data)} cached answer: {task_id}")
177
  except Exception as exc:
178
  submitted_answer = f"AGENT ERROR: {exc}"
179
  source = "error"
180
  status = str(exc)
181
+ log(f"Task {index}/{len(questions_data)} error: {task_id}: {exc}")
182
 
183
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
184
  results_log.append(
 
191
  "Status": status,
192
  }
193
  )
194
+ log(f"[{index}/{len(questions_data)}] {task_id}: {submitted_answer}")
195
 
196
  status = (
197
  f"Generated {len(answers_payload)} answer(s) for {profile.username}. "
 
203
  def submit_answers(profile: gr.OAuthProfile | None, answers_payload: list[dict] | None):
204
  if not profile:
205
  return "Please log in to Hugging Face first."
206
+ source_note = "current run"
207
  if not answers_payload:
208
+ answers_payload = cache_to_payload(load_cache())
209
+ if not answers_payload:
210
+ return "No answers to submit. Run the agent first."
211
+ source_note = "answers_cache.json"
212
 
213
  space_id = os.getenv("SPACE_ID")
214
  if space_id:
 
229
  return (
230
  "Submission Successful!\n"
231
  f"User: {result_data.get('username')}\n"
232
+ f"Submitted: {len(answers_payload)} answer(s) from {source_note}\n"
233
  f"Overall Score: {result_data.get('score', 'N/A')}% "
234
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
235
  f"Message: {result_data.get('message', 'No message received.')}\n"
 
246
  return f"Submission failed: {exc}"
247
 
248
 
249
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
250
+ status, answers_payload, results_df = run_agent(
251
+ profile=profile,
252
+ run_all_questions=True,
253
+ use_cache=True,
254
+ )
255
+ if not answers_payload:
256
+ return status, results_df
257
+
258
+ submit_status = submit_answers(profile, answers_payload)
259
+ return f"{status}\n\n{submit_status}", results_df
260
+
261
+
262
  with gr.Blocks() as demo:
263
+ gr.Markdown("# Basic Agent Evaluation Runner")
264
  gr.Markdown(
265
+ """
266
+ **Instructions:**
 
267
 
268
+ 1. Log in to your Hugging Face account using the button below.
269
+ 2. Click 'Run Evaluation & Submit All Answers' to fetch questions, run the agent, submit answers, and see the score.
270
 
271
+ ---
272
+ **Disclaimers:**
273
+ This can take quite some time while the agent works through all questions.
274
+ """
275
+ )
276
 
277
+ gr.LoginButton()
 
 
278
 
279
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
 
280
 
281
+ status_output = gr.Textbox(label="Run Status / Submission Result", lines=8, interactive=False)
 
282
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
283
 
284
  run_button.click(
285
+ fn=run_and_submit_all,
286
+ outputs=[status_output, results_table],
 
 
 
 
 
 
287
  )
288
 
289