lmrkmrcs commited on
Commit
0c47b3c
Β·
verified Β·
1 Parent(s): b30a6a8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +148 -121
app.py CHANGED
@@ -3,113 +3,85 @@ import re
3
  import requests
4
  import gradio as gr
5
  import pandas as pd
6
- from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, tool, VisitWebpageTool
 
7
 
8
  # --- Constants ---
9
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
 
10
 
11
  # ============================================
12
- # TOOLS
13
  # ============================================
14
 
15
- @tool
16
- def calculator(expression: str) -> str:
17
- """
18
- Calculates a math expression.
19
-
20
- Args:
21
- expression: Math expression like "2+2" or "10*5"
22
-
23
- Returns:
24
- Result as string
25
- """
26
- import math
27
  try:
28
- safe = {"sqrt": math.sqrt, "pow": pow, "abs": abs, "round": round,
29
- "sin": math.sin, "cos": math.cos, "pi": math.pi, "log": math.log}
30
- return str(eval(expression, {"__builtins__": {}}, safe))
31
- except Exception as e:
32
- return f"Error: {e}"
 
 
33
 
34
 
35
- @tool
36
  def wikipedia_search(topic: str) -> str:
37
- """
38
- Gets Wikipedia summary for a topic.
39
-
40
- Args:
41
- topic: What to search
42
-
43
- Returns:
44
- Wikipedia extract
45
- """
46
  try:
47
  url = "https://en.wikipedia.org/w/api.php"
48
  params = {"action": "query", "list": "search", "srsearch": topic, "format": "json", "srlimit": 1}
49
- data = requests.get(url, params=params, timeout=10).json()
50
 
51
  if not data.get("query", {}).get("search"):
52
- return "No Wikipedia article found."
53
 
54
  title = data["query"]["search"][0]["title"]
55
  params2 = {"action": "query", "titles": title, "prop": "extracts", "exintro": True, "explaintext": True, "format": "json"}
56
- pages = requests.get(url, params=params2, timeout=10).json().get("query", {}).get("pages", {})
57
 
58
  for page in pages.values():
59
- return page.get("extract", "No content")[:3000]
60
  return "No content"
61
- except Exception as e:
62
- return f"Error: {e}"
63
 
64
 
65
- @tool
66
  def get_task_file(task_id: str) -> str:
67
- """
68
- Gets file content for a GAIA task.
69
-
70
- Args:
71
- task_id: The task ID
72
-
73
- Returns:
74
- File content
75
- """
76
  try:
77
  url = f"https://agents-course-unit4-scoring.hf.space/files/{task_id}"
78
- response = requests.get(url, timeout=20)
79
 
80
  if response.status_code == 404:
81
- return "No file for this task."
82
 
83
  content_type = response.headers.get('content-type', '').lower()
84
 
85
  if 'text' in content_type or 'json' in content_type:
86
- return response.text[:5000]
87
 
88
- if 'spreadsheet' in content_type or 'excel' in content_type:
89
  try:
90
  from io import BytesIO
91
  df = pd.read_excel(BytesIO(response.content))
92
- return df.to_string()
93
  except:
94
- return "Excel file (cannot read)"
95
 
96
- return f"Binary file: {content_type}"
97
- except Exception as e:
98
- return f"Error: {e}"
99
-
100
-
101
- @tool
102
- def reverse_text(text: str) -> str:
103
- """
104
- Reverses text.
105
-
106
- Args:
107
- text: Text to reverse
108
-
109
- Returns:
110
- Reversed text
111
- """
112
- return text[::-1]
113
 
114
 
115
  # ============================================
@@ -118,56 +90,67 @@ def reverse_text(text: str) -> str:
118
 
119
  class BasicAgent:
120
  def __init__(self):
121
- print("Initializing HuggingFace agent...")
122
-
123
- # Use HfApiModel with a FREE model
124
- self.model = HfApiModel(
125
- model_id="Qwen/Qwen2.5-72B-Instruct", # This one should be free
126
- token=os.environ.get("HF_TOKEN"),
127
- )
128
-
129
- self.agent = CodeAgent(
130
- model=self.model,
131
- tools=[
132
- DuckDuckGoSearchTool(),
133
- VisitWebpageTool(),
134
- wikipedia_search,
135
- calculator,
136
- get_task_file,
137
- reverse_text,
138
- ],
139
- max_steps=5,
140
- verbosity_level=2,
141
- )
142
- print("Agent ready!")
143
 
144
  def __call__(self, question: str, task_id: str = None) -> str:
145
- print(f" Processing: {question[:60]}...")
146
-
147
  try:
148
- prompt = f"""Answer this question concisely. Use tools if needed.
149
- If a file is mentioned, use get_task_file("{task_id}").
150
- Give ONLY the final answer.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
- Question: {question}"""
153
 
154
- result = self.agent.run(prompt)
155
- answer = str(result).strip()
 
 
 
 
 
156
 
157
- # Clean up
158
- for prefix in ["Answer:", "Final answer:", "The answer is"]:
 
 
159
  if answer.lower().startswith(prefix.lower()):
160
  answer = answer[len(prefix):].strip()
161
 
162
- if answer.startswith('"') and answer.endswith('"'):
 
 
163
  answer = answer[1:-1]
164
 
165
- print(f" Answer: {answer[:60]}")
166
  return answer
167
 
168
  except Exception as e:
169
- print(f" Error: {e}")
170
- return "Unable to answer"
171
 
172
 
173
  # ============================================
@@ -183,42 +166,61 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
183
 
184
  print(f"\n{'='*50}")
185
  print(f"User: {username}")
186
- print(f"{'='*50}")
 
 
 
 
 
 
187
 
188
  # Init agent
189
  try:
190
  agent = BasicAgent()
191
  except Exception as e:
192
- return f"Agent failed to init: {e}", None
193
 
194
  # Get questions
195
  try:
196
  questions = requests.get(f"{DEFAULT_API_URL}/questions", timeout=15).json()
197
- print(f"Fetched {len(questions)} questions\n")
198
  except Exception as e:
199
- return f"Failed to fetch questions: {e}", None
200
 
201
  # Process each question
202
  results = []
203
  answers = []
204
 
 
 
 
205
  for i, q in enumerate(questions):
206
  task_id = q.get("task_id")
207
  question = q.get("question", "")
208
 
209
- print(f"[{i+1}/{len(questions)}] {task_id}")
 
210
 
211
  try:
212
  answer = agent(question, task_id)
 
 
213
  except Exception as e:
214
- answer = "Error"
215
- print(f" Failed: {e}")
216
 
217
  answers.append({"task_id": task_id, "submitted_answer": answer})
218
- results.append({"#": i+1, "Question": question[:50]+"...", "Answer": answer[:80]})
 
 
 
 
 
 
 
219
 
220
  # Submit
221
- print(f"\nSubmitting {len(answers)} answers...")
222
 
223
  try:
224
  submission = {
@@ -232,13 +234,22 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
232
  correct = result.get('correct_count', 0)
233
  total = result.get('total_attempted', 0)
234
 
235
- status = f"βœ… Done!\n\nScore: {score}% ({correct}/{total})\n\n"
236
- status += "πŸŽ‰ PASSED!" if score >= 30 else f"Need {30-score}% more to pass"
 
 
 
 
 
 
 
 
 
237
 
238
  return status, pd.DataFrame(results)
239
 
240
  except Exception as e:
241
- return f"Submit failed: {e}", pd.DataFrame(results)
242
 
243
 
244
  # ============================================
@@ -247,16 +258,32 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
247
 
248
  with gr.Blocks() as demo:
249
  gr.Markdown("# 🎯 GAIA Agent - Unit 4")
250
- gr.Markdown("Using **HuggingFace** + **Qwen 72B**")
 
 
 
 
 
 
 
 
 
251
 
252
  gr.LoginButton()
253
- run_btn = gr.Button("πŸš€ Run Evaluation", variant="primary")
254
- status = gr.Textbox(label="Status", lines=5)
255
  table = gr.DataFrame(label="Results")
256
 
257
  run_btn.click(run_and_submit_all, outputs=[status, table])
258
 
259
  if __name__ == "__main__":
260
- print("Starting GAIA Agent (HuggingFace)...")
261
- print(f"HF_TOKEN: {'βœ… Found' if os.environ.get('HF_TOKEN') else '❌ Missing'}")
 
 
 
 
 
 
 
262
  demo.launch()
 
3
  import requests
4
  import gradio as gr
5
  import pandas as pd
6
+ from groq import Groq
7
+ from duckduckgo_search import DDGS
8
 
9
  # --- Constants ---
10
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
11
+ TIMEOUT_PER_QUESTION = 30 # Max 30 seconds per question
12
 
13
  # ============================================
14
+ # INITIALIZE GROQ CLIENT
15
  # ============================================
16
 
17
+ def get_groq_client():
18
+ api_key = os.environ.get("GROQ_API_KEY")
19
+ if not api_key:
20
+ raise ValueError("GROQ_API_KEY not set!")
21
+ return Groq(api_key=api_key)
22
+
23
+ # ============================================
24
+ # TOOL FUNCTIONS
25
+ # ============================================
26
+
27
+ def web_search(query: str) -> str:
28
+ """Search the web"""
29
  try:
30
+ with DDGS() as ddgs:
31
+ results = list(ddgs.text(query, max_results=3))
32
+ if not results:
33
+ return "No results"
34
+ return "\n".join([f"- {r['title']}: {r['body']}" for r in results])
35
+ except:
36
+ return "Search failed"
37
 
38
 
 
39
  def wikipedia_search(topic: str) -> str:
40
+ """Get Wikipedia info"""
 
 
 
 
 
 
 
 
41
  try:
42
  url = "https://en.wikipedia.org/w/api.php"
43
  params = {"action": "query", "list": "search", "srsearch": topic, "format": "json", "srlimit": 1}
44
+ data = requests.get(url, params=params, timeout=5).json()
45
 
46
  if not data.get("query", {}).get("search"):
47
+ return "Not found"
48
 
49
  title = data["query"]["search"][0]["title"]
50
  params2 = {"action": "query", "titles": title, "prop": "extracts", "exintro": True, "explaintext": True, "format": "json"}
51
+ pages = requests.get(url, params=params2, timeout=5).json().get("query", {}).get("pages", {})
52
 
53
  for page in pages.values():
54
+ return page.get("extract", "")[:2000]
55
  return "No content"
56
+ except:
57
+ return "Wikipedia error"
58
 
59
 
 
60
  def get_task_file(task_id: str) -> str:
61
+ """Get GAIA task file"""
 
 
 
 
 
 
 
 
62
  try:
63
  url = f"https://agents-course-unit4-scoring.hf.space/files/{task_id}"
64
+ response = requests.get(url, timeout=10)
65
 
66
  if response.status_code == 404:
67
+ return ""
68
 
69
  content_type = response.headers.get('content-type', '').lower()
70
 
71
  if 'text' in content_type or 'json' in content_type:
72
+ return response.text[:4000]
73
 
74
+ if 'excel' in content_type or 'spreadsheet' in content_type:
75
  try:
76
  from io import BytesIO
77
  df = pd.read_excel(BytesIO(response.content))
78
+ return df.to_string()[:4000]
79
  except:
80
+ return "Excel file"
81
 
82
+ return f"File type: {content_type}"
83
+ except:
84
+ return ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
 
87
  # ============================================
 
90
 
91
  class BasicAgent:
92
  def __init__(self):
93
+ print("Initializing Groq agent...")
94
+ self.client = get_groq_client()
95
+ print("βœ… Agent ready!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
  def __call__(self, question: str, task_id: str = None) -> str:
 
 
98
  try:
99
+ # Check for file first
100
+ file_content = ""
101
+ if task_id:
102
+ file_content = get_task_file(task_id)
103
+
104
+ # Check if we need to search
105
+ needs_search = any(word in question.lower() for word in
106
+ ["who is", "what is", "when did", "where is", "current", "latest", "recent"])
107
+
108
+ search_results = ""
109
+ if needs_search and not file_content:
110
+ # Extract search query from question
111
+ search_results = web_search(question[:100])
112
+
113
+ # Build context
114
+ context = ""
115
+ if file_content:
116
+ context += f"\n\nFile content:\n{file_content}"
117
+ if search_results and search_results != "No results":
118
+ context += f"\n\nSearch results:\n{search_results}"
119
+
120
+ # Ask Groq
121
+ prompt = f"""Answer this question with ONLY the final answer. No explanation.
122
+ Be precise - just give the exact answer.
123
+ {context}
124
+
125
+ Question: {question}
126
 
127
+ Answer:"""
128
 
129
+ response = self.client.chat.completions.create(
130
+ model="llama-3.3-70b-versatile",
131
+ messages=[{"role": "user", "content": prompt}],
132
+ temperature=0,
133
+ max_tokens=200,
134
+ timeout=TIMEOUT_PER_QUESTION,
135
+ )
136
 
137
+ answer = response.choices[0].message.content.strip()
138
+
139
+ # Clean up common prefixes
140
+ for prefix in ["Answer:", "The answer is:", "Final answer:", "A:"]:
141
  if answer.lower().startswith(prefix.lower()):
142
  answer = answer[len(prefix):].strip()
143
 
144
+ # Remove quotes
145
+ if (answer.startswith('"') and answer.endswith('"')) or \
146
+ (answer.startswith("'") and answer.endswith("'")):
147
  answer = answer[1:-1]
148
 
 
149
  return answer
150
 
151
  except Exception as e:
152
+ print(f" Error: {e}")
153
+ return "unknown"
154
 
155
 
156
  # ============================================
 
166
 
167
  print(f"\n{'='*50}")
168
  print(f"User: {username}")
169
+
170
+ # Check API key
171
+ if not os.environ.get("GROQ_API_KEY"):
172
+ return "❌ ERROR: Add GROQ_API_KEY to Space secrets!", None
173
+
174
+ print("βœ… GROQ_API_KEY found")
175
+ print(f"{'='*50}\n")
176
 
177
  # Init agent
178
  try:
179
  agent = BasicAgent()
180
  except Exception as e:
181
+ return f"❌ Agent init failed: {e}", None
182
 
183
  # Get questions
184
  try:
185
  questions = requests.get(f"{DEFAULT_API_URL}/questions", timeout=15).json()
186
+ print(f"πŸ“‹ Got {len(questions)} questions\n")
187
  except Exception as e:
188
+ return f"❌ Failed to fetch questions: {e}", None
189
 
190
  # Process each question
191
  results = []
192
  answers = []
193
 
194
+ import time
195
+ start_time = time.time()
196
+
197
  for i, q in enumerate(questions):
198
  task_id = q.get("task_id")
199
  question = q.get("question", "")
200
 
201
+ q_start = time.time()
202
+ print(f"[{i+1}/{len(questions)}] {question[:70]}...")
203
 
204
  try:
205
  answer = agent(question, task_id)
206
+ q_time = time.time() - q_start
207
+ print(f" βœ“ {answer[:50]}... ({q_time:.1f}s)")
208
  except Exception as e:
209
+ answer = "unknown"
210
+ print(f" βœ— Error: {e}")
211
 
212
  answers.append({"task_id": task_id, "submitted_answer": answer})
213
+ results.append({
214
+ "#": i+1,
215
+ "Question": question[:50]+"...",
216
+ "Answer": answer[:60]
217
+ })
218
+
219
+ total_time = time.time() - start_time
220
+ print(f"\n⏱️ Total time: {total_time:.1f}s ({total_time/60:.1f} min)")
221
 
222
  # Submit
223
+ print(f"\nπŸ“€ Submitting {len(answers)} answers...")
224
 
225
  try:
226
  submission = {
 
234
  correct = result.get('correct_count', 0)
235
  total = result.get('total_attempted', 0)
236
 
237
+ status = f"βœ… Done in {total_time:.0f}s!\n\n"
238
+ status += f"🎯 Score: {score}% ({correct}/{total} correct)\n\n"
239
+
240
+ if score >= 30:
241
+ status += "πŸŽ‰ PASSED! You got 30%+!"
242
+ else:
243
+ status += f"πŸ“ˆ Need {30-score}% more to pass"
244
+
245
+ print(f"\n{'='*50}")
246
+ print(f"SCORE: {score}% ({correct}/{total})")
247
+ print(f"{'='*50}")
248
 
249
  return status, pd.DataFrame(results)
250
 
251
  except Exception as e:
252
+ return f"❌ Submit failed: {e}", pd.DataFrame(results)
253
 
254
 
255
  # ============================================
 
258
 
259
  with gr.Blocks() as demo:
260
  gr.Markdown("# 🎯 GAIA Agent - Unit 4")
261
+ gr.Markdown("""
262
+ **Powered by Groq + Llama 3.3 70B**
263
+
264
+ ⚑ Fast: ~5-10 minutes for all 20 questions
265
+
266
+ **Setup:**
267
+ 1. Add `GROQ_API_KEY` to Space secrets
268
+ 2. Log in below
269
+ 3. Click Run!
270
+ """)
271
 
272
  gr.LoginButton()
273
+ run_btn = gr.Button("πŸš€ Run Evaluation", variant="primary", size="lg")
274
+ status = gr.Textbox(label="Status", lines=6)
275
  table = gr.DataFrame(label="Results")
276
 
277
  run_btn.click(run_and_submit_all, outputs=[status, table])
278
 
279
  if __name__ == "__main__":
280
+ print("="*50)
281
+ print("🎯 GAIA Agent - Groq Edition")
282
+ print("="*50)
283
+
284
+ if os.environ.get("GROQ_API_KEY"):
285
+ print("βœ… GROQ_API_KEY found")
286
+ else:
287
+ print("❌ GROQ_API_KEY missing - add to secrets!")
288
+
289
  demo.launch()