Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -3,6 +3,21 @@ import gradio as gr
|
|
3 |
import requests
|
4 |
import inspect
|
5 |
import pandas as pd
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
# (Keep Constants as is)
|
8 |
# --- Constants ---
|
@@ -10,14 +25,187 @@ 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 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
def run_and_submit_all( profile: gr.OAuthProfile | None):
|
23 |
"""
|
@@ -40,7 +228,7 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
|
|
40 |
|
41 |
# 1. Instantiate Agent ( modify this part to create your agent)
|
42 |
try:
|
43 |
-
agent =
|
44 |
except Exception as e:
|
45 |
print(f"Error instantiating agent: {e}")
|
46 |
return f"Error initializing agent: {e}", None
|
|
|
3 |
import requests
|
4 |
import inspect
|
5 |
import pandas as pd
|
6 |
+
from smolagents import CodeAgent, InferenceClientModel, tool
|
7 |
+
from smolagents import ActionStep, PlanningStep, ToolCall, Tool
|
8 |
+
from smolagents import (
|
9 |
+
CodeAgent,
|
10 |
+
DuckDuckGoSearchTool,
|
11 |
+
VisitWebpageTool,
|
12 |
+
WikipediaSearchTool,
|
13 |
+
OpenAIServerModel,
|
14 |
+
SpeechToTextTool,
|
15 |
+
FinalAnswerTool,
|
16 |
+
)
|
17 |
+
import yaml, importlib, requests, json, os, base64, re
|
18 |
+
import wikipediaapi
|
19 |
+
from typing import List, Dict, Any, Union, Optional
|
20 |
+
from openai import OpenAI
|
21 |
|
22 |
# (Keep Constants as is)
|
23 |
# --- Constants ---
|
|
|
25 |
|
26 |
# --- Basic Agent Definition ---
|
27 |
# ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
|
28 |
+
model = OpenAIServerModel(
|
29 |
+
model_id="gpt-4.1-mini",
|
30 |
+
api_key=userdata.get('OPENAI_API_KEY'),
|
31 |
+
)
|
32 |
+
# PROMPTS
|
33 |
+
system_prompt = """You are a general AI assistant. I will ask you a question.
|
34 |
+
YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
|
35 |
+
If your answer is a number and you are not explicitly asked for a string, write it in numerals instead of words, and don't use comma to write your number nor use units such as $ or percent sign unless specified otherwise.
|
36 |
+
If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise.
|
37 |
+
If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string.
|
38 |
+
|
39 |
+
Answer questions as literally as you can, making as few assumptions as possible. Restrict the answer to the narrowest definition that still satifies the question.
|
40 |
+
If you are provied with a video, please watch and summarize the entire video before answering the question. The correct answer may be present only in a few frames of the video.
|
41 |
+
If you are asked to prove something, first state your assumptions and think step by step before giving your final answer.
|
42 |
+
"""
|
43 |
+
req_instruction = (
|
44 |
+
"You are a highly capable and autonomous agent named {{name}}, designed to solve complex tasks efficiently.\n"
|
45 |
+
"A valued client has assigned you the following task:\n"
|
46 |
+
"---\n"
|
47 |
+
"Task:\n"
|
48 |
+
"{{task}}\n"
|
49 |
+
"---\n"
|
50 |
+
"To complete this task successfully, follow these steps carefully:\n"
|
51 |
+
" 1. Comprehend the task and identify the intended goal.\n"
|
52 |
+
" 2. Break the task into clear, logical steps.\n"
|
53 |
+
" 3. Select and prepare the tools or resources you need.\n"
|
54 |
+
" - If a tool does not return useful results on the first attempt, consider retrying it with a simpler, more general, or slightly modified input.\n"
|
55 |
+
" Avoid switching to a different tool too quickly unless clearly necessary.\n"
|
56 |
+
" 4. Set up the required environment or context.\n"
|
57 |
+
" 5. Execute each step methodically.\n"
|
58 |
+
" 6. Monitor outcomes and identify any deviations.\n"
|
59 |
+
" 7. Revise your plan if necessary based on feedback.\n"
|
60 |
+
" 8. Maintain internal state and track progress.\n"
|
61 |
+
" 9. Verify that the goal has been fully achieved.\n"
|
62 |
+
" 10. Present the final result clearly and concisely.\n"
|
63 |
+
"If you succeed, you will be rewarded with a significant bonus.\n\n"
|
64 |
+
"Your final_answer MUST be:\n"
|
65 |
+
"- a number (retain its original type; do not include units),\n"
|
66 |
+
"- a concise phrase,\n"
|
67 |
+
"- or a comma-separated list of numbers or strings, with a space after each comma (e.g., \"1, 2, 3\", not \"1,2,3\"; do not include articles or abbreviations).\n\n"
|
68 |
+
"Only the content passed to the final_answer tool will be preserved. Any other content will be discarded."
|
69 |
+
)
|
70 |
+
|
71 |
+
prompts = yaml.safe_load(
|
72 |
+
importlib.resources.files("smolagents.prompts").joinpath("code_agent.yaml").read_text()
|
73 |
+
)
|
74 |
+
prompts['managed_agent']['task'] = req_instruction
|
75 |
+
prompts['managed_agent']['report'] = "{{final_answer}}"
|
76 |
+
|
77 |
+
# Tools
|
78 |
+
@tool
|
79 |
+
def wikipedia_df_tool(query: str) -> List[pd.DataFrame]:
|
80 |
+
"""
|
81 |
+
Use this tool first for Wikipedia searches, before switching to text-based tools, and retry this tool if no results are found.
|
82 |
+
|
83 |
+
Retrieve useful tabular data from English Wikipedia.
|
84 |
+
|
85 |
+
This tool searches for HTML tables on the Wikipedia page matching the given query,
|
86 |
+
and returns them as a list of Pandas DataFrames. It always returns a list — if no tables
|
87 |
+
are found, the list will be empty.
|
88 |
+
|
89 |
+
If no results are found, retry this tool with a more general, simpler, or alternative version of the query.
|
90 |
+
Examples of simplifications: removing terms like 'discography', using only the person's name, or trying keywords like 'albums', 'list', or 'table'.
|
91 |
+
|
92 |
+
|
93 |
+
Args:
|
94 |
+
query: A Wikipedia page title or related phrase (e.g., "Argentina", "Mercedes Sosa discography").
|
95 |
+
"""
|
96 |
+
wiki = wikipediaapi.Wikipedia(user_agent='MyProjectName ([email protected])', language='en')
|
97 |
+
wiki_page = wiki.page(query)
|
98 |
+
try:
|
99 |
+
url = wiki_page.fullurl
|
100 |
+
except Exception:
|
101 |
+
return []
|
102 |
+
dfs = pd.read_html(url)
|
103 |
+
return dfs if dfs else []
|
104 |
+
|
105 |
+
@tool
|
106 |
+
def get_file_from_task(task_id: str, file_name: str) -> str:
|
107 |
+
"""
|
108 |
+
Use this tool to download the file content associated with the given task_id if exists.
|
109 |
+
Returns absolute file path.
|
110 |
+
Args:
|
111 |
+
task_id: The unique identifier of the task whose associated file should be downloaded.
|
112 |
+
This is used to locate the file on the server via the API endpoint.
|
113 |
+
file_name: The desired name (or path) to save the downloaded file locally.
|
114 |
+
This will be the name of the file written to disk.
|
115 |
+
Returns:
|
116 |
+
The absolute path to the downloaded file saved on the local filesystem.
|
117 |
+
"""
|
118 |
+
response = requests.get(f"{DEFAULT_API_URL}/files/{task_id}", timeout=15)
|
119 |
+
response.raise_for_status()
|
120 |
+
with open(file_name, 'wb') as file:
|
121 |
+
file.write(response.content)
|
122 |
+
return os.path.abspath(file_name)
|
123 |
+
|
124 |
+
@tool
|
125 |
+
def load_text_file(file_path: str) -> str:
|
126 |
+
"""
|
127 |
+
Reads and returns the content of a UTF-8 encoded text file.
|
128 |
+
|
129 |
+
Args:
|
130 |
+
file_path (str): Path to the file to be read.
|
131 |
+
|
132 |
+
Returns:
|
133 |
+
str: The content of the file as a string.
|
134 |
+
"""
|
135 |
+
with open(file_path, 'r', encoding='utf-8') as file:
|
136 |
+
return file.read()
|
137 |
+
|
138 |
+
|
139 |
+
|
140 |
+
@tool
|
141 |
+
def analyze_image(image_path: str, task: str) -> str:
|
142 |
+
"""
|
143 |
+
Analyzes the image at the given path using OpenAI's vision model,
|
144 |
+
based on the provided task description.
|
145 |
+
|
146 |
+
Args:
|
147 |
+
image_path (str): Path to the image file.
|
148 |
+
task (str): Task to perform on the image (e.g., describe, interpret, extract data).
|
149 |
+
|
150 |
+
Returns:
|
151 |
+
str: Result of the analysis as a string.
|
152 |
+
"""
|
153 |
+
client = OpenAI(api_key=userdata.get('OPENAI_API_KEY'))
|
154 |
+
|
155 |
+
with open(image_path, "rb") as f:
|
156 |
+
encoded_image = base64.b64encode(f.read()).decode("utf-8")
|
157 |
+
|
158 |
+
|
159 |
+
|
160 |
+
prompt = (
|
161 |
+
"You are an expert image analysis tool. Please examine the following image and perform the task:\n\n"
|
162 |
+
f"{task}"
|
163 |
+
)
|
164 |
+
|
165 |
+
response = client.responses.create(
|
166 |
+
model="gpt-4.1-mini",
|
167 |
+
input=[
|
168 |
+
{"role": "user", "content": [
|
169 |
+
{"type": "input_text", "text": prompt},
|
170 |
+
{"type": "input_image", "image_url": f"data:image/jpeg;base64,{encoded_image}"}
|
171 |
+
]}
|
172 |
+
]
|
173 |
+
)
|
174 |
+
|
175 |
+
return response.output_text
|
176 |
+
|
177 |
+
def summarize_steps(agent):
|
178 |
+
summary = []
|
179 |
+
for step in agent.memory.steps:
|
180 |
+
if isinstance(step, ActionStep):
|
181 |
+
args = step.tool_calls[0].arguments.strip().replace('\n', ' ')
|
182 |
+
summary.append({'Step': step.step_number, 'Summary': args})
|
183 |
+
return summary
|
184 |
+
|
185 |
+
mp3_to_text_tool = Tool.from_space(
|
186 |
+
"mrfakename/fast-whisper-turbo",
|
187 |
+
name="voice_to_text",
|
188 |
+
description="Transcribes an English audio file into text. Returns the transcribed text.",
|
189 |
+
api_name="/transcribe"
|
190 |
+
)
|
191 |
+
|
192 |
+
agent = CodeAgent(
|
193 |
+
tools=[
|
194 |
+
DuckDuckGoSearchTool(),
|
195 |
+
VisitWebpageTool(),
|
196 |
+
WikipediaSearchTool(),
|
197 |
+
mp3_to_text_tool,
|
198 |
+
FinalAnswerTool(),
|
199 |
+
wikipedia_df_tool,
|
200 |
+
get_file_from_task,
|
201 |
+
load_text_file,
|
202 |
+
analyze_image,
|
203 |
+
],
|
204 |
+
model=model,
|
205 |
+
prompt_templates=prompts,
|
206 |
+
additional_authorized_imports = ["pandas", "requests", "BeautifulSoap"],
|
207 |
+
name="tikito",
|
208 |
+
)
|
209 |
|
210 |
def run_and_submit_all( profile: gr.OAuthProfile | None):
|
211 |
"""
|
|
|
228 |
|
229 |
# 1. Instantiate Agent ( modify this part to create your agent)
|
230 |
try:
|
231 |
+
agent = agent
|
232 |
except Exception as e:
|
233 |
print(f"Error instantiating agent: {e}")
|
234 |
return f"Error initializing agent: {e}", None
|