Mouhamedamar commited on
Commit
3339f5a
Β·
verified Β·
1 Parent(s): 63a15ab

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -101
app.py CHANGED
@@ -8,13 +8,19 @@ import gradio as gr
8
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
9
 
10
  # ──────────────────────────────────────────────
11
- # Tools
12
  # ──────────────────────────────────────────────
 
 
 
 
 
 
 
13
 
14
- from huggingface_hub import InferenceClient
15
- from smolagents import tool, CodeAgent
16
- from smolagents import DuckDuckGoSearchTool, VisitWebpageTool
17
-
18
 
19
  @tool
20
  def wikipedia_search(query: str) -> str:
@@ -66,15 +72,14 @@ def download_file_for_task(task_id: str) -> str:
66
  except Exception as e:
67
  return f"PDF error: {e}"
68
 
69
- # Audio β†’ transcribe
70
- if any(x in ct for x in ["audio", "mpeg", "mp3", "wav", "ogg"]) or data[:3] == b"ID3":
71
  hf_url = "https://api-inference.huggingface.co/models/openai/whisper-large-v3"
72
  headers = {"Authorization": f"Bearer {os.environ.get('HF_TOKEN','')}"}
73
  for _ in range(3):
74
  resp = requests.post(hf_url, headers=headers, data=data, timeout=120)
75
  if resp.status_code == 503:
76
- time.sleep(20)
77
- continue
78
  if resp.status_code == 200:
79
  return resp.json().get("text", "")
80
  return "Audio transcription failed."
@@ -94,16 +99,10 @@ def download_file_for_task(task_id: str) -> str:
94
  return f"Spreadsheet error: {e}"
95
 
96
  # Image β†’ vision model
97
- if any(x in ct for x in ["image", "png", "jpg", "jpeg", "gif", "webp"]):
98
  import base64
99
  b64 = base64.b64encode(data).decode()
100
- # Detect media type
101
- if data[:4] == b"\x89PNG":
102
- mime = "image/png"
103
- elif data[:2] == b"\xff\xd8":
104
- mime = "image/jpeg"
105
- else:
106
- mime = "image/png"
107
  hf_url = "https://api-inference.huggingface.co/models/meta-llama/Llama-3.2-11B-Vision-Instruct/v1/chat/completions"
108
  headers = {
109
  "Authorization": f"Bearer {os.environ.get('HF_TOKEN','')}",
@@ -111,20 +110,16 @@ def download_file_for_task(task_id: str) -> str:
111
  }
112
  payload = {
113
  "model": "meta-llama/Llama-3.2-11B-Vision-Instruct",
114
- "messages": [{
115
- "role": "user",
116
- "content": [
117
- {"type": "image_url", "image_url": {"url": f"data:{mime};base64,{b64}"}},
118
- {"type": "text", "text": "Describe this image in detail. If it's a chess position, describe every piece and its square. If it contains text or numbers, transcribe them exactly."},
119
- ]
120
- }],
121
  "max_tokens": 1024,
122
  }
123
  for _ in range(3):
124
  resp = requests.post(hf_url, headers=headers, json=payload, timeout=120)
125
  if resp.status_code == 503:
126
- time.sleep(20)
127
- continue
128
  if resp.status_code == 200:
129
  return resp.json()["choices"][0]["message"]["content"]
130
  return "Image analysis failed."
@@ -150,11 +145,10 @@ def get_youtube_transcript(video_url: str) -> str:
150
  if not vid_match:
151
  vid_match = re.search(r"youtu\.be/([A-Za-z0-9_-]{11})", video_url)
152
  if not vid_match:
153
- return "Could not extract video ID from URL."
154
  vid_id = vid_match.group(1)
155
  transcript = YouTubeTranscriptApi.get_transcript(vid_id, languages=["en", "en-US", "en-GB"])
156
- text = " ".join(t["text"] for t in transcript)
157
- return text[:5000]
158
  except Exception as e:
159
  return f"Transcript error: {e}"
160
 
@@ -184,83 +178,59 @@ def run_python_code(code: str) -> str:
184
  # Agent
185
  # ──────────────────────────────────────────────
186
 
187
- GAIA_SYSTEM_PROMPT = """You are an expert AI solving questions from the GAIA benchmark.
188
- You must give EXACT answers β€” they are checked with exact string matching.
189
-
190
- Guidelines:
191
- - For reversed/encoded text: decode it yourself first before answering.
192
- - For Wikipedia questions: search Wikipedia with specific terms.
193
- - For YouTube videos: use get_youtube_transcript tool.
194
- - For math/logic/tables: use run_python_code tool.
195
- - For attached files (images, PDFs, audio, spreadsheets): use download_file_for_task tool.
196
- - For counting (albums, items, etc): search and count carefully.
197
- - Answer with ONLY the final answer β€” no explanation, no punctuation unless asked.
198
- - For lists: comma-separated unless otherwise specified.
199
- - For numbers: digits only unless units are asked.
200
- """
201
-
202
-
203
- class InferenceClientModel:
204
- """Thin smolagents-compatible wrapper around huggingface_hub.InferenceClient."""
205
- def __init__(self, model_id: str, token: str, timeout: int = 120):
206
- self.model_id = model_id
207
- self.client = InferenceClient(model=model_id, token=token, timeout=timeout)
208
-
209
- def __call__(self, messages, stop_sequences=None, **kwargs):
210
- # Prepend GAIA system guidance if not already present
211
- if messages and messages[0].get("role") != "system":
212
- messages = [{"role": "system", "content": GAIA_SYSTEM_PROMPT}] + list(messages)
213
- elif messages and messages[0].get("role") == "system":
214
- messages = list(messages)
215
- messages[0]["content"] = GAIA_SYSTEM_PROMPT + "\n\n" + messages[0]["content"]
216
- response = self.client.chat_completion(
217
- messages=messages,
218
- max_tokens=2048,
219
- temperature=0.1,
220
- stop=stop_sequences or [],
221
- )
222
- return response.choices[0].message.content
223
-
224
-
225
- def make_agent() -> CodeAgent:
226
- token = os.environ.get("HF_TOKEN", "")
227
- model = InferenceClientModel(
228
- model_id="meta-llama/Llama-3.3-70B-Instruct",
229
- token=token,
230
- timeout=120,
231
- )
232
- tools = [
233
- DuckDuckGoSearchTool(),
234
- VisitWebpageTool(),
235
- wikipedia_search,
236
- download_file_for_task,
237
- get_youtube_transcript,
238
- run_python_code,
239
- ]
240
- agent = CodeAgent(
241
- tools=tools,
242
- model=model,
243
- max_steps=10,
244
- verbosity_level=1,
245
- additional_authorized_imports=["re", "json", "math", "datetime", "collections", "itertools"],
246
- )
247
- return agent
248
-
249
-
250
  class GAIAAgent:
251
  def __init__(self):
252
- self.agent = make_agent()
253
- print("GAIAAgent (smolagents) ready.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
  def __call__(self, question: str, task_id: str = "") -> str:
256
- print(f"\n{'='*55}\nQ: {question[:100]}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  try:
258
- result = self.agent.run(question)
259
  answer = str(result).strip()
260
- for prefix in ["The answer is", "Answer:", "ANSWER:", "Final answer:"]:
 
261
  if answer.lower().startswith(prefix.lower()):
262
- answer = answer[len(prefix):].strip().strip(":").strip()
263
- print(f"β†’ Answer: {answer}")
264
  return answer
265
  except Exception as e:
266
  print(f"Agent error: {e}")
@@ -300,7 +270,7 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
300
  question_text = item.get("question", "")
301
  if not task_id or not question_text:
302
  continue
303
- answer = agent(question_text)
304
  answers_payload.append({"task_id": task_id, "submitted_answer": answer})
305
  results_log.append({
306
  "Task ID": task_id,
@@ -337,7 +307,7 @@ with gr.Blocks() as demo:
337
  gr.Markdown("# πŸ€– GAIA Agent β€” smolagents + HF Inference")
338
  gr.Markdown("""
339
  **Models:** Llama-3.3-70B (reasoning) Β· Llama-3.2-11B-Vision (images) Β· Whisper large-v3 (audio)
340
- **Tools:** DuckDuckGo search Β· Wikipedia Β· Visit webpage Β· YouTube transcript Β· Python execution Β· File reader (PDF/Excel/Audio/Image)
341
  **Requires:** `HF_TOKEN` secret in your Space settings.
342
  """)
343
  gr.LoginButton()
 
8
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
9
 
10
  # ──────────────────────────────────────────────
11
+ # smolagents β€” InferenceClientModel est dans smolagents directement
12
  # ──────────────────────────────────────────────
13
+ from smolagents import (
14
+ tool,
15
+ CodeAgent,
16
+ InferenceClientModel,
17
+ DuckDuckGoSearchTool,
18
+ VisitWebpageTool,
19
+ )
20
 
21
+ # ──────────────────────────────────────────────
22
+ # Tools
23
+ # ──────────────────────────────────────────────
 
24
 
25
  @tool
26
  def wikipedia_search(query: str) -> str:
 
72
  except Exception as e:
73
  return f"PDF error: {e}"
74
 
75
+ # Audio
76
+ if any(x in ct for x in ["audio", "mpeg", "mp3", "wav"]) or data[:3] == b"ID3":
77
  hf_url = "https://api-inference.huggingface.co/models/openai/whisper-large-v3"
78
  headers = {"Authorization": f"Bearer {os.environ.get('HF_TOKEN','')}"}
79
  for _ in range(3):
80
  resp = requests.post(hf_url, headers=headers, data=data, timeout=120)
81
  if resp.status_code == 503:
82
+ time.sleep(20); continue
 
83
  if resp.status_code == 200:
84
  return resp.json().get("text", "")
85
  return "Audio transcription failed."
 
99
  return f"Spreadsheet error: {e}"
100
 
101
  # Image β†’ vision model
102
+ if any(x in ct for x in ["image", "png", "jpg", "jpeg"]):
103
  import base64
104
  b64 = base64.b64encode(data).decode()
105
+ mime = "image/png" if data[:4] == b"\x89PNG" else "image/jpeg"
 
 
 
 
 
 
106
  hf_url = "https://api-inference.huggingface.co/models/meta-llama/Llama-3.2-11B-Vision-Instruct/v1/chat/completions"
107
  headers = {
108
  "Authorization": f"Bearer {os.environ.get('HF_TOKEN','')}",
 
110
  }
111
  payload = {
112
  "model": "meta-llama/Llama-3.2-11B-Vision-Instruct",
113
+ "messages": [{"role": "user", "content": [
114
+ {"type": "image_url", "image_url": {"url": f"data:{mime};base64,{b64}"}},
115
+ {"type": "text", "text": "Describe this image in full detail. If chess: name every piece and square. If text/numbers: transcribe exactly."},
116
+ ]}],
 
 
 
117
  "max_tokens": 1024,
118
  }
119
  for _ in range(3):
120
  resp = requests.post(hf_url, headers=headers, json=payload, timeout=120)
121
  if resp.status_code == 503:
122
+ time.sleep(20); continue
 
123
  if resp.status_code == 200:
124
  return resp.json()["choices"][0]["message"]["content"]
125
  return "Image analysis failed."
 
145
  if not vid_match:
146
  vid_match = re.search(r"youtu\.be/([A-Za-z0-9_-]{11})", video_url)
147
  if not vid_match:
148
+ return "Could not extract video ID."
149
  vid_id = vid_match.group(1)
150
  transcript = YouTubeTranscriptApi.get_transcript(vid_id, languages=["en", "en-US", "en-GB"])
151
+ return " ".join(t["text"] for t in transcript)[:5000]
 
152
  except Exception as e:
153
  return f"Transcript error: {e}"
154
 
 
178
  # Agent
179
  # ──────────────────────────────────────────────
180
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  class GAIAAgent:
182
  def __init__(self):
183
+ model = InferenceClientModel(
184
+ model_id="meta-llama/Llama-3.3-70B-Instruct",
185
+ token=os.environ.get("HF_TOKEN", ""),
186
+ timeout=120,
187
+ )
188
+ self.agent = CodeAgent(
189
+ tools=[
190
+ DuckDuckGoSearchTool(),
191
+ VisitWebpageTool(),
192
+ wikipedia_search,
193
+ download_file_for_task,
194
+ get_youtube_transcript,
195
+ run_python_code,
196
+ ],
197
+ model=model,
198
+ max_steps=10,
199
+ verbosity_level=1,
200
+ additional_authorized_imports=[
201
+ "re", "json", "math", "datetime",
202
+ "collections", "itertools", "unicodedata",
203
+ ],
204
+ )
205
+ print("GAIAAgent ready βœ…")
206
 
207
  def __call__(self, question: str, task_id: str = "") -> str:
208
+ print(f"\n{'='*55}\nQ: {question[:120]}")
209
+ full_question = question
210
+ if task_id:
211
+ full_question = (
212
+ f"{question}\n\n"
213
+ f"[If this question needs a file, call download_file_for_task with task_id='{task_id}']"
214
+ )
215
+ prompt = (
216
+ "You are solving a GAIA benchmark question. Rules:\n"
217
+ "- Think step by step and use tools when needed.\n"
218
+ "- For YouTube links: call get_youtube_transcript.\n"
219
+ "- For attached files (image/pdf/audio/excel): call download_file_for_task.\n"
220
+ "- For math/logic: call run_python_code.\n"
221
+ "- For facts: call wikipedia_search or DuckDuckGoSearchTool.\n"
222
+ "- Give ONLY the final answer, nothing else. Exact match required.\n"
223
+ "- For lists: comma-separated. For numbers: digits only.\n\n"
224
+ f"Question: {full_question}"
225
+ )
226
  try:
227
+ result = self.agent.run(prompt)
228
  answer = str(result).strip()
229
+ # Strip common LLM prefixes
230
+ for prefix in ["The answer is", "Answer:", "ANSWER:", "Final answer:", "Result:"]:
231
  if answer.lower().startswith(prefix.lower()):
232
+ answer = answer[len(prefix):].strip().lstrip(":").strip()
233
+ print(f"β†’ {answer}")
234
  return answer
235
  except Exception as e:
236
  print(f"Agent error: {e}")
 
270
  question_text = item.get("question", "")
271
  if not task_id or not question_text:
272
  continue
273
+ answer = agent(question_text, task_id=task_id)
274
  answers_payload.append({"task_id": task_id, "submitted_answer": answer})
275
  results_log.append({
276
  "Task ID": task_id,
 
307
  gr.Markdown("# πŸ€– GAIA Agent β€” smolagents + HF Inference")
308
  gr.Markdown("""
309
  **Models:** Llama-3.3-70B (reasoning) Β· Llama-3.2-11B-Vision (images) Β· Whisper large-v3 (audio)
310
+ **Tools:** DuckDuckGo Β· Wikipedia Β· Visit webpage Β· YouTube transcript Β· Python execution Β· File reader
311
  **Requires:** `HF_TOKEN` secret in your Space settings.
312
  """)
313
  gr.LoginButton()