JanEisen commited on
Commit
9ebdc49
·
1 Parent(s): 1013893

used smol_agents, works way better, added post processing with simple 4o-mini call, 50% completion

Browse files
LEARNINGS.MD CHANGED
@@ -14,7 +14,11 @@
14
  not an option for european customers due to only US based datacenters
15
 
16
  ### Smolagents
17
- try out
 
 
 
 
18
 
19
  ### Llamaindex
20
  try out
 
14
  not an option for european customers due to only US based datacenters
15
 
16
  ### Smolagents
17
+ - very flexible code agent
18
+ - duckduckgo search has low rate limit, serper api 2500 free searches, then paid as alternative
19
+ -
20
+
21
+
22
 
23
  ### Llamaindex
24
  try out
REQUIREMENTS.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # capabilites the agent needs
2
+
3
+ - internet access
4
+ - search the internet (google/duckduckgo)
5
+ - open webpages
6
+ - search wikipedia
7
+ - open complete wikipedia pages
8
+ - watch youtube videos (multi-modal model with file download/youtube streaming or video to images + image recognition)
9
+
10
+
11
+ prompt adjustment or post processing of answers: only value itself without any fluff should be given out.
__pycache__/app_openai.cpython-312.pyc ADDED
Binary file (17.5 kB). View file
 
__pycache__/app_smolagents.cpython-312.pyc ADDED
Binary file (14.7 kB). View file
 
app.py → app_openai.py RENAMED
File without changes
app_smolagents.py ADDED
@@ -0,0 +1,294 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import requests
4
+ import inspect
5
+ import asyncio
6
+ import pandas as pd
7
+ from dotenv import load_dotenv
8
+ from litellm import completion
9
+ from smolagents import ToolCallingAgent, Tool, CodeAgent, LiteLLMModel, PythonInterpreterTool, WikipediaSearchTool, GoogleSearchTool, FinalAnswerTool, VisitWebpageTool, SpeechToTextTool, DuckDuckGoSearchTool
10
+
11
+ # (Keep Constants as is)
12
+ # --- Constants ---
13
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
14
+
15
+ load_dotenv()
16
+
17
+ model = LiteLLMModel(
18
+ model_id="azure/" + os.getenv("AZURE_OPENAI_DEPLOYMENT"),
19
+ api_base=os.getenv("AZURE_OPENAI_ENDPOINT"),
20
+ api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
21
+ api_key=os.getenv("AZURE_OPENAI_API_KEY")
22
+ )
23
+
24
+
25
+ # --- Agent Base Class ---
26
+ class BaseAgent:
27
+ """Base class for agent implementations"""
28
+
29
+ def __init__(self):
30
+
31
+ self.agent = ToolCallingAgent(
32
+ tools=[
33
+ FinalAnswerTool(),
34
+ PythonInterpreterTool(),
35
+ VisitWebpageTool(
36
+ max_output_length=100000
37
+ ),
38
+ WikipediaSearchTool(
39
+ user_agent="Jan Eisenbarth Research Bot (jan.eisenbarth@gmail.com)",
40
+ language="en",
41
+ content_type="summary", # or "text"
42
+ extract_format="WIKI",
43
+ ),
44
+ GoogleSearchTool()
45
+ ],
46
+ model=model
47
+ )
48
+
49
+ async def __call__(self, question: str) -> str:
50
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
51
+ try:
52
+ # Run the agent synchronously - smolagents doesn't need async
53
+ answer = self.agent.run(question)
54
+
55
+ # Convert the answer to a string to ensure we can handle any return type
56
+ answer_str = str(answer)
57
+
58
+ print(f"Agent returning answer (first 50 chars): {answer_str[:50] if answer_str else 'No answer'}...")
59
+ return answer_str
60
+ except Exception as e:
61
+ print(f"Error in agent processing: {e}")
62
+ # Fallback mechanism in case of errors
63
+ fallback_answer = f"ERROR: {str(e)}"
64
+ return fallback_answer
65
+
66
+
67
+ def answer_post_processing(question: str, answer: str) -> str:
68
+ """Post-process the answer to remove any fluff"""
69
+ response = completion(
70
+ model="gpt-4o-mini",
71
+ messages=[
72
+ {"role": "system", "content": "You are a helpful assistant that can answer questions and help with tasks. Your job is to look at a given question and answer and remove any fluff or extra information. Output only the direct answer to the question. No punctuation marks, no introductory words, no nothing. Just the Value / String / List that answers the question in as few characters as possible."},
73
+ {"role": "user", "content": f"Question: {question}\nAnswer: {answer}"}
74
+ ]
75
+ )
76
+ cleaned_answer = response['choices'][0]['message']['content']
77
+ print(f"Cleaned answer: {cleaned_answer}")
78
+ return cleaned_answer
79
+
80
+
81
+ # --- Default Huggingface Functions for Evaluation and Submission ---
82
+
83
+ def run_and_submit_all(profile: gr.OAuthProfile = None):
84
+ # This needs to be sync since Gradio expects a sync function
85
+ try:
86
+ # Get the current user profile from context if not explicitly passed
87
+ if profile is None:
88
+ profile = gr.context.get("user", None)
89
+
90
+ return asyncio.run(_run_and_submit_all_async(profile))
91
+ except Exception as e:
92
+ print(f"Error in run_and_submit_all: {e}")
93
+ return f"An unexpected error occurred: {e}", None
94
+
95
+ async def _run_and_submit_all_async(profile: gr.OAuthProfile | None):
96
+ # --- Determine HF Space Runtime URL and Repo URL ---
97
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
98
+
99
+ if profile:
100
+ username= f"{profile.username}"
101
+ print(f"User logged in: {username}")
102
+ else:
103
+ print("User not logged in.")
104
+ return "Please Login to Hugging Face with the button.", None
105
+
106
+ api_url = DEFAULT_API_URL
107
+ questions_url = f"{api_url}/questions"
108
+ submit_url = f"{api_url}/submit"
109
+
110
+ # 1. Instantiate Agent
111
+ try:
112
+ agent = BaseAgent()
113
+ print(f"Using agent type: {agent.__class__.__name__}")
114
+ except Exception as e:
115
+ print(f"Error instantiating agent: {e}")
116
+ return f"Error initializing agent: {e}", None
117
+
118
+ # In the case of an app running as a hugging Face space, this link points toward your codebase
119
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
120
+ print(f"Agent code URL: {agent_code}")
121
+
122
+ # 2. Fetch Questions
123
+ print(f"Fetching questions from: {questions_url}")
124
+ try:
125
+ response = requests.get(questions_url, timeout=30) # Increased timeout
126
+ response.raise_for_status()
127
+ questions_data = response.json()
128
+ if not questions_data:
129
+ print("Fetched questions list is empty.")
130
+ return "Fetched questions list is empty or invalid format.", None
131
+ print(f"Successfully fetched {len(questions_data)} questions.")
132
+ except requests.exceptions.RequestException as e:
133
+ print(f"Error fetching questions: {e}")
134
+ return f"Error fetching questions: {e}", None
135
+ except requests.exceptions.JSONDecodeError as e:
136
+ print(f"Error decoding JSON response from questions endpoint: {e}")
137
+ print(f"Response text: {response.text[:500]}")
138
+ return f"Error decoding server response for questions: {e}", None
139
+ except Exception as e:
140
+ print(f"An unexpected error occurred fetching questions: {e}")
141
+ return f"An unexpected error occurred fetching questions: {e}", None
142
+
143
+ # 3. Run your Agent
144
+ results_log = []
145
+ answers_payload = []
146
+ print(f"Running agent on {len(questions_data)} questions...")
147
+
148
+ for idx, item in enumerate(questions_data):
149
+ task_id = item.get("task_id")
150
+ question_text = item.get("question")
151
+ if not task_id or question_text is None:
152
+ print(f"Skipping item with missing task_id or question: {item}")
153
+ continue
154
+
155
+ print(f"Processing question {idx+1}/{len(questions_data)}: Task ID {task_id}")
156
+ try:
157
+ # Call the agent to process the question
158
+ temp_answer = await agent(question_text)
159
+ # Post-process the answer
160
+ submitted_answer = answer_post_processing(question_text, temp_answer)
161
+ # Add to our results
162
+ answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
163
+ results_log.append({
164
+ "Task ID": task_id,
165
+ "Question": question_text,
166
+ "Submitted Answer": submitted_answer
167
+ })
168
+ print(f"Successfully processed question {idx+1}")
169
+ except Exception as e:
170
+ error_msg = f"Error running agent on task {task_id}: {e}"
171
+ print(error_msg)
172
+ # Still add to results but mark as error
173
+ results_log.append({
174
+ "Task ID": task_id,
175
+ "Question": question_text,
176
+ "Submitted Answer": f"AGENT ERROR: {e}"
177
+ })
178
+
179
+ if not answers_payload:
180
+ print("Agent did not produce any answers to submit.")
181
+ return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
182
+
183
+ # 4. Prepare Submission
184
+ submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
185
+ status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
186
+ print(status_update)
187
+
188
+ # 5. Submit
189
+ print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
190
+ try:
191
+ response = requests.post(submit_url, json=submission_data, timeout=120) # Increased timeout for larger submissions
192
+ response.raise_for_status()
193
+ result_data = response.json()
194
+ final_status = (
195
+ f"Submission Successful!\n"
196
+ f"User: {result_data.get('username')}\n"
197
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
198
+ f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
199
+ f"Message: {result_data.get('message', 'No message received.')}"
200
+ )
201
+ print("Submission successful.")
202
+ results_df = pd.DataFrame(results_log)
203
+ return final_status, results_df
204
+ except requests.exceptions.HTTPError as e:
205
+ error_detail = f"Server responded with status {e.response.status_code}."
206
+ try:
207
+ error_json = e.response.json()
208
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
209
+ except requests.exceptions.JSONDecodeError:
210
+ error_detail += f" Response: {e.response.text[:500]}"
211
+ status_message = f"Submission Failed: {error_detail}"
212
+ print(status_message)
213
+ results_df = pd.DataFrame(results_log)
214
+ return status_message, results_df
215
+ except requests.exceptions.Timeout:
216
+ status_message = "Submission Failed: The request timed out."
217
+ print(status_message)
218
+ results_df = pd.DataFrame(results_log)
219
+ return status_message, results_df
220
+ except requests.exceptions.RequestException as e:
221
+ status_message = f"Submission Failed: Network error - {e}"
222
+ print(status_message)
223
+ results_df = pd.DataFrame(results_log)
224
+ return status_message, results_df
225
+ except Exception as e:
226
+ status_message = f"An unexpected error occurred during submission: {e}"
227
+ print(status_message)
228
+ results_df = pd.DataFrame(results_log)
229
+ return status_message, results_df
230
+
231
+
232
+ # --- Build Gradio Interface using Blocks ---
233
+ with gr.Blocks() as demo:
234
+ gr.Markdown("# Enhanced Agent Evaluation Runner")
235
+ gr.Markdown(
236
+ """
237
+ **Instructions:**
238
+
239
+ 1. Please ensure you have the required environment variables set in your .env file
240
+ 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
241
+ 3. Select the agent type you want to use.
242
+ 4. Click 'Run Evaluation & Submit All Answers' to fetch questions, run the agent, submit answers, and see the score.
243
+
244
+ ---
245
+ **Note:**
246
+ The evaluation process may take several minutes as the agent processes all questions sequentially.
247
+ """
248
+ )
249
+
250
+ with gr.Row():
251
+ with gr.Column(scale=1):
252
+ gr.LoginButton()
253
+ with gr.Column(scale=2):
254
+ run_button = gr.Button("Run Evaluation & Submit All Answers", variant="primary")
255
+
256
+ status_output = gr.Textbox(
257
+ label="Run Status / Submission Result",
258
+ lines=6,
259
+ interactive=False
260
+ )
261
+
262
+ results_table = gr.DataFrame(
263
+ label="Questions and Agent Answers",
264
+ wrap=True
265
+ )
266
+
267
+ run_button.click(
268
+ fn=run_and_submit_all,
269
+ outputs=[status_output, results_table]
270
+ )
271
+
272
+ if __name__ == "__main__":
273
+ print("\n" + "-"*30 + " App Starting " + "-"*30)
274
+
275
+ # Check for SPACE_HOST and SPACE_ID at startup for information
276
+ space_host_startup = os.getenv("SPACE_HOST")
277
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
278
+
279
+ if space_host_startup:
280
+ print(f"✅ SPACE_HOST found: {space_host_startup}")
281
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
282
+ else:
283
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
284
+
285
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
286
+ print(f"✅ SPACE_ID found: {space_id_startup}")
287
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
288
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
289
+ else:
290
+ print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
291
+
292
+ print("-"*(60 + len(" App Starting ")) + "\n")
293
+
294
+ demo.launch(debug=True, share=False)
questions.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ | ID | question | answer |
3
+ | --- | --- | --- |
4
+ | |How many studio albums were published by Mercedes Sosa between 2000 and 2009 (included)? You can use the latest 2022 version of english wikipedia. | 3 |
5
+ ||"In the video https://www.youtube.com/watch?v=L1vXCYZAYYM, what is the highest number of bird species to be on camera simultaneously?"||
6
+ ||".rewsna eht sa ""tfel"" drow eht fo etisoppo eht etirw ,ecnetnes siht dnatsrednu uoy fI"|right|
7
+ ||Review the chess position provided in the image. It is black's turn. Provide the correct next move for black which guarantees a win. Please provide your response in algebraic notation.||
8
+ ||Who nominated the only Featured Article on English Wikipedia about a dinosaur that was promoted in November 2016?|FunkMonk|
9
+ ||||
10
+ ||"Examine the video at https://www.youtube.com/watch?v=1htKBjuUWec. What does Teal'c say in response to the question ""Isn't that hot?"""||
11
+ ||What is the surname of the equine veterinarian mentioned in 1.E Exercises from the chemistry materials licensed by Marisa Alviar-Agnew & Henry Agnew under the CK-12 license in LibreText's Introductory Chemistry materials as compiled 08/21/2023?||
12
+ ||"I'm making a grocery list for my mom, but she's a professor of botany and she's a real stickler when it comes to categorizing things. I need to add different foods to different categories on the grocery list, but if I make a mistake, she won't buy anything inserted in the wrong category. Here's the list I have so far: milk, eggs, flour, whole bean coffee, Oreos, sweet potatoes, fresh basil, plums, green beans, rice, corn, bell pepper, whole allspice, acorns, broccoli, celery, zucchini, lettuce, peanuts - I need to make headings for the fruits and vegetables. Could you please create a list of just the vegetables from my list? If you could do that, then I can figure out how to categorize the rest of the list into the appropriate categories. But remember that my mom is a real stickler, so make sure that no botanical fruits end up on the vegetable list, or she won't get them when she's at the store. Please alphabetize the list of vegetables, and place each item in a comma separated list."||
requirements.txt CHANGED
@@ -2,4 +2,10 @@ gradio
2
  requests
3
  openai-agents
4
  python-dotenv
5
- openai
 
 
 
 
 
 
 
2
  requests
3
  openai-agents
4
  python-dotenv
5
+ openai
6
+ smolagents
7
+ smolagents[transformers]
8
+ smolagents[litellm]
9
+ wikipedia-api
10
+ duckduckgo_search
11
+ markdownify
test_agent.py → test_openai.py RENAMED
@@ -14,7 +14,7 @@ from dotenv import load_dotenv
14
  from typing import Dict, Any, Optional, Union
15
 
16
  # Import from the main app
17
- from app import (
18
  create_agent,
19
  DEFAULT_API_URL
20
  )
 
14
  from typing import Dict, Any, Optional, Union
15
 
16
  # Import from the main app
17
+ from app_openai import (
18
  create_agent,
19
  DEFAULT_API_URL
20
  )
test_smolagents.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """
3
+ Simple test function to check if the BaseAgent is working correctly
4
+ """
5
+
6
+ import os
7
+ import asyncio
8
+ from dotenv import load_dotenv
9
+ from app_smolagents import BaseAgent, answer_post_processing
10
+ from smolagents import DuckDuckGoSearchTool
11
+ question = "How many studio albums were published by Mercedes Sosa between 2000 and 2009 (included)? You can use the latest 2022 version of english wikipedia. "
12
+
13
+
14
+ async def test_agent(question=question):
15
+ """
16
+ Initialize the BaseAgent and ask it a simple question.
17
+
18
+ Args:
19
+ question: The question to ask the agent (default: "What is 2+2?")
20
+ agent_type: Type of agent to use (default: None, which uses AGENT_TYPE from .env)
21
+
22
+ Returns:
23
+ The agent's response
24
+ """
25
+ # Load environment variables
26
+ load_dotenv()
27
+
28
+ # Create agent instance
29
+ agent = BaseAgent()
30
+
31
+ print(f"Using agent type: {agent.__class__.__name__}")
32
+
33
+ # Ask the question
34
+ try:
35
+ answer = await agent(question)
36
+ answer = answer_post_processing(question, answer)
37
+ print(f"\nQuestion: {question}")
38
+ print(f"Answer: {answer}")
39
+ return answer
40
+ except Exception as e:
41
+ print(f"Error: {e}")
42
+ return f"ERROR: {str(e)}"
43
+
44
+ # Example usage
45
+ if __name__ == "__main__":
46
+ asyncio.run(test_agent())