Viske commited on
Commit
e23fbd2
·
verified ·
1 Parent(s): dff8f68

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +305 -390
app.py CHANGED
@@ -1,109 +1,114 @@
1
  import os
2
  import json
3
  import re
4
-
5
  import gradio as gr
6
- import pandas as pd
 
7
 
8
  from huggingface_hub import InferenceClient
9
 
10
  from prompt import SYSTEM_PROMPT
11
-
12
- from tools import (
13
- execute_tool,
14
- download_file
15
- )
16
-
17
- import requests
18
 
19
 
20
  # ============================================================
21
  # CONFIG
22
  # ============================================================
23
 
24
- SCORING_API = (
25
- "https://agents-course-unit4-scoring.hf.space"
26
- )
27
 
28
- MODEL_ID = os.getenv(
29
- "TEXT_MODEL",
30
- "Qwen/Qwen2.5-72B-Instruct"
31
- )
32
 
33
  HF_TOKEN = os.getenv("HF_TOKEN")
34
 
35
- MAX_STEPS = 10
36
-
37
-
38
  client = InferenceClient(
 
39
  token=HF_TOKEN
40
  )
41
 
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  # ============================================================
44
  # ANSWER CLEANING
45
  # ============================================================
46
 
47
  def clean_answer(answer):
 
 
48
 
49
  answer = str(answer).strip()
50
 
51
- # Remove markdown code fences.
52
- answer = re.sub(
53
- r"^```(?:text)?\s*",
54
- "",
55
- answer,
56
- flags=re.IGNORECASE
57
- )
58
 
59
- answer = re.sub(
60
- r"\s*```$",
61
- "",
62
- answer
63
- )
64
 
65
- # Remove accidental prefixes.
66
- answer = re.sub(
67
- r"^\s*FINAL ANSWER\s*:?\s*",
68
- "",
69
- answer,
70
- flags=re.IGNORECASE
71
- )
72
 
73
- answer = re.sub(
74
- r"^\s*THE ANSWER IS\s*:?\s*",
75
- "",
76
- answer,
77
- flags=re.IGNORECASE
78
- )
79
 
80
- return answer.strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
 
83
  # ============================================================
84
  # MODEL CALL
85
  # ============================================================
86
 
87
- def call_model(messages):
88
 
89
- response = client.chat.completions.create(
90
- model=MODEL_ID,
91
  messages=messages,
92
  max_tokens=1200,
93
- temperature=0
94
  )
95
 
96
  return response.choices[0].message.content
97
 
98
 
99
  # ============================================================
100
- # AGENT
101
  # ============================================================
102
 
103
- def solve_question(
104
- task_id,
105
- question
106
- ):
107
 
108
  messages = [
109
  {
@@ -115,237 +120,195 @@ def solve_question(
115
  "content": (
116
  f"GAIA TASK ID: {task_id}\n\n"
117
  f"QUESTION:\n{question}\n\n"
118
- "Solve this question."
 
119
  )
120
  }
121
  ]
122
 
123
- # Cache downloaded attachment path if needed.
124
- attachment_path = None
125
 
126
- for step in range(MAX_STEPS):
127
-
128
- print(
129
- f" Agent step {step + 1}/{MAX_STEPS}"
130
- )
131
-
132
- raw = call_model(messages)
133
-
134
- print(
135
- f" Model: {raw[:500]}"
136
- )
137
-
138
- # ----------------------------------------------------
139
- # Parse JSON
140
- # ----------------------------------------------------
141
 
142
  try:
 
143
 
144
- decision = json.loads(
145
- raw.strip()
146
- )
147
 
148
- except json.JSONDecodeError:
149
 
150
- # Sometimes models put JSON inside markdown.
151
- match = re.search(
152
- r"\{.*\}",
153
- raw,
154
- re.DOTALL
155
- )
156
 
157
- if match:
 
 
 
 
 
 
158
 
159
- try:
160
- decision = json.loads(
161
- match.group(0)
 
 
 
 
 
 
162
  )
163
-
164
- except json.JSONDecodeError:
165
- decision = None
166
-
167
- else:
168
- decision = None
169
-
170
- # ----------------------------------------------------
171
- # Invalid model response
172
- # ----------------------------------------------------
173
-
174
- if not decision:
175
-
176
- messages.append({
177
- "role": "assistant",
178
- "content": raw
179
- })
180
-
181
- messages.append({
182
- "role": "user",
183
- "content": (
184
- "Your response was not valid JSON.\n"
185
- "Return ONLY one of these formats:\n\n"
186
- '{"action":"tool","tool":"TOOL_NAME","input":"..."}\n'
187
- '{"action":"final","answer":"..."}'
188
- )
189
- })
190
 
191
  continue
192
 
 
 
193
  # ----------------------------------------------------
194
  # FINAL ANSWER
195
  # ----------------------------------------------------
196
 
197
- if decision.get("action") == "final":
198
 
199
- answer = decision.get(
200
- "answer",
201
- ""
202
- )
203
 
204
- return clean_answer(
205
- answer
206
- )
207
 
208
  # ----------------------------------------------------
209
  # TOOL CALL
210
  # ----------------------------------------------------
211
 
212
- if decision.get("action") == "tool":
213
 
214
- tool_name = decision.get(
215
- "tool"
216
- )
217
-
218
- tool_input = decision.get(
219
- "input",
220
- ""
221
- )
222
 
223
- # -----------------------------------------------
224
- # Automatically download attachment
225
- # -----------------------------------------------
226
-
227
- if (
228
- tool_name == "download_file"
229
- and not attachment_path
230
- ):
231
-
232
- attachment_path = (
233
- download_file(task_id)
234
  )
 
235
 
236
- tool_result = (
237
- f"FILE_PATH:\n"
238
- f"{attachment_path}\n\n"
239
- f"The file has been downloaded."
240
- )
241
 
242
- # -----------------------------------------------
243
- # Inspect downloaded file
244
- # -----------------------------------------------
245
 
246
- elif (
247
- tool_name == "inspect_file"
248
- and tool_input == "CURRENT_FILE"
249
- ):
 
 
250
 
251
- if not attachment_path:
252
 
253
- attachment_path = (
254
- download_file(task_id)
 
255
  )
256
 
257
- tool_result = execute_tool(
 
 
 
 
258
  "inspect_file",
259
- attachment_path,
260
- task_id,
261
- question
262
- )
263
 
264
- # -----------------------------------------------
265
- # Audio
266
- # -----------------------------------------------
267
 
268
- elif (
269
- tool_name == "transcribe_audio"
270
- and tool_input == "CURRENT_FILE"
271
- ):
272
 
273
- if not attachment_path:
274
 
275
- attachment_path = (
276
- download_file(task_id)
277
- )
 
278
 
279
- tool_result = execute_tool(
280
- "transcribe_audio",
281
- attachment_path,
282
- task_id,
283
- question
284
- )
285
 
286
- # -----------------------------------------------
287
- # Image
288
- # -----------------------------------------------
 
289
 
290
- elif (
291
- tool_name == "analyze_image"
292
- and tool_input == "CURRENT_FILE"
293
- ):
294
 
295
- if not attachment_path:
 
 
 
 
 
 
296
 
297
- attachment_path = (
298
- download_file(task_id)
 
 
 
299
  )
300
 
301
- tool_result = execute_tool(
302
- "analyze_image",
303
- attachment_path,
304
- task_id,
305
- question
306
- )
307
 
308
- # -----------------------------------------------
309
- # Normal tool
310
- # -----------------------------------------------
311
 
312
- else:
 
 
 
 
 
 
313
 
314
- tool_result = execute_tool(
315
- tool_name,
316
- tool_input,
317
- task_id,
318
- question
319
- )
 
 
 
 
 
 
320
 
321
- # Don't let huge tool outputs destroy context.
322
- tool_result = str(
323
- tool_result
324
- )[:40000]
325
 
326
- messages.append({
327
- "role": "assistant",
328
- "content": raw
329
- })
330
 
331
- messages.append({
 
332
  "role": "user",
333
  "content": (
334
- f"TOOL RESULT ({tool_name}):\n"
335
- f"{tool_result}\n\n"
336
- "Continue solving the original question. "
337
- "Use another tool if necessary, otherwise "
338
- "return the final JSON answer."
339
  )
340
- })
341
-
342
- continue
343
 
344
- return "Unable to determine the answer."
345
 
346
 
347
  # ============================================================
348
- # FETCH QUESTIONS
349
  # ============================================================
350
 
351
  def get_questions():
@@ -357,21 +320,40 @@ def get_questions():
357
 
358
  response.raise_for_status()
359
 
360
- return response.json()
 
 
 
 
 
 
 
 
 
 
361
 
362
 
363
  # ============================================================
364
- # SUBMIT
365
  # ============================================================
366
 
367
- def submit(
368
- username,
369
- agent_code,
370
- answers
371
- ):
 
 
 
 
 
 
 
 
 
372
 
373
  payload = {
374
- "username": username,
375
  "agent_code": agent_code,
376
  "answers": answers
377
  }
@@ -379,7 +361,7 @@ def submit(
379
  response = requests.post(
380
  f"{SCORING_API}/submit",
381
  json=payload,
382
- timeout=180
383
  )
384
 
385
  response.raise_for_status()
@@ -391,101 +373,46 @@ def submit(
391
  # MAIN EVALUATION
392
  # ============================================================
393
 
394
- def run_and_submit_all(
395
- profile: gr.OAuthProfile | None
396
- ):
397
 
398
- if profile is None:
399
 
400
  return (
401
- "Please login to Hugging Face.",
402
- None
403
  )
404
 
405
- username = profile.username
406
 
407
- space_id = os.getenv(
408
- "SPACE_ID"
409
- )
410
-
411
- if not space_id:
412
-
413
- return (
414
- "SPACE_ID was not found.",
415
- None
416
- )
417
-
418
- agent_code = (
419
- "https://huggingface.co/spaces/"
420
- f"{space_id}/tree/main"
421
- )
422
-
423
- print("=" * 70)
424
  print("GAIA UNIT 4 AGENT")
425
- print("=" * 70)
426
-
427
- print(
428
- f"Username: {username}"
429
- )
430
 
431
- print(
432
- f"Agent code: {agent_code}"
433
- )
434
-
435
- # --------------------------------------------------------
436
- # Fetch questions
437
- # --------------------------------------------------------
438
-
439
- try:
440
-
441
- questions = get_questions()
442
-
443
- except Exception as e:
444
-
445
- return (
446
- f"Could not fetch questions: {e}",
447
- None
448
- )
449
 
450
- print(
451
- f"Fetched {len(questions)} questions."
452
- )
453
 
454
- answers = []
455
- results = []
456
 
457
- # --------------------------------------------------------
458
- # Solve questions
459
- # --------------------------------------------------------
460
 
461
- for index, item in enumerate(
462
  questions,
463
  start=1
464
  ):
465
 
466
- task_id = item.get(
467
- "task_id"
468
- )
469
-
470
- question = item.get(
471
- "question"
472
- )
473
-
474
- print("\n" + "=" * 70)
475
 
476
- print(
477
- f"QUESTION {index}/{len(questions)}"
 
478
  )
479
 
480
- print(
481
- f"TASK ID: {task_id}"
482
- )
483
-
484
- print(
485
- question[:500]
486
- )
487
-
488
- print("=" * 70)
489
 
490
  try:
491
 
@@ -494,139 +421,125 @@ def run_and_submit_all(
494
  question
495
  )
496
 
497
- answer = clean_answer(
498
- answer
499
- )
500
-
501
- print(
502
- f"FINAL ANSWER: {answer}"
503
- )
504
-
505
- answers.append({
506
- "task_id": task_id,
507
- "submitted_answer": answer
508
- })
509
-
510
- results.append({
511
- "Task ID": task_id,
512
- "Submitted Answer": answer
513
- })
514
-
515
  except Exception as e:
516
 
517
- print(
518
- f"ERROR: {e}"
519
- )
520
 
521
- results.append({
522
- "Task ID": task_id,
523
- "Submitted Answer":
524
- f"ERROR: {e}"
525
- })
526
 
527
- # --------------------------------------------------------
528
- # Submit
529
- # --------------------------------------------------------
530
 
531
- if not answers:
 
 
 
 
 
532
 
533
- return (
534
- "No answers were generated.",
535
- pd.DataFrame(results)
 
 
 
536
  )
537
 
538
- print("\n" + "=" * 70)
539
  print("SUBMITTING")
540
- print("=" * 70)
541
 
542
  try:
543
 
544
- result = submit(
545
  username,
546
- agent_code,
547
- answers
548
  )
549
 
 
 
 
550
  score = result.get(
551
  "score",
552
- "N/A"
553
  )
554
 
555
  correct = result.get(
556
  "correct_count",
557
- "?"
558
  )
559
 
560
  total = result.get(
561
  "total_attempted",
562
- "?"
563
- )
564
-
565
- message = result.get(
566
- "message",
567
- ""
568
  )
569
 
570
  status = (
571
- "Submission Successful!\n\n"
572
- f"User: {username}\n"
573
- f"Score: {score}%\n"
574
- f"Correct: {correct}/{total}\n"
575
- f"Message: {message}"
576
  )
577
 
578
- print(status)
579
-
580
- return (
581
- status,
582
- pd.DataFrame(results)
583
- )
584
 
585
  except Exception as e:
586
 
587
- status = (
588
- f"Submission failed: {e}"
589
- )
590
-
591
- print(status)
592
-
593
  return (
594
- status,
595
- pd.DataFrame(results)
596
  )
597
 
598
 
599
  # ============================================================
600
- # MINIMAL UI
601
  # ============================================================
602
 
603
- with gr.Blocks() as demo:
 
 
604
 
605
  gr.Markdown(
606
- "# GAIA Unit 4 Agent"
607
- )
608
 
609
- gr.Markdown(
610
- "Login and click the button to run all GAIA questions."
 
 
 
611
  )
612
 
613
- gr.LoginButton()
 
 
 
614
 
615
  run_button = gr.Button(
616
- "Run Evaluation & Submit"
 
617
  )
618
 
619
  status = gr.Textbox(
620
- label="Result",
621
- lines=6
622
  )
623
 
624
- results = gr.DataFrame(
 
 
 
 
 
 
 
 
 
 
625
  label="Answers"
626
  )
627
 
628
  run_button.click(
629
- fn=run_and_submit_all,
 
630
  outputs=[
631
  status,
632
  results
@@ -634,9 +547,11 @@ with gr.Blocks() as demo:
634
  )
635
 
636
 
637
- if __name__ == "__main__":
 
638
 
639
- demo.launch(
640
- debug=True,
641
- share=False
642
- )
 
 
1
  import os
2
  import json
3
  import re
 
4
  import gradio as gr
5
+ import requests
6
+ import spaces
7
 
8
  from huggingface_hub import InferenceClient
9
 
10
  from prompt import SYSTEM_PROMPT
11
+ from tools import execute_tool, download_file
 
 
 
 
 
 
12
 
13
 
14
  # ============================================================
15
  # CONFIG
16
  # ============================================================
17
 
18
+ SCORING_API = "https://agents-course-unit4-scoring.hf.space"
 
 
19
 
20
+ MODEL_ID = "Qwen/Qwen2.5-72B-Instruct"
 
 
 
21
 
22
  HF_TOKEN = os.getenv("HF_TOKEN")
23
 
 
 
 
24
  client = InferenceClient(
25
+ model=MODEL_ID,
26
  token=HF_TOKEN
27
  )
28
 
29
 
30
+ # ============================================================
31
+ # ZERO GPU STARTUP PROBE
32
+ # ============================================================
33
+
34
+ # ZeroGPU requires at least one @spaces.GPU function to exist
35
+ # when the Space starts.
36
+ #
37
+ # We DO NOT call this function.
38
+ # Therefore it consumes no GPU quota.
39
+
40
+ @spaces.GPU(duration=1)
41
+ def zerogpu_probe():
42
+ return "ok"
43
+
44
+
45
  # ============================================================
46
  # ANSWER CLEANING
47
  # ============================================================
48
 
49
  def clean_answer(answer):
50
+ if answer is None:
51
+ return ""
52
 
53
  answer = str(answer).strip()
54
 
55
+ answer = answer.replace("```", "")
56
+ answer = answer.replace("FINAL ANSWER:", "")
57
+ answer = answer.replace("Final Answer:", "")
58
+ answer = answer.replace("THE ANSWER IS:", "")
59
+ answer = answer.replace("The answer is:", "")
 
 
60
 
61
+ answer = answer.strip()
 
 
 
 
62
 
63
+ return answer
 
 
 
 
 
 
64
 
 
 
 
 
 
 
65
 
66
+ # ============================================================
67
+ # JSON EXTRACTION
68
+ # ============================================================
69
+
70
+ def extract_json(text):
71
+
72
+ text = text.strip()
73
+
74
+ # Direct JSON
75
+ try:
76
+ return json.loads(text)
77
+ except:
78
+ pass
79
+
80
+ # Find JSON object inside model response
81
+ match = re.search(r"\{.*\}", text, re.DOTALL)
82
+
83
+ if match:
84
+ try:
85
+ return json.loads(match.group(0))
86
+ except:
87
+ pass
88
+
89
+ return None
90
 
91
 
92
  # ============================================================
93
  # MODEL CALL
94
  # ============================================================
95
 
96
+ def ask_model(messages):
97
 
98
+ response = client.chat_completion(
 
99
  messages=messages,
100
  max_tokens=1200,
101
+ temperature=0.1
102
  )
103
 
104
  return response.choices[0].message.content
105
 
106
 
107
  # ============================================================
108
+ # SOLVE ONE GAIA QUESTION
109
  # ============================================================
110
 
111
+ def solve_question(task_id, question):
 
 
 
112
 
113
  messages = [
114
  {
 
120
  "content": (
121
  f"GAIA TASK ID: {task_id}\n\n"
122
  f"QUESTION:\n{question}\n\n"
123
+ "Solve this task completely. "
124
+ "Use tools whenever necessary."
125
  )
126
  }
127
  ]
128
 
129
+ current_file = None
 
130
 
131
+ for step in range(12):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
  try:
134
+ response = ask_model(messages)
135
 
136
+ except Exception as e:
137
+ return f"ERROR: model request failed: {e}"
 
138
 
139
+ parsed = extract_json(response)
140
 
141
+ if parsed is None:
 
 
 
 
 
142
 
143
+ # Give model another chance to follow JSON format
144
+ messages.append(
145
+ {
146
+ "role": "assistant",
147
+ "content": response
148
+ }
149
+ )
150
 
151
+ messages.append(
152
+ {
153
+ "role": "user",
154
+ "content": (
155
+ "Your previous response was not valid JSON. "
156
+ "Respond ONLY with either:\n"
157
+ '{"action":"tool","tool":"TOOL_NAME","input":"..."}\n'
158
+ "or:\n"
159
+ '{"action":"final","answer":"..."}'
160
  )
161
+ }
162
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
 
164
  continue
165
 
166
+ action = parsed.get("action")
167
+
168
  # ----------------------------------------------------
169
  # FINAL ANSWER
170
  # ----------------------------------------------------
171
 
172
+ if action == "final":
173
 
174
+ answer = parsed.get("answer", "")
 
 
 
175
 
176
+ return clean_answer(answer)
 
 
177
 
178
  # ----------------------------------------------------
179
  # TOOL CALL
180
  # ----------------------------------------------------
181
 
182
+ if action == "tool":
183
 
184
+ tool_name = parsed.get("tool")
185
+ tool_input = parsed.get("input", "")
 
 
 
 
 
 
186
 
187
+ if not tool_name:
188
+ messages.append(
189
+ {
190
+ "role": "user",
191
+ "content": "You must provide a tool name."
192
+ }
 
 
 
 
 
193
  )
194
+ continue
195
 
196
+ try:
 
 
 
 
197
 
198
+ # ------------------------------------------------
199
+ # Download file
200
+ # ------------------------------------------------
201
 
202
+ if tool_name == "download_file":
203
+
204
+ file_path = download_file(
205
+ task_id,
206
+ tool_input
207
+ )
208
 
209
+ current_file = file_path
210
 
211
+ result = (
212
+ f"File downloaded successfully.\n"
213
+ f"FILE_PATH: {file_path}"
214
  )
215
 
216
+ # ------------------------------------------------
217
+ # File tools automatically use current file
218
+ # ------------------------------------------------
219
+
220
+ elif tool_name in [
221
  "inspect_file",
222
+ "transcribe_audio"
223
+ ]:
 
 
224
 
225
+ if not current_file:
 
 
226
 
227
+ result = (
228
+ "No file has been downloaded yet. "
229
+ "Use download_file first."
230
+ )
231
 
232
+ else:
233
 
234
+ result = execute_tool(
235
+ tool_name,
236
+ current_file
237
+ )
238
 
239
+ elif tool_name == "analyze_image":
240
+
241
+ if not current_file:
 
 
 
242
 
243
+ result = (
244
+ "No image has been downloaded yet. "
245
+ "Use download_file first."
246
+ )
247
 
248
+ else:
 
 
 
249
 
250
+ result = execute_tool(
251
+ tool_name,
252
+ {
253
+ "path": current_file,
254
+ "question": tool_input
255
+ }
256
+ )
257
 
258
+ else:
259
+
260
+ result = execute_tool(
261
+ tool_name,
262
+ tool_input
263
  )
264
 
265
+ except Exception as e:
 
 
 
 
 
266
 
267
+ result = f"TOOL ERROR: {e}"
 
 
268
 
269
+ # Give tool result back to model
270
+ messages.append(
271
+ {
272
+ "role": "assistant",
273
+ "content": json.dumps(parsed)
274
+ }
275
+ )
276
 
277
+ messages.append(
278
+ {
279
+ "role": "user",
280
+ "content": (
281
+ f"TOOL RESULT ({tool_name}):\n"
282
+ f"{result}\n\n"
283
+ "Continue solving the original question. "
284
+ "Use another tool if necessary, otherwise return "
285
+ "the final answer as JSON."
286
+ )
287
+ }
288
+ )
289
 
290
+ continue
 
 
 
291
 
292
+ # ----------------------------------------------------
293
+ # INVALID ACTION
294
+ # ----------------------------------------------------
 
295
 
296
+ messages.append(
297
+ {
298
  "role": "user",
299
  "content": (
300
+ "Invalid action. Use exactly one of:\n"
301
+ '{"action":"tool","tool":"TOOL_NAME","input":"..."}\n'
302
+ '{"action":"final","answer":"..."}'
 
 
303
  )
304
+ }
305
+ )
 
306
 
307
+ return "ERROR: agent exceeded maximum reasoning steps."
308
 
309
 
310
  # ============================================================
311
+ # GET QUESTIONS
312
  # ============================================================
313
 
314
  def get_questions():
 
320
 
321
  response.raise_for_status()
322
 
323
+ data = response.json()
324
+
325
+ if isinstance(data, dict):
326
+
327
+ if "questions" in data:
328
+ return data["questions"]
329
+
330
+ if "data" in data:
331
+ return data["data"]
332
+
333
+ return data
334
 
335
 
336
  # ============================================================
337
+ # SUBMIT ANSWERS
338
  # ============================================================
339
 
340
+ def submit_answers(username, answers):
341
+
342
+ space_id = os.getenv("SPACE_ID")
343
+
344
+ if not space_id:
345
+
346
+ raise RuntimeError(
347
+ "SPACE_ID environment variable is missing."
348
+ )
349
+
350
+ agent_code = (
351
+ f"https://huggingface.co/spaces/"
352
+ f"{space_id}/tree/main"
353
+ )
354
 
355
  payload = {
356
+ "username": username.strip(),
357
  "agent_code": agent_code,
358
  "answers": answers
359
  }
 
361
  response = requests.post(
362
  f"{SCORING_API}/submit",
363
  json=payload,
364
+ timeout=120
365
  )
366
 
367
  response.raise_for_status()
 
373
  # MAIN EVALUATION
374
  # ============================================================
375
 
376
+ def run_agent(username):
 
 
377
 
378
+ if not username or not username.strip():
379
 
380
  return (
381
+ "ERROR: Please enter your Hugging Face username.",
382
+ []
383
  )
384
 
385
+ username = username.strip()
386
 
387
+ print("\n========================================")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  print("GAIA UNIT 4 AGENT")
389
+ print("========================================")
 
 
 
 
390
 
391
+ print(f"Username: {username}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
 
393
+ questions = get_questions()
 
 
394
 
395
+ print(f"Questions received: {len(questions)}")
 
396
 
397
+ answers_payload = []
398
+ display_rows = []
 
399
 
400
+ for index, question_data in enumerate(
401
  questions,
402
  start=1
403
  ):
404
 
405
+ task_id = question_data.get("task_id")
 
 
 
 
 
 
 
 
406
 
407
+ question = question_data.get(
408
+ "question",
409
+ question_data.get("prompt", "")
410
  )
411
 
412
+ print("\n----------------------------------------")
413
+ print(f"Question {index}/{len(questions)}")
414
+ print(f"Task ID: {task_id}")
415
+ print("----------------------------------------")
 
 
 
 
 
416
 
417
  try:
418
 
 
421
  question
422
  )
423
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
  except Exception as e:
425
 
426
+ answer = f"ERROR: {e}"
 
 
427
 
428
+ answer = clean_answer(answer)
 
 
 
 
429
 
430
+ print(f"ANSWER: {answer}")
 
 
431
 
432
+ answers_payload.append(
433
+ {
434
+ "task_id": task_id,
435
+ "submitted_answer": answer
436
+ }
437
+ )
438
 
439
+ display_rows.append(
440
+ [
441
+ index,
442
+ task_id,
443
+ answer
444
+ ]
445
  )
446
 
447
+ print("\n========================================")
448
  print("SUBMITTING")
449
+ print("========================================")
450
 
451
  try:
452
 
453
+ result = submit_answers(
454
  username,
455
+ answers_payload
 
456
  )
457
 
458
+ print("Submission result:")
459
+ print(result)
460
+
461
  score = result.get(
462
  "score",
463
+ result.get("total_score", "N/A")
464
  )
465
 
466
  correct = result.get(
467
  "correct_count",
468
+ result.get("correct", "N/A")
469
  )
470
 
471
  total = result.get(
472
  "total_attempted",
473
+ len(answers_payload)
 
 
 
 
 
474
  )
475
 
476
  status = (
477
+ f"SUBMITTED\n"
478
+ f"Score: {score}\n"
479
+ f"Correct: {correct}/{total}"
 
 
480
  )
481
 
482
+ return status, display_rows
 
 
 
 
 
483
 
484
  except Exception as e:
485
 
 
 
 
 
 
 
486
  return (
487
+ f"SUBMISSION ERROR: {e}",
488
+ display_rows
489
  )
490
 
491
 
492
  # ============================================================
493
+ # SIMPLE UI
494
  # ============================================================
495
 
496
+ with gr.Blocks(
497
+ title="GAIA Unit 4 Agent"
498
+ ) as demo:
499
 
500
  gr.Markdown(
501
+ """
502
+ # GAIA Unit 4 Agent
503
 
504
+ Enter your Hugging Face username and run the agent.
505
+
506
+ The agent will solve the 20 validation questions and submit
507
+ the answers automatically.
508
+ """
509
  )
510
 
511
+ username = gr.Textbox(
512
+ label="Hugging Face Username",
513
+ placeholder="Your HF username"
514
+ )
515
 
516
  run_button = gr.Button(
517
+ "Run Agent & Submit",
518
+ variant="primary"
519
  )
520
 
521
  status = gr.Textbox(
522
+ label="Status",
523
+ lines=5
524
  )
525
 
526
+ results = gr.Dataframe(
527
+ headers=[
528
+ "Question",
529
+ "Task ID",
530
+ "Submitted Answer"
531
+ ],
532
+ datatype=[
533
+ "number",
534
+ "str",
535
+ "str"
536
+ ],
537
  label="Answers"
538
  )
539
 
540
  run_button.click(
541
+ fn=run_agent,
542
+ inputs=username,
543
  outputs=[
544
  status,
545
  results
 
547
  )
548
 
549
 
550
+ # IMPORTANT:
551
+ # Disable Gradio SSR for better Spaces compatibility.
552
 
553
+ demo.launch(
554
+ debug=True,
555
+ share=False,
556
+ ssr_mode=False
557
+ )