asaporta commited on
Commit
a9ae310
Β·
verified Β·
1 Parent(s): 3fb5033

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -268
app.py CHANGED
@@ -1,211 +1,49 @@
1
  import os
2
- import re
3
- import pathlib
4
- import tempfile
5
- from pathlib import Path
6
- from typing import Union, Optional
7
-
8
- import openai
9
- from openai import OpenAI
10
- import requests
11
  import gradio as gr
 
 
12
  import pandas as pd
13
- from tabulate import tabulate
14
- from smolagents import OpenAIServerModel,DuckDuckGoSearchTool,CodeAgent, WikipediaSearchTool
15
- from smolagents.tools import PipelineTool, Tool
16
 
17
- client = OpenAI(api_key = os.environ.get("OPENAI_API_KEY"))
18
- # (Keep Constants as is)
19
  # --- Constants ---
20
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
21
 
22
-
23
- class SpeechToTextTool(PipelineTool):
24
- """
25
- Transcribes an audio file to text using the OpenAI Whisper API.
26
- Only local file paths are supported.
27
- """
28
-
29
- default_checkpoint = "openai/whisper-1" # purely informational here
30
- description = (
31
- "This tool sends an audio file to OpenAI Whisper and returns the "
32
- "transcribed text."
33
- )
34
- name = "transcriber"
35
- inputs = {
36
- "audio": {
37
- "type": "string",
38
- "description": "Absolute or relative path to a local audio file.",
39
- }
40
- }
41
- output_type = "string"
42
-
43
- # ──────────────────────────────────────────────────────────────────────────
44
- # Public interface
45
- # ──────────────────────────────────────────────────────────────────────────
46
- def __call__(self, audio: str) -> str:
47
- """
48
- Convenience wrapper so the tool can be used like a regular function:
49
- text = SpeechToTextTool()(path_to_audio)
50
- """
51
- return self._transcribe(audio)
52
-
53
- # ──────────────────────────────────────────────────────────────────────────
54
- # Internal helpers
55
- # ──────────────────────────────────────────────────────────────────────────
56
- @staticmethod
57
- def _transcribe(audio_path: str) -> str:
58
- # ----- validation ----------------------------------------------------
59
- if not isinstance(audio_path, str):
60
- raise TypeError(
61
- "Parameter 'audio' must be a string containing the file path."
62
- )
63
- path = Path(audio_path).expanduser().resolve()
64
- if not path.is_file():
65
- raise FileNotFoundError(f"No such audio file: {path}")
66
-
67
- # ----- API call ------------------------------------------------------
68
- with path.open("rb") as fp:
69
- response = openai.audio.transcriptions.create(
70
- file=fp,
71
- model="whisper-1", # currently the only Whisper model
72
- response_format="text", # returns plain text instead of JSON
73
- )
74
-
75
- # For response_format="text", `response` is already the raw transcript
76
- return response
77
-
78
-
79
- class ExcelToTextTool(Tool):
80
- """Render an Excel worksheet as Markdown text."""
81
-
82
- # ------------------------------------------------------------------
83
- # Required smol‑agents metadata
84
- # ------------------------------------------------------------------
85
- name = "excel_to_text"
86
- description = (
87
- "Read an Excel file and return a Markdown table of the requested sheet. "
88
- "Accepts either the sheet name or the zero-based index."
89
- )
90
-
91
- inputs = {
92
- "excel_path": {
93
- "type": "string",
94
- "description": "Path to the Excel file (.xlsx / .xls).",
95
- },
96
- "sheet_name": {
97
- "type": "string",
98
- "description": (
99
- "Worksheet name or zero-based index *as a string* (optional; default first sheet)."
100
- ),
101
- "nullable": True,
102
- },
103
- }
104
-
105
- output_type = "string"
106
-
107
- def forward(
108
- self,
109
- excel_path: str,
110
- sheet_name: Optional[str] = None,
111
- ) -> str:
112
- """Load *excel_path* and return the sheet as a Markdown table."""
113
-
114
- path = pathlib.Path(excel_path).expanduser().resolve()
115
- if not path.exists():
116
- return f"Error: Excel file not found at {path}"
117
-
118
- try:
119
- # Interpret sheet identifier -----------------------------------
120
- sheet: Union[str, int]
121
- if sheet_name is None or sheet_name == "":
122
- sheet = 0 # first sheet
123
- else:
124
- # If the user passed a numeric string (e.g. "1"), cast to int
125
- sheet = int(sheet_name) if sheet_name.isdigit() else sheet_name
126
-
127
- # Load worksheet ----------------------------------------------
128
- df = pd.read_excel(path, sheet_name=sheet)
129
-
130
- # Render to Markdown; fall back to tabulate if needed ---------
131
- if hasattr(pd.DataFrame, "to_markdown"):
132
- return df.to_markdown(index=False)
133
-
134
- return tabulate(df, headers="keys", tablefmt="github", showindex=False)
135
-
136
- except Exception as exc: # pylint: disable=broad-except
137
- return f"Error reading Excel file: {exc}"
138
-
139
-
140
- def download_file_if_any(base_api_url: str, task_id: str) -> str | None:
141
- """
142
- Try GET /files/{task_id}.
143
- β€’ On HTTP 200 β†’ save to a temp dir and return local path.
144
- β€’ On 404 β†’ return None.
145
- β€’ On other errors β†’ raise so caller can log / handle.
146
- """
147
- url = f"{base_api_url}/files/{task_id}"
148
- try:
149
- resp = requests.get(url, timeout=30)
150
- if resp.status_code == 404:
151
- return None # no file
152
- resp.raise_for_status() # raise on 4xx/5xx β‰  404
153
- except requests.exceptions.HTTPError as e:
154
- # propagate non-404 errors (403, 500, …)
155
- raise e
156
-
157
- # β–Έ Save bytes to a named file inside the system temp dir
158
- # Try to keep original extension from Content-Disposition if present.
159
- cdisp = resp.headers.get("content-disposition", "")
160
- filename = task_id # default base name
161
- if "filename=" in cdisp:
162
- m = re.search(r'filename="([^"]+)"', cdisp)
163
- if m:
164
- filename = m.group(1) # keep provided name
165
-
166
- tmp_dir = Path(tempfile.gettempdir()) / "gaia_files"
167
- tmp_dir.mkdir(exist_ok=True)
168
- file_path = tmp_dir / filename
169
- with open(file_path, "wb") as f:
170
- f.write(resp.content)
171
- return str(file_path)
172
-
173
-
174
  class BasicAgent:
175
- """Basic Agent for the evaluation task."""
176
-
177
  def __init__(self):
178
- self.agent = CodeAgent(
179
- model=OpenAIServerModel(model_id="gpt-4o"),
180
- tools=[
181
- DuckDuckGoSearchTool(),
182
- WikipediaSearchTool(),
183
- SpeechToTextTool(),
184
- ExcelToTextTool(),
185
- ],
186
- add_base_tools=True,
187
- additional_authorized_imports=["pandas", "numpy", "csv", "subprocess"],
188
- )
189
-
190
  print("BasicAgent initialized.")
191
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  def __call__(self, question: str) -> str:
193
  print(f"Agent received question (first 50 chars): {question[:50]}...")
194
- fixed_answer = self.agent.run(question)
195
- print(f"Agent returning answer: {fixed_answer}")
196
- return fixed_answer
197
-
198
 
199
- def run_and_submit_all(profile: gr.OAuthProfile | None):
200
  """
201
  Fetches all questions, runs the BasicAgent on them, submits all answers,
202
  and displays the results.
203
  """
204
  # --- Determine HF Space Runtime URL and Repo URL ---
205
- space_id = os.getenv("SPACE_ID")
206
 
207
  if profile:
208
- username = f"{profile.username}"
209
  print(f"User logged in: {username}")
210
  else:
211
  print("User not logged in.")
@@ -215,9 +53,10 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
215
  questions_url = f"{api_url}/questions"
216
  submit_url = f"{api_url}/submit"
217
 
 
218
  try:
219
  agent = BasicAgent()
220
- except Exception as e: # pylint: disable=broad-except
221
  print(f"Error instantiating agent: {e}")
222
  return f"Error initializing agent: {e}", None
223
  # 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)
@@ -231,17 +70,17 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
231
  response.raise_for_status()
232
  questions_data = response.json()
233
  if not questions_data:
234
- print("Fetched questions list is empty.")
235
- return "Fetched questions list is empty or invalid format.", None
236
  print(f"Fetched {len(questions_data)} questions.")
237
- except requests.exceptions.JSONDecodeError as e:
238
- print(f"Error decoding JSON response from questions endpoint: {e}")
239
- print(f"Response text: {response.text[:500]}")
240
- return f"Error decoding server response for questions: {e}", None
241
  except requests.exceptions.RequestException as e:
242
  print(f"Error fetching questions: {e}")
243
  return f"Error fetching questions: {e}", None
244
- except Exception as e: # pylint: disable=broad-except
 
 
 
 
245
  print(f"An unexpected error occurred fetching questions: {e}")
246
  return f"An unexpected error occurred fetching questions: {e}", None
247
 
@@ -252,62 +91,23 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
252
  for item in questions_data:
253
  task_id = item.get("task_id")
254
  question_text = item.get("question")
255
-
256
- # ----------fetch any attached file ----------
257
- try:
258
- file_path = download_file_if_any(api_url, task_id)
259
- except Exception as e: # pylint: disable=broad-except
260
- file_path = None
261
- print(f"[file fetch error] {task_id}: {e}")
262
-
263
- # ---------- Build the prompt sent to the agent ----------
264
- if file_path:
265
- q_for_agent = (
266
- f"{question_text}\n\n"
267
- f"---\n"
268
- f"A file was downloaded for this task and saved locally at:\n"
269
- f"{file_path}\n"
270
- f"---\n\n"
271
- )
272
- else:
273
- q_for_agent = question_text
274
-
275
  if not task_id or question_text is None:
276
  print(f"Skipping item with missing task_id or question: {item}")
277
  continue
278
  try:
279
- submitted_answer = agent(q_for_agent)
280
- answers_payload.append(
281
- {"task_id": task_id, "submitted_answer": submitted_answer}
282
- )
283
- results_log.append(
284
- {
285
- "Task ID": task_id,
286
- "Question": question_text,
287
- "Submitted Answer": submitted_answer,
288
- }
289
- )
290
- except Exception as e: # pylint: disable=broad-except
291
- print(f"Error running agent on task {task_id}: {e}")
292
- results_log.append(
293
- {
294
- "Task ID": task_id,
295
- "Question": question_text,
296
- "Submitted Answer": f"AGENT ERROR: {e}",
297
- }
298
- )
299
 
300
  if not answers_payload:
301
  print("Agent did not produce any answers to submit.")
302
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
303
 
304
- # 4. Prepare Submission
305
- submission_data = {
306
- "username": username.strip(),
307
- "agent_code": agent_code,
308
- "answers": answers_payload,
309
- }
310
-
311
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
312
  print(status_update)
313
 
@@ -348,7 +148,7 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
348
  print(status_message)
349
  results_df = pd.DataFrame(results_log)
350
  return status_message, results_df
351
- except Exception as e: # pylint: disable=broad-except
352
  status_message = f"An unexpected error occurred during submission: {e}"
353
  print(status_message)
354
  results_df = pd.DataFrame(results_log)
@@ -359,35 +159,29 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
359
  with gr.Blocks() as demo:
360
  gr.Markdown("# Basic Agent Evaluation Runner")
361
  gr.Markdown(
362
- """
363
- **Instructions:**
364
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
365
- 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
366
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
367
- ---
368
- **Disclaimers:**
369
- 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).
370
- 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.
371
- """
372
  )
373
 
374
  gr.LoginButton()
375
 
376
  run_button = gr.Button("Run Evaluation & Submit All Answers")
377
 
378
- status_output = gr.Textbox(
379
- label="Run Status / Submission Result", lines=5, interactive=False
380
- )
381
  # Removed max_rows=10 from DataFrame constructor
382
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
383
 
384
- run_button.click(fn=run_and_submit_all, outputs=[status_output, results_table])
 
 
 
385
 
386
  if __name__ == "__main__":
387
- print("\n" + "-" * 30 + " App Starting " + "-" * 30)
388
  # Check for SPACE_HOST and SPACE_ID at startup for information
389
  space_host_startup = os.getenv("SPACE_HOST")
390
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
391
 
392
  if space_host_startup:
393
  print(f"βœ… SPACE_HOST found: {space_host_startup}")
@@ -395,18 +189,16 @@ if __name__ == "__main__":
395
  else:
396
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
397
 
398
- if space_id_startup: # Print repo URLs if SPACE_ID is found
399
  print(f"βœ… SPACE_ID found: {space_id_startup}")
400
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
401
- print(
402
- f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main"
403
- )
404
  else:
405
- print(
406
- "ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined."
407
- )
408
 
409
- print("-" * (60 + len(" App Starting ")) + "\n")
410
 
411
  print("Launching Gradio Interface for Basic Agent Evaluation...")
412
  demo.launch(debug=True, share=False)
 
 
 
1
  import os
 
 
 
 
 
 
 
 
 
2
  import gradio as gr
3
+ import requests
4
+ import inspect
5
  import pandas as pd
6
+ from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel
 
 
7
 
8
+ # (Keep Constants and BasicAgent class as is)
 
9
  # --- Constants ---
10
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
11
 
12
+ # --- Basic Agent Definition ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  class BasicAgent:
 
 
14
  def __init__(self):
 
 
 
 
 
 
 
 
 
 
 
 
15
  print("BasicAgent initialized.")
16
+ self.agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=HfApiModel())
17
+
18
+ SYSTEM_PROMPT = """You are a general AI assistant. I will ask you a question. Report your thoughts, and
19
+ finish your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER].
20
+ YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated
21
+ list of numbers and/or strings.
22
+ If you are asked for a number, don't use comma to write your number neither use units such as $ or
23
+ percent sign unless specified otherwise.
24
+ If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the
25
+ digits in plain text unless specified otherwise.
26
+ If you are asked for a comma separated list, apply the above rules depending of whether the element
27
+ to be put in the list is a number or a string.
28
+ """
29
+ self.agent.prompt_templates["system_prompt"] = self.agent.prompt_templates["system_prompt"] + SYSTEM_PROMPT
30
+
31
  def __call__(self, question: str) -> str:
32
  print(f"Agent received question (first 50 chars): {question[:50]}...")
33
+ final_answer = self.agent.run(question)
34
+ print(f"Agent returning final answer: {final_answer}")
35
+ return final_answer
 
36
 
37
+ def run_and_submit_all( profile: gr.OAuthProfile | None):
38
  """
39
  Fetches all questions, runs the BasicAgent on them, submits all answers,
40
  and displays the results.
41
  """
42
  # --- Determine HF Space Runtime URL and Repo URL ---
43
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
44
 
45
  if profile:
46
+ username= f"{profile.username}"
47
  print(f"User logged in: {username}")
48
  else:
49
  print("User not logged in.")
 
53
  questions_url = f"{api_url}/questions"
54
  submit_url = f"{api_url}/submit"
55
 
56
+ # 1. Instantiate Agent ( modify this part to create your agent)
57
  try:
58
  agent = BasicAgent()
59
+ except Exception as e:
60
  print(f"Error instantiating agent: {e}")
61
  return f"Error initializing agent: {e}", None
62
  # 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)
 
70
  response.raise_for_status()
71
  questions_data = response.json()
72
  if not questions_data:
73
+ print("Fetched questions list is empty.")
74
+ return "Fetched questions list is empty or invalid format.", None
75
  print(f"Fetched {len(questions_data)} questions.")
 
 
 
 
76
  except requests.exceptions.RequestException as e:
77
  print(f"Error fetching questions: {e}")
78
  return f"Error fetching questions: {e}", None
79
+ except requests.exceptions.JSONDecodeError as e:
80
+ print(f"Error decoding JSON response from questions endpoint: {e}")
81
+ print(f"Response text: {response.text[:500]}")
82
+ return f"Error decoding server response for questions: {e}", None
83
+ except Exception as e:
84
  print(f"An unexpected error occurred fetching questions: {e}")
85
  return f"An unexpected error occurred fetching questions: {e}", None
86
 
 
91
  for item in questions_data:
92
  task_id = item.get("task_id")
93
  question_text = item.get("question")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  if not task_id or question_text is None:
95
  print(f"Skipping item with missing task_id or question: {item}")
96
  continue
97
  try:
98
+ submitted_answer = agent(question_text)
99
+ answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
100
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
101
+ except Exception as e:
102
+ print(f"Error running agent on task {task_id}: {e}")
103
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
  if not answers_payload:
106
  print("Agent did not produce any answers to submit.")
107
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
108
 
109
+ # 4. Prepare Submission
110
+ submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
 
 
 
 
 
111
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
112
  print(status_update)
113
 
 
148
  print(status_message)
149
  results_df = pd.DataFrame(results_log)
150
  return status_message, results_df
151
+ except Exception as e:
152
  status_message = f"An unexpected error occurred during submission: {e}"
153
  print(status_message)
154
  results_df = pd.DataFrame(results_log)
 
159
  with gr.Blocks() as demo:
160
  gr.Markdown("# Basic Agent Evaluation Runner")
161
  gr.Markdown(
162
+ "Please clone this space, then modify the code to define your agent's logic within the `BasicAgent` class. "
163
+ "Log in to your Hugging Face account using the button below. This uses your HF username for submission. "
164
+ "Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score."
 
 
 
 
 
 
 
165
  )
166
 
167
  gr.LoginButton()
168
 
169
  run_button = gr.Button("Run Evaluation & Submit All Answers")
170
 
171
+ status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
 
 
172
  # Removed max_rows=10 from DataFrame constructor
173
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
174
 
175
+ run_button.click(
176
+ fn=run_and_submit_all,
177
+ outputs=[status_output, results_table]
178
+ )
179
 
180
  if __name__ == "__main__":
181
+ print("\n" + "-"*30 + " App Starting " + "-"*30)
182
  # Check for SPACE_HOST and SPACE_ID at startup for information
183
  space_host_startup = os.getenv("SPACE_HOST")
184
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
185
 
186
  if space_host_startup:
187
  print(f"βœ… SPACE_HOST found: {space_host_startup}")
 
189
  else:
190
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
191
 
192
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
193
  print(f"βœ… SPACE_ID found: {space_id_startup}")
194
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
195
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
 
 
196
  else:
197
+ print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
 
 
198
 
199
+ print("-"*(60 + len(" App Starting ")) + "\n")
200
 
201
  print("Launching Gradio Interface for Basic Agent Evaluation...")
202
  demo.launch(debug=True, share=False)
203
+
204
+