Files changed (1) hide show
  1. app.py +261 -60
app.py CHANGED
@@ -3,32 +3,127 @@ import gradio as gr
3
  import requests
4
  import inspect
5
  import pandas as pd
 
 
6
 
7
  # (Keep Constants as is)
8
  # --- Constants ---
9
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
10
 
11
- # --- Basic Agent Definition ---
12
- # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
13
- class BasicAgent:
 
 
 
 
 
14
  def __init__(self):
15
- print("BasicAgent initialized.")
 
 
 
 
 
 
 
 
 
 
16
  def __call__(self, question: str) -> str:
17
- print(f"Agent received question (first 50 chars): {question[:50]}...")
18
- fixed_answer = "This is a default answer."
19
- print(f"Agent returning fixed answer: {fixed_answer}")
20
- return fixed_answer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
- def run_and_submit_all( profile: gr.OAuthProfile | None):
 
23
  """
24
- Fetches all questions, runs the BasicAgent on them, submits all answers,
25
  and displays the results.
26
  """
27
  # --- Determine HF Space Runtime URL and Repo URL ---
28
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
29
 
30
  if profile:
31
- username= f"{profile.username}"
32
  print(f"User logged in: {username}")
33
  else:
34
  print("User not logged in.")
@@ -38,15 +133,18 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
38
  questions_url = f"{api_url}/questions"
39
  submit_url = f"{api_url}/submit"
40
 
41
- # 1. Instantiate Agent ( modify this part to create your agent)
42
  try:
43
- agent = BasicAgent()
 
 
44
  except Exception as e:
45
  print(f"Error instantiating agent: {e}")
46
  return f"Error initializing agent: {e}", None
47
- # In the case of an app running as a hugging Face space, this link points toward your codebase ( usefull for others so please keep it public)
48
- agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
49
- print(agent_code)
 
50
 
51
  # 2. Fetch Questions
52
  print(f"Fetching questions from: {questions_url}")
@@ -54,54 +152,96 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
54
  response = requests.get(questions_url, timeout=15)
55
  response.raise_for_status()
56
  questions_data = response.json()
 
57
  if not questions_data:
58
- print("Fetched questions list is empty.")
59
- return "Fetched questions list is empty or invalid format.", None
 
60
  print(f"Fetched {len(questions_data)} questions.")
 
 
 
 
 
 
 
61
  except requests.exceptions.RequestException as e:
62
  print(f"Error fetching questions: {e}")
63
  return f"Error fetching questions: {e}", None
64
  except requests.exceptions.JSONDecodeError as e:
65
- print(f"Error decoding JSON response from questions endpoint: {e}")
66
- print(f"Response text: {response.text[:500]}")
67
- return f"Error decoding server response for questions: {e}", None
68
  except Exception as e:
69
  print(f"An unexpected error occurred fetching questions: {e}")
70
  return f"An unexpected error occurred fetching questions: {e}", None
71
 
72
- # 3. Run your Agent
73
  results_log = []
74
  answers_payload = []
75
- print(f"Running agent on {len(questions_data)} questions...")
76
- for item in questions_data:
 
 
 
 
77
  task_id = item.get("task_id")
78
  question_text = item.get("question")
 
79
  if not task_id or question_text is None:
80
  print(f"Skipping item with missing task_id or question: {item}")
81
  continue
 
 
 
82
  try:
 
83
  submitted_answer = agent(question_text)
84
- answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
85
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  except Exception as e:
87
- print(f"Error running agent on task {task_id}: {e}")
88
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
 
 
 
 
89
 
90
  if not answers_payload:
91
  print("Agent did not produce any answers to submit.")
92
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
93
 
94
- # 4. Prepare Submission
95
- submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
 
 
 
 
 
96
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
97
  print(status_update)
98
 
99
- # 5. Submit
100
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
101
  try:
102
  response = requests.post(submit_url, json=submission_data, timeout=60)
103
  response.raise_for_status()
104
  result_data = response.json()
 
105
  final_status = (
106
  f"Submission Successful!\n"
107
  f"User: {result_data.get('username')}\n"
@@ -109,9 +249,23 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
109
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
110
  f"Message: {result_data.get('message', 'No message received.')}"
111
  )
 
112
  print("Submission successful.")
113
- results_df = pd.DataFrame(results_log)
 
 
 
 
 
 
 
 
 
 
 
 
114
  return final_status, results_df
 
115
  except requests.exceptions.HTTPError as e:
116
  error_detail = f"Server responded with status {e.response.status_code}."
117
  try:
@@ -123,16 +277,19 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
123
  print(status_message)
124
  results_df = pd.DataFrame(results_log)
125
  return status_message, results_df
 
126
  except requests.exceptions.Timeout:
127
  status_message = "Submission Failed: The request timed out."
128
  print(status_message)
129
  results_df = pd.DataFrame(results_log)
130
  return status_message, results_df
 
131
  except requests.exceptions.RequestException as e:
132
  status_message = f"Submission Failed: Network error - {e}"
133
  print(status_message)
134
  results_df = pd.DataFrame(results_log)
135
  return status_message, results_df
 
136
  except Exception as e:
137
  status_message = f"An unexpected error occurred during submission: {e}"
138
  print(status_message)
@@ -141,30 +298,69 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
141
 
142
 
143
  # --- Build Gradio Interface using Blocks ---
144
- with gr.Blocks() as demo:
145
- gr.Markdown("# Basic Agent Evaluation Runner")
146
  gr.Markdown(
147
  """
 
 
 
 
148
  **Instructions:**
149
-
150
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
151
- 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
152
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
153
-
154
- ---
 
 
 
 
 
 
 
155
  **Disclaimers:**
156
- Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
157
- This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution. For instance for the delay process of the submit button, a solution could be to cache the answers and submit in a seperate action or even to answer the questions in async.
158
  """
159
  )
160
 
161
- gr.LoginButton()
 
 
 
 
 
162
 
163
- run_button = gr.Button("Run Evaluation & Submit All Answers")
164
-
165
- status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
166
- # Removed max_rows=10 from DataFrame constructor
167
- results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
  run_button.click(
170
  fn=run_and_submit_all,
@@ -172,25 +368,30 @@ with gr.Blocks() as demo:
172
  )
173
 
174
  if __name__ == "__main__":
175
- print("\n" + "-"*30 + " App Starting " + "-"*30)
176
- # Check for SPACE_HOST and SPACE_ID at startup for information
 
 
 
177
  space_host_startup = os.getenv("SPACE_HOST")
178
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
179
 
180
  if space_host_startup:
181
  print(f"✅ SPACE_HOST found: {space_host_startup}")
182
- print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
183
  else:
184
- print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
185
 
186
- if space_id_startup: # Print repo URLs if SPACE_ID is found
187
  print(f"✅ SPACE_ID found: {space_id_startup}")
188
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
189
- print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
190
  else:
191
- print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
192
-
193
- print("-"*(60 + len(" App Starting ")) + "\n")
194
 
195
- print("Launching Gradio Interface for Basic Agent Evaluation...")
 
 
 
 
 
196
  demo.launch(debug=True, share=False)
 
3
  import requests
4
  import inspect
5
  import pandas as pd
6
+ import json
7
+ from typing import Dict, List, Optional, Any
8
 
9
  # (Keep Constants as is)
10
  # --- Constants ---
11
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
12
 
13
+ # --- Enhanced Agent Definition ---
14
+ # ----- THIS IS WHERE YOU CAN BUILD WHAT YOU WANT ------
15
+ class GIAIAAgent:
16
+ """
17
+ Agent designed to answer GIAIA questions.
18
+ Modify this class to implement your own logic for answering questions.
19
+ """
20
+
21
  def __init__(self):
22
+ """Initialize your agent with any necessary tools, models, or resources."""
23
+ print("GIAIA Agent initialized.")
24
+
25
+ # TODO: Initialize your tools, models, or APIs here
26
+ # Example:
27
+ # self.model = load_your_model()
28
+ # self.tools = load_your_tools()
29
+
30
+ # You can store a cache of answers if needed
31
+ self.answer_cache = {}
32
+
33
  def __call__(self, question: str) -> str:
34
+ """
35
+ Process a question and return an answer.
36
+
37
+ Args:
38
+ question: The question text to answer
39
+
40
+ Returns:
41
+ The answer as a string
42
+ """
43
+ print(f"Processing question (first 100 chars): {question[:100]}...")
44
+
45
+ # TODO: Implement your actual question-answering logic here
46
+ # This is where you should put your agent's intelligence
47
+
48
+ # For now, let's do some basic processing to show the structure
49
+ try:
50
+ # You might want to:
51
+ # 1. Parse the question
52
+ # 2. Use tools to gather information
53
+ # 3. Process with a model
54
+ # 4. Format the answer
55
+
56
+ # Example structure (replace with your actual logic):
57
+ answer = self._generate_answer(question)
58
+
59
+ print(f"Generated answer: {answer[:50]}...")
60
+ return answer
61
+
62
+ except Exception as e:
63
+ print(f"Error processing question: {e}")
64
+ return f"Error generating answer: {str(e)}"
65
+
66
+ def _generate_answer(self, question: str) -> str:
67
+ """
68
+ Internal method to generate answers.
69
+ Replace this with your actual implementation.
70
+
71
+ This is a placeholder - you should implement your own logic!
72
+ """
73
+
74
+ # TODO: IMPLEMENT YOUR ACTUAL ANSWER GENERATION LOGIC HERE
75
+ #
76
+ # Some ideas:
77
+ # - Use a language model via API
78
+ # - Use retrieval augmented generation
79
+ # - Use web search tools
80
+ # - Use a knowledge base
81
+ # - Implement specific logic for each type of question
82
+
83
+ # For demonstration, I'll categorize questions based on keywords
84
+ # BUT YOU SHOULD REPLACE THIS WITH YOUR ACTUAL IMPLEMENTATION
85
+
86
+ question_lower = question.lower()
87
+
88
+ # This is just a simple example - REPLACE WITH REAL LOGIC!
89
+ if "what is" in question_lower:
90
+ return f"Based on the context, {question.replace('What is', '').strip()} refers to a concept in the field."
91
+ elif "how to" in question_lower:
92
+ return f"To {question.replace('How to', '').strip()}, you should follow these steps: [Your solution here]"
93
+ elif "explain" in question_lower:
94
+ return f"Here's an explanation of {question.replace('Explain', '').strip()}: [Your explanation here]"
95
+ elif "difference between" in question_lower:
96
+ return f"The main differences are: [Your comparison here]"
97
+ else:
98
+ # For questions without clear keywords, you might want to use a default approach
99
+ return f"Answer: [Your answer for: {question[:50]}...]"
100
+
101
+ def batch_answer(self, questions: List[str]) -> List[str]:
102
+ """
103
+ Optional: Process multiple questions at once for efficiency.
104
+
105
+ Args:
106
+ questions: List of question strings
107
+
108
+ Returns:
109
+ List of answer strings
110
+ """
111
+ answers = []
112
+ for question in questions:
113
+ answers.append(self(question))
114
+ return answers
115
 
116
+
117
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
118
  """
119
+ Fetches all questions, runs the GIAIAAgent on them, submits all answers,
120
  and displays the results.
121
  """
122
  # --- Determine HF Space Runtime URL and Repo URL ---
123
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
124
 
125
  if profile:
126
+ username = f"{profile.username}"
127
  print(f"User logged in: {username}")
128
  else:
129
  print("User not logged in.")
 
133
  questions_url = f"{api_url}/questions"
134
  submit_url = f"{api_url}/submit"
135
 
136
+ # 1. Instantiate Agent (modify this part to create your agent)
137
  try:
138
+ # Use the enhanced GIAIA agent instead of BasicAgent
139
+ agent = GIAIAAgent()
140
+ print("Agent instantiated successfully")
141
  except Exception as e:
142
  print(f"Error instantiating agent: {e}")
143
  return f"Error initializing agent: {e}", None
144
+
145
+ # In the case of an app running as a Hugging Face space, this link points toward your codebase
146
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main" if space_id else "Local development"
147
+ print(f"Agent code URL: {agent_code}")
148
 
149
  # 2. Fetch Questions
150
  print(f"Fetching questions from: {questions_url}")
 
152
  response = requests.get(questions_url, timeout=15)
153
  response.raise_for_status()
154
  questions_data = response.json()
155
+
156
  if not questions_data:
157
+ print("Fetched questions list is empty.")
158
+ return "Fetched questions list is empty or invalid format.", None
159
+
160
  print(f"Fetched {len(questions_data)} questions.")
161
+
162
+ # Optional: Display the first few questions to see what we're dealing with
163
+ print("\n--- First 3 questions (preview) ---")
164
+ for i, item in enumerate(questions_data[:3]):
165
+ print(f"Q{i+1}: {item.get('question', 'No question')[:100]}...")
166
+ print("--- End preview ---\n")
167
+
168
  except requests.exceptions.RequestException as e:
169
  print(f"Error fetching questions: {e}")
170
  return f"Error fetching questions: {e}", None
171
  except requests.exceptions.JSONDecodeError as e:
172
+ print(f"Error decoding JSON response from questions endpoint: {e}")
173
+ print(f"Response text: {response.text[:500]}")
174
+ return f"Error decoding server response for questions: {e}", None
175
  except Exception as e:
176
  print(f"An unexpected error occurred fetching questions: {e}")
177
  return f"An unexpected error occurred fetching questions: {e}", None
178
 
179
+ # 3. Run your Agent on all questions
180
  results_log = []
181
  answers_payload = []
182
+
183
+ print(f"\nRunning GIAIA agent on {len(questions_data)} questions...")
184
+ print("This may take a while depending on your implementation...")
185
+
186
+ # Process questions one by one (or in batches if you implement batch_answer)
187
+ for i, item in enumerate(questions_data):
188
  task_id = item.get("task_id")
189
  question_text = item.get("question")
190
+
191
  if not task_id or question_text is None:
192
  print(f"Skipping item with missing task_id or question: {item}")
193
  continue
194
+
195
+ print(f"Processing question {i+1}/{len(questions_data)} (Task ID: {task_id})")
196
+
197
  try:
198
+ # Run your agent on the question
199
  submitted_answer = agent(question_text)
200
+
201
+ # Add to payload for submission
202
+ answers_payload.append({
203
+ "task_id": task_id,
204
+ "submitted_answer": submitted_answer
205
+ })
206
+
207
+ # Log for display
208
+ results_log.append({
209
+ "Task ID": task_id,
210
+ "Question": question_text[:100] + "..." if len(question_text) > 100 else question_text,
211
+ "Submitted Answer": submitted_answer[:100] + "..." if len(submitted_answer) > 100 else submitted_answer
212
+ })
213
+
214
+ print(f"✓ Question {i+1} answered")
215
+
216
  except Exception as e:
217
+ print(f"Error running agent on task {task_id}: {e}")
218
+ results_log.append({
219
+ "Task ID": task_id,
220
+ "Question": question_text[:100] + "..." if len(question_text) > 100 else question_text,
221
+ "Submitted Answer": f"AGENT ERROR: {str(e)}"
222
+ })
223
 
224
  if not answers_payload:
225
  print("Agent did not produce any answers to submit.")
226
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
227
 
228
+ # 4. Prepare Submission
229
+ submission_data = {
230
+ "username": username.strip(),
231
+ "agent_code": agent_code,
232
+ "answers": answers_payload
233
+ }
234
+
235
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
236
  print(status_update)
237
 
238
+ # 5. Submit answers to scoring server
239
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
240
  try:
241
  response = requests.post(submit_url, json=submission_data, timeout=60)
242
  response.raise_for_status()
243
  result_data = response.json()
244
+
245
  final_status = (
246
  f"Submission Successful!\n"
247
  f"User: {result_data.get('username')}\n"
 
249
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
250
  f"Message: {result_data.get('message', 'No message received.')}"
251
  )
252
+
253
  print("Submission successful.")
254
+ print(f"Score: {result_data.get('score', 'N/A')}%")
255
+
256
+ # Create full results DataFrame with complete answers for download
257
+ full_results_log = []
258
+ for i, item in enumerate(questions_data):
259
+ if i < len(answers_payload):
260
+ full_results_log.append({
261
+ "Task ID": item.get("task_id"),
262
+ "Question": item.get("question"),
263
+ "Submitted Answer": answers_payload[i].get("submitted_answer")
264
+ })
265
+
266
+ results_df = pd.DataFrame(full_results_log if full_results_log else results_log)
267
  return final_status, results_df
268
+
269
  except requests.exceptions.HTTPError as e:
270
  error_detail = f"Server responded with status {e.response.status_code}."
271
  try:
 
277
  print(status_message)
278
  results_df = pd.DataFrame(results_log)
279
  return status_message, results_df
280
+
281
  except requests.exceptions.Timeout:
282
  status_message = "Submission Failed: The request timed out."
283
  print(status_message)
284
  results_df = pd.DataFrame(results_log)
285
  return status_message, results_df
286
+
287
  except requests.exceptions.RequestException as e:
288
  status_message = f"Submission Failed: Network error - {e}"
289
  print(status_message)
290
  results_df = pd.DataFrame(results_log)
291
  return status_message, results_df
292
+
293
  except Exception as e:
294
  status_message = f"An unexpected error occurred during submission: {e}"
295
  print(status_message)
 
298
 
299
 
300
  # --- Build Gradio Interface using Blocks ---
301
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
302
+ gr.Markdown("# GIAIA Agent Evaluation Runner")
303
  gr.Markdown(
304
  """
305
+ **Welcome to the GIAIA Agent Evaluation!**
306
+
307
+ This space evaluates your agent on 20 GIAIA questions.
308
+
309
  **Instructions:**
310
+ 1. **Fork/Clone** this space to your own account
311
+ 2. **Modify the `GIAIAAgent` class** in `app.py` to implement your agent's logic
312
+ 3. Add any required **dependencies** to `requirements.txt`
313
+ 4. Log in with your Hugging Face account below
314
+ 5. Click 'Run Evaluation' to test your agent on all 20 questions
315
+ 6. View your score and detailed results
316
+
317
+ **Tips for Implementation:**
318
+ - The agent will be called once for each question
319
+ - You can add tools, use APIs, or implement any logic you want
320
+ - Consider performance - all 20 questions will be processed sequentially
321
+ - You can implement caching if needed
322
+
323
  **Disclaimers:**
324
+ - This evaluation may take some time depending on your implementation
325
+ - Make sure to keep your space public so others can see your solution
326
  """
327
  )
328
 
329
+ with gr.Row():
330
+ with gr.Column(scale=1):
331
+ gr.LoginButton()
332
+
333
+ with gr.Column(scale=2):
334
+ run_button = gr.Button("🚀 Run Evaluation on 20 Questions", variant="primary", size="lg")
335
 
336
+ with gr.Row():
337
+ with gr.Column():
338
+ status_output = gr.Textbox(
339
+ label="Run Status / Submission Result",
340
+ lines=6,
341
+ interactive=False,
342
+ placeholder="Status will appear here..."
343
+ )
344
+
345
+ with gr.Row():
346
+ with gr.Column():
347
+ results_table = gr.DataFrame(
348
+ label="Questions and Agent Answers (Preview)",
349
+ wrap=True,
350
+ height=400
351
+ )
352
+
353
+ with gr.Row():
354
+ with gr.Column():
355
+ gr.Markdown(
356
+ """
357
+ ---
358
+ **Need Help?**
359
+ - Check the [documentation](https://huggingface.co/docs)
360
+ - Modify the `GIAIAAgent._generate_answer` method with your logic
361
+ - Add any required packages to `requirements.txt`
362
+ """
363
+ )
364
 
365
  run_button.click(
366
  fn=run_and_submit_all,
 
368
  )
369
 
370
  if __name__ == "__main__":
371
+ print("\n" + "="*70)
372
+ print(" GIAIA Agent Evaluation App Starting")
373
+ print("="*70)
374
+
375
+ # Check for SPACE_HOST and SPACE_ID at startup
376
  space_host_startup = os.getenv("SPACE_HOST")
377
+ space_id_startup = os.getenv("SPACE_ID")
378
 
379
  if space_host_startup:
380
  print(f"✅ SPACE_HOST found: {space_host_startup}")
381
+ print(f" Runtime URL: https://{space_host_startup}.hf.space")
382
  else:
383
+ print("ℹ️ SPACE_HOST not found (running locally)")
384
 
385
+ if space_id_startup:
386
  print(f"✅ SPACE_ID found: {space_id_startup}")
387
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
 
388
  else:
389
+ print("ℹ️ SPACE_ID not found (running locally)")
 
 
390
 
391
+ print("="*70 + "\n")
392
+ print("Launching Gradio Interface...")
393
+ print("NOTE: The agent in this template uses placeholder logic.")
394
+ print("You MUST modify the GIAIAAgent class to implement actual answers!")
395
+ print("-"*70 + "\n")
396
+
397
  demo.launch(debug=True, share=False)