Spaces:
Sleeping
Sleeping
Mikkel Skovdal commited on
Commit ·
f0eb1da
1
Parent(s): 7d72891
audio and image support
Browse files- .DS_Store +0 -0
- .gitignore +1 -1
- app.py +14 -29
- requirements.txt +4 -1
- src/.DS_Store +0 -0
- src/__pycache__/agent.cpython-310.pyc +0 -0
- src/__pycache__/api_client.cpython-310.pyc +0 -0
- src/__pycache__/tools.cpython-310.pyc +0 -0
- src/agent.py +78 -68
- src/api_client.py +30 -9
- src/temp/.DS_Store +0 -0
- src/tools.py +43 -3
- test.json +6 -0
.DS_Store
CHANGED
|
Binary files a/.DS_Store and b/.DS_Store differ
|
|
|
.gitignore
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
secret
|
| 2 |
test.ipynb
|
| 3 |
.env
|
| 4 |
-
error.txt
|
| 5 |
log.txt
|
|
|
|
|
|
| 1 |
secret
|
| 2 |
test.ipynb
|
| 3 |
.env
|
|
|
|
| 4 |
log.txt
|
| 5 |
+
src/temp/files/
|
app.py
CHANGED
|
@@ -12,25 +12,6 @@ from src.api_client import ApiClient
|
|
| 12 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
| 13 |
|
| 14 |
|
| 15 |
-
def save_file(file_content, task_id):
|
| 16 |
-
"""
|
| 17 |
-
Save a task file to a temporary location
|
| 18 |
-
"""
|
| 19 |
-
if not file_content:
|
| 20 |
-
return None
|
| 21 |
-
|
| 22 |
-
# Create a temporary file
|
| 23 |
-
temp_dir = tempfile.gettempdir()
|
| 24 |
-
file_path = os.path.join(temp_dir, f"task_{task_id}.txt")
|
| 25 |
-
|
| 26 |
-
# Write content to the file
|
| 27 |
-
with open(file_path, "wb") as f:
|
| 28 |
-
f.write(file_content)
|
| 29 |
-
|
| 30 |
-
print(f"File saved to {file_path}")
|
| 31 |
-
return file_path
|
| 32 |
-
|
| 33 |
-
|
| 34 |
def run_and_submit_all(profile: gr.OAuthProfile | None):
|
| 35 |
"""
|
| 36 |
Fetches all questions, runs the CustomAgent on them, submits all answers,
|
|
@@ -49,7 +30,6 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
|
|
| 49 |
# 1. Instantiate Agent ( modify this part to create your agent)
|
| 50 |
agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
|
| 51 |
print(agent_code)
|
| 52 |
-
# Initialize Agent with configuration
|
| 53 |
try:
|
| 54 |
agent_config = get_config()
|
| 55 |
print(f"Using agent configuration: {agent_config}")
|
|
@@ -83,6 +63,9 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
|
|
| 83 |
for item in questions_data:
|
| 84 |
task_id = item.get("task_id")
|
| 85 |
question_text = item.get("question")
|
|
|
|
|
|
|
|
|
|
| 86 |
if not task_id or question_text is None:
|
| 87 |
print(f"Skipping item with missing task_id or question: {item}")
|
| 88 |
continue
|
|
@@ -95,13 +78,11 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
|
|
| 95 |
)
|
| 96 |
|
| 97 |
# Check if the question has an associated file
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
except Exception as file_e:
|
| 104 |
-
print(f"No file for task {task_id}")
|
| 105 |
|
| 106 |
# Run the agent to get the answer
|
| 107 |
submitted_answer = agent.forward(question_text, file_path)
|
|
@@ -134,7 +115,8 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
|
|
| 134 |
}
|
| 135 |
)
|
| 136 |
finally:
|
| 137 |
-
|
|
|
|
| 138 |
|
| 139 |
# Print summary
|
| 140 |
print(f"\nProcessing complete: {completed} questions processed, {failed} failures")
|
|
@@ -143,12 +125,15 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
|
|
| 143 |
return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
|
| 144 |
|
| 145 |
# Store results in a log file
|
| 146 |
-
log_file_path = "
|
| 147 |
os.makedirs(os.path.dirname(log_file_path), exist_ok=True)
|
| 148 |
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
| 149 |
with open(log_file_path, "a") as log_file:
|
| 150 |
for entry in results_log:
|
| 151 |
log_file.write(f"{timestamp} - {entry}\n")
|
|
|
|
|
|
|
|
|
|
| 152 |
|
| 153 |
# 4. Prepare Submission
|
| 154 |
print(f"Submitting {len(answers_payload)} answers for username '{username}'...")
|
|
|
|
| 12 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
| 13 |
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
def run_and_submit_all(profile: gr.OAuthProfile | None):
|
| 16 |
"""
|
| 17 |
Fetches all questions, runs the CustomAgent on them, submits all answers,
|
|
|
|
| 30 |
# 1. Instantiate Agent ( modify this part to create your agent)
|
| 31 |
agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
|
| 32 |
print(agent_code)
|
|
|
|
| 33 |
try:
|
| 34 |
agent_config = get_config()
|
| 35 |
print(f"Using agent configuration: {agent_config}")
|
|
|
|
| 63 |
for item in questions_data:
|
| 64 |
task_id = item.get("task_id")
|
| 65 |
question_text = item.get("question")
|
| 66 |
+
file_name = item.get("file_name")
|
| 67 |
+
file_path = None
|
| 68 |
+
|
| 69 |
if not task_id or question_text is None:
|
| 70 |
print(f"Skipping item with missing task_id or question: {item}")
|
| 71 |
continue
|
|
|
|
| 78 |
)
|
| 79 |
|
| 80 |
# Check if the question has an associated file
|
| 81 |
+
if file_name:
|
| 82 |
+
try:
|
| 83 |
+
file_path = api_client.get_file(task_id=task_id, file_name=file_name)
|
| 84 |
+
except Exception as file_e:
|
| 85 |
+
print(f"Failed to download the file for task {task_id} - {file_e}")
|
|
|
|
|
|
|
| 86 |
|
| 87 |
# Run the agent to get the answer
|
| 88 |
submitted_answer = agent.forward(question_text, file_path)
|
|
|
|
| 115 |
}
|
| 116 |
)
|
| 117 |
finally:
|
| 118 |
+
if completed+failed < total_questions:
|
| 119 |
+
time.sleep(55)
|
| 120 |
|
| 121 |
# Print summary
|
| 122 |
print(f"\nProcessing complete: {completed} questions processed, {failed} failures")
|
|
|
|
| 125 |
return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
|
| 126 |
|
| 127 |
# Store results in a log file
|
| 128 |
+
log_file_path = "src/temp/log.txt"
|
| 129 |
os.makedirs(os.path.dirname(log_file_path), exist_ok=True)
|
| 130 |
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
| 131 |
with open(log_file_path, "a") as log_file:
|
| 132 |
for entry in results_log:
|
| 133 |
log_file.write(f"{timestamp} - {entry}\n")
|
| 134 |
+
log_file.write(
|
| 135 |
+
f"{timestamp} - Summary: {completed} questions processed, {failed} failures\n\n"
|
| 136 |
+
)
|
| 137 |
|
| 138 |
# 4. Prepare Submission
|
| 139 |
print(f"Submitting {len(answers_payload)} answers for username '{username}'...")
|
requirements.txt
CHANGED
|
@@ -2,4 +2,7 @@ gradio
|
|
| 2 |
requests
|
| 3 |
smolagents
|
| 4 |
smolagents[litellm]
|
| 5 |
-
ratelimiter
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
requests
|
| 3 |
smolagents
|
| 4 |
smolagents[litellm]
|
| 5 |
+
ratelimiter
|
| 6 |
+
youtube-transcript-api
|
| 7 |
+
SpeechRecognition
|
| 8 |
+
pydub
|
src/.DS_Store
CHANGED
|
Binary files a/src/.DS_Store and b/src/.DS_Store differ
|
|
|
src/__pycache__/agent.cpython-310.pyc
CHANGED
|
Binary files a/src/__pycache__/agent.cpython-310.pyc and b/src/__pycache__/agent.cpython-310.pyc differ
|
|
|
src/__pycache__/api_client.cpython-310.pyc
CHANGED
|
Binary files a/src/__pycache__/api_client.cpython-310.pyc and b/src/__pycache__/api_client.cpython-310.pyc differ
|
|
|
src/__pycache__/tools.cpython-310.pyc
ADDED
|
Binary file (1.1 kB). View file
|
|
|
src/agent.py
CHANGED
|
@@ -1,15 +1,23 @@
|
|
| 1 |
-
from smolagents import
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
import os
|
| 4 |
-
import
|
| 5 |
-
from typing import List, Optional
|
| 6 |
from dotenv import load_dotenv
|
| 7 |
|
| 8 |
-
load_dotenv()
|
| 9 |
-
|
| 10 |
|
|
|
|
| 11 |
SYSTEM_PROMPT = """
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
| 13 |
"""
|
| 14 |
|
| 15 |
|
|
@@ -30,28 +38,41 @@ class CustomAgent:
|
|
| 30 |
"""
|
| 31 |
self.logging = logging
|
| 32 |
self.verbose = verbose
|
| 33 |
-
self.imports = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
if additional_imports:
|
| 35 |
self.imports.extend(additional_imports)
|
| 36 |
|
| 37 |
-
|
| 38 |
self.tools = [
|
| 39 |
DuckDuckGoSearchTool(),
|
| 40 |
PythonInterpreterTool(),
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
# analyze_csv_file,
|
| 44 |
-
# analyze_excel_file
|
| 45 |
]
|
| 46 |
|
| 47 |
# Initialize the model
|
| 48 |
model = LiteLLMModel(
|
| 49 |
-
model_id=model_id,
|
| 50 |
api_key=os.getenv("GEMINI_API_KEY"),
|
| 51 |
timeout=timeout,
|
| 52 |
)
|
| 53 |
|
| 54 |
-
# Initialize the CodeAgent
|
| 55 |
self.agent = CodeAgent(
|
| 56 |
model=model,
|
| 57 |
tools=self.tools,
|
|
@@ -64,14 +85,10 @@ class CustomAgent:
|
|
| 64 |
print("CustomAgent initialized.")
|
| 65 |
|
| 66 |
def __call__(self, question: str) -> str:
|
| 67 |
-
|
| 68 |
-
print(f"Agent received question (first 50 chars): {question[:50]}...")
|
| 69 |
try:
|
| 70 |
full_prompt = f"""{question}
|
| 71 |
-
|
| 72 |
-
Do not include explanations, steps, reasoning, or additional text.
|
| 73 |
-
Be direct and specific. GAIA benchmark requires exact matching answers.
|
| 74 |
-
For example, if asked "What is the capital of France?", respond simply with "Paris".
|
| 75 |
"""
|
| 76 |
answer = self.agent.run(full_prompt)
|
| 77 |
answer = self._clean_answer(answer)
|
|
@@ -82,39 +99,34 @@ class CustomAgent:
|
|
| 82 |
if self.verbose:
|
| 83 |
print(error_msg)
|
| 84 |
return error_msg
|
| 85 |
-
|
| 86 |
def forward(self, question: str, file_path) -> str:
|
| 87 |
-
|
| 88 |
-
print(f"Agent received question (first 50 chars): {question[:50]}...")
|
| 89 |
try:
|
| 90 |
-
|
| 91 |
-
|
|
|
|
| 92 |
if file_path:
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
Do not include explanations, steps, reasoning, or additional text.
|
| 114 |
-
Be direct and specific. GAIA benchmark requires exact matching answers.
|
| 115 |
-
For example, if asked "What is the capital of France?", respond simply with "Paris".
|
| 116 |
-
"""
|
| 117 |
-
answer = self.agent.run(full_prompt)
|
| 118 |
answer = self._clean_answer(answer)
|
| 119 |
return answer
|
| 120 |
|
|
@@ -123,27 +135,24 @@ class CustomAgent:
|
|
| 123 |
if self.verbose:
|
| 124 |
print(error_msg)
|
| 125 |
return error_msg
|
| 126 |
-
|
| 127 |
def _clean_answer(self, answer: any) -> str:
|
| 128 |
"""
|
| 129 |
Clean up the answer to remove common prefixes and formatting
|
| 130 |
that models often add but that can cause exact match failures.
|
| 131 |
-
|
| 132 |
Args:
|
| 133 |
answer: The raw answer from the model
|
| 134 |
-
|
| 135 |
Returns:
|
| 136 |
The cleaned answer as a string
|
| 137 |
"""
|
| 138 |
# Convert non-string types to strings
|
| 139 |
if not isinstance(answer, str):
|
| 140 |
-
# Handle numeric types (float, int)
|
| 141 |
if isinstance(answer, float):
|
| 142 |
-
# Format floating point numbers properly
|
| 143 |
if answer.is_integer():
|
| 144 |
formatted_answer = str(int(answer))
|
| 145 |
else:
|
| 146 |
-
# For currency values that might need formatting
|
| 147 |
if abs(answer) >= 1000:
|
| 148 |
formatted_answer = f"${answer:,.2f}"
|
| 149 |
else:
|
|
@@ -153,13 +162,13 @@ class CustomAgent:
|
|
| 153 |
return str(answer)
|
| 154 |
else:
|
| 155 |
return str(answer)
|
| 156 |
-
|
| 157 |
# Normalize whitespace
|
| 158 |
answer = answer.strip()
|
| 159 |
-
|
| 160 |
# Remove common prefixes and formatting that models add
|
| 161 |
prefixes_to_remove = [
|
| 162 |
-
"The answer is ",
|
| 163 |
"Answer: ",
|
| 164 |
"Final answer: ",
|
| 165 |
"The result is ",
|
|
@@ -169,12 +178,14 @@ class CustomAgent:
|
|
| 169 |
]
|
| 170 |
for prefix in prefixes_to_remove:
|
| 171 |
if answer.startswith(prefix):
|
| 172 |
-
answer = answer[len(prefix):].strip()
|
| 173 |
-
|
| 174 |
# Remove quotes if they wrap the entire answer
|
| 175 |
-
if (answer.startswith('"') and answer.endswith('"')) or (
|
|
|
|
|
|
|
| 176 |
answer = answer[1:-1].strip()
|
| 177 |
-
|
| 178 |
return answer
|
| 179 |
|
| 180 |
|
|
@@ -184,13 +195,12 @@ def get_config():
|
|
| 184 |
"""
|
| 185 |
# Default configuration
|
| 186 |
config = {
|
| 187 |
-
"model_id": "
|
| 188 |
"logging": False,
|
| 189 |
"max_steps": 5,
|
| 190 |
"verbose": False,
|
| 191 |
"executor_type": "local",
|
| 192 |
-
"timeout": 120
|
| 193 |
-
"sleep" : 60,
|
| 194 |
}
|
| 195 |
-
|
| 196 |
return config
|
|
|
|
| 1 |
+
from smolagents import (
|
| 2 |
+
CodeAgent,
|
| 3 |
+
LiteLLMModel,
|
| 4 |
+
DuckDuckGoSearchTool,
|
| 5 |
+
PythonInterpreterTool,
|
| 6 |
+
VisitWebpageTool,
|
| 7 |
+
)
|
| 8 |
+
from src.tools import extract_text_from_youtube
|
| 9 |
+
from PIL import Image
|
| 10 |
import os
|
| 11 |
+
from typing import List
|
|
|
|
| 12 |
from dotenv import load_dotenv
|
| 13 |
|
|
|
|
|
|
|
| 14 |
|
| 15 |
+
load_dotenv()
|
| 16 |
SYSTEM_PROMPT = """
|
| 17 |
+
When answering, provide ONLY the precise answer requested.
|
| 18 |
+
Do not include explanations, steps, reasoning, or additional text.
|
| 19 |
+
Be direct and specific. GAIA benchmark requires exact matching answers.
|
| 20 |
+
For example, if asked "What is the capital of France?", respond simply with "Paris".
|
| 21 |
"""
|
| 22 |
|
| 23 |
|
|
|
|
| 38 |
"""
|
| 39 |
self.logging = logging
|
| 40 |
self.verbose = verbose
|
| 41 |
+
self.imports = [
|
| 42 |
+
"pandas",
|
| 43 |
+
"numpy",
|
| 44 |
+
"io",
|
| 45 |
+
"datetime",
|
| 46 |
+
"json",
|
| 47 |
+
"re",
|
| 48 |
+
"math",
|
| 49 |
+
"os",
|
| 50 |
+
"requests",
|
| 51 |
+
"csv",
|
| 52 |
+
"urllib",
|
| 53 |
+
"youtube-transcript-api",
|
| 54 |
+
"SpeechRecognition",
|
| 55 |
+
"pydub",
|
| 56 |
+
]
|
| 57 |
if additional_imports:
|
| 58 |
self.imports.extend(additional_imports)
|
| 59 |
|
| 60 |
+
# Initialize tools
|
| 61 |
self.tools = [
|
| 62 |
DuckDuckGoSearchTool(),
|
| 63 |
PythonInterpreterTool(),
|
| 64 |
+
VisitWebpageTool(),
|
| 65 |
+
extract_text_from_youtube,
|
|
|
|
|
|
|
| 66 |
]
|
| 67 |
|
| 68 |
# Initialize the model
|
| 69 |
model = LiteLLMModel(
|
| 70 |
+
model_id=model_id,
|
| 71 |
api_key=os.getenv("GEMINI_API_KEY"),
|
| 72 |
timeout=timeout,
|
| 73 |
)
|
| 74 |
|
| 75 |
+
# Initialize the CodeAgent
|
| 76 |
self.agent = CodeAgent(
|
| 77 |
model=model,
|
| 78 |
tools=self.tools,
|
|
|
|
| 85 |
print("CustomAgent initialized.")
|
| 86 |
|
| 87 |
def __call__(self, question: str) -> str:
|
| 88 |
+
print(f"Agent received question (first 50 chars): {question[:50]}...")
|
|
|
|
| 89 |
try:
|
| 90 |
full_prompt = f"""{question}
|
| 91 |
+
{SYSTEM_PROMPT}
|
|
|
|
|
|
|
|
|
|
| 92 |
"""
|
| 93 |
answer = self.agent.run(full_prompt)
|
| 94 |
answer = self._clean_answer(answer)
|
|
|
|
| 99 |
if self.verbose:
|
| 100 |
print(error_msg)
|
| 101 |
return error_msg
|
| 102 |
+
|
| 103 |
def forward(self, question: str, file_path) -> str:
|
| 104 |
+
print(f"Agent received question (first 50 chars): {question[:50]}...")
|
|
|
|
| 105 |
try:
|
| 106 |
+
full_prompt = f"""Question: {question}
|
| 107 |
+
|
| 108 |
+
{SYSTEM_PROMPT}"""
|
| 109 |
if file_path:
|
| 110 |
+
file_path_ext = os.path.splitext(file_path)[1]
|
| 111 |
+
if file_path_ext.lower() in [".jpg", ".jpeg", ".png"]:
|
| 112 |
+
image = Image.open(file_path).convert("RGB")
|
| 113 |
+
answer = self.agent.run(full_prompt, images=[image])
|
| 114 |
+
elif file_path_ext.lower() in [".txt", ".py"]:
|
| 115 |
+
with open(file_path, "r") as f:
|
| 116 |
+
content = f.read()
|
| 117 |
+
full_prompt = f"""Question: {question}
|
| 118 |
+
File content: ```{content}```
|
| 119 |
+
|
| 120 |
+
{SYSTEM_PROMPT}"""
|
| 121 |
+
answer = self.agent.run(full_prompt)
|
| 122 |
+
else:
|
| 123 |
+
full_prompt = f"""Question: {question}
|
| 124 |
+
File path: {file_path}
|
| 125 |
+
|
| 126 |
+
{SYSTEM_PROMPT}"""
|
| 127 |
+
answer = self.agent.run(full_prompt)
|
| 128 |
+
else:
|
| 129 |
+
answer = self.agent.run(full_prompt)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
answer = self._clean_answer(answer)
|
| 131 |
return answer
|
| 132 |
|
|
|
|
| 135 |
if self.verbose:
|
| 136 |
print(error_msg)
|
| 137 |
return error_msg
|
| 138 |
+
|
| 139 |
def _clean_answer(self, answer: any) -> str:
|
| 140 |
"""
|
| 141 |
Clean up the answer to remove common prefixes and formatting
|
| 142 |
that models often add but that can cause exact match failures.
|
| 143 |
+
|
| 144 |
Args:
|
| 145 |
answer: The raw answer from the model
|
| 146 |
+
|
| 147 |
Returns:
|
| 148 |
The cleaned answer as a string
|
| 149 |
"""
|
| 150 |
# Convert non-string types to strings
|
| 151 |
if not isinstance(answer, str):
|
|
|
|
| 152 |
if isinstance(answer, float):
|
|
|
|
| 153 |
if answer.is_integer():
|
| 154 |
formatted_answer = str(int(answer))
|
| 155 |
else:
|
|
|
|
| 156 |
if abs(answer) >= 1000:
|
| 157 |
formatted_answer = f"${answer:,.2f}"
|
| 158 |
else:
|
|
|
|
| 162 |
return str(answer)
|
| 163 |
else:
|
| 164 |
return str(answer)
|
| 165 |
+
|
| 166 |
# Normalize whitespace
|
| 167 |
answer = answer.strip()
|
| 168 |
+
|
| 169 |
# Remove common prefixes and formatting that models add
|
| 170 |
prefixes_to_remove = [
|
| 171 |
+
"The answer is ",
|
| 172 |
"Answer: ",
|
| 173 |
"Final answer: ",
|
| 174 |
"The result is ",
|
|
|
|
| 178 |
]
|
| 179 |
for prefix in prefixes_to_remove:
|
| 180 |
if answer.startswith(prefix):
|
| 181 |
+
answer = answer[len(prefix) :].strip()
|
| 182 |
+
|
| 183 |
# Remove quotes if they wrap the entire answer
|
| 184 |
+
if (answer.startswith('"') and answer.endswith('"')) or (
|
| 185 |
+
answer.startswith("'") and answer.endswith("'")
|
| 186 |
+
):
|
| 187 |
answer = answer[1:-1].strip()
|
| 188 |
+
|
| 189 |
return answer
|
| 190 |
|
| 191 |
|
|
|
|
| 195 |
"""
|
| 196 |
# Default configuration
|
| 197 |
config = {
|
| 198 |
+
"model_id": "gemini/gemini-2.5-flash-preview-04-17",
|
| 199 |
"logging": False,
|
| 200 |
"max_steps": 5,
|
| 201 |
"verbose": False,
|
| 202 |
"executor_type": "local",
|
| 203 |
+
"timeout": 120,
|
|
|
|
| 204 |
}
|
| 205 |
+
|
| 206 |
return config
|
src/api_client.py
CHANGED
|
@@ -3,35 +3,56 @@ import os
|
|
| 3 |
import datetime
|
| 4 |
from typing import List, Dict, Any
|
| 5 |
|
|
|
|
| 6 |
class ApiClient:
|
| 7 |
def __init__(self, api_url="https://agents-course-unit4-scoring.hf.space"):
|
| 8 |
self.api_url = api_url
|
| 9 |
self.questions_url = f"{api_url}/questions"
|
| 10 |
self.submit_url = f"{api_url}/submit"
|
| 11 |
self.files_url = f"{api_url}/files"
|
| 12 |
-
|
| 13 |
def get_questions(self, limit=20) -> List[Dict[str, Any]]:
|
| 14 |
limit = min(limit, 20)
|
| 15 |
limit = max(limit, 1)
|
| 16 |
response = requests.get(self.questions_url)
|
| 17 |
response.raise_for_status()
|
| 18 |
return response.json()[:limit]
|
| 19 |
-
|
| 20 |
def get_random_question(self) -> Dict[str, Any]:
|
| 21 |
response = requests.get(f"{self.api_url}/random-question")
|
| 22 |
response.raise_for_status()
|
| 23 |
return response.json()
|
| 24 |
-
|
| 25 |
-
def get_file(self, task_id: str) -> bytes:
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
response.raise_for_status()
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
data = {
|
| 32 |
"username": username,
|
| 33 |
"agent_code": agent_code,
|
| 34 |
-
"answers": answers_payload
|
| 35 |
}
|
| 36 |
response = requests.post(self.submit_url, json=data)
|
| 37 |
response.raise_for_status()
|
|
|
|
| 3 |
import datetime
|
| 4 |
from typing import List, Dict, Any
|
| 5 |
|
| 6 |
+
|
| 7 |
class ApiClient:
|
| 8 |
def __init__(self, api_url="https://agents-course-unit4-scoring.hf.space"):
|
| 9 |
self.api_url = api_url
|
| 10 |
self.questions_url = f"{api_url}/questions"
|
| 11 |
self.submit_url = f"{api_url}/submit"
|
| 12 |
self.files_url = f"{api_url}/files"
|
| 13 |
+
|
| 14 |
def get_questions(self, limit=20) -> List[Dict[str, Any]]:
|
| 15 |
limit = min(limit, 20)
|
| 16 |
limit = max(limit, 1)
|
| 17 |
response = requests.get(self.questions_url)
|
| 18 |
response.raise_for_status()
|
| 19 |
return response.json()[:limit]
|
| 20 |
+
|
| 21 |
def get_random_question(self) -> Dict[str, Any]:
|
| 22 |
response = requests.get(f"{self.api_url}/random-question")
|
| 23 |
response.raise_for_status()
|
| 24 |
return response.json()
|
| 25 |
+
|
| 26 |
+
def get_file(self, task_id, file_name: str) -> bytes:
|
| 27 |
+
# check if file already exists
|
| 28 |
+
file_path = os.path.join("src/temp/files", file_name)
|
| 29 |
+
if os.path.exists(file_path):
|
| 30 |
+
return file_path
|
| 31 |
+
|
| 32 |
+
# Download the file
|
| 33 |
+
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
| 34 |
+
response = requests.get(f"{self.files_url}/{task_id}", stream=True)
|
| 35 |
response.raise_for_status()
|
| 36 |
+
|
| 37 |
+
# Save the file
|
| 38 |
+
with open(file_path, "wb") as f:
|
| 39 |
+
for chunk in response.iter_content(chunk_size=8192):
|
| 40 |
+
f.write(chunk)
|
| 41 |
+
print(f"File saved to {file_path}")
|
| 42 |
+
|
| 43 |
+
return file_path
|
| 44 |
+
|
| 45 |
+
def submit_answers(
|
| 46 |
+
self,
|
| 47 |
+
username: str,
|
| 48 |
+
agent_code: str,
|
| 49 |
+
answers_payload: List[Dict[str, Any]],
|
| 50 |
+
logging: bool,
|
| 51 |
+
) -> Dict[str, Any]:
|
| 52 |
data = {
|
| 53 |
"username": username,
|
| 54 |
"agent_code": agent_code,
|
| 55 |
+
"answers": answers_payload,
|
| 56 |
}
|
| 57 |
response = requests.post(self.submit_url, json=data)
|
| 58 |
response.raise_for_status()
|
src/temp/.DS_Store
ADDED
|
Binary file (6.15 kB). View file
|
|
|
src/tools.py
CHANGED
|
@@ -2,8 +2,48 @@ from smolagents import tool
|
|
| 2 |
|
| 3 |
|
| 4 |
@tool
|
| 5 |
-
def
|
| 6 |
"""
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
"""
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
|
| 4 |
@tool
|
| 5 |
+
def extract_text_from_mp3(mp3_file_path: str) -> str:
|
| 6 |
"""
|
| 7 |
+
Extract text from an mp3 audio file.
|
| 8 |
+
|
| 9 |
+
Args:
|
| 10 |
+
mp3_file_path (str): Path to the mp3 file.
|
| 11 |
+
Returns:
|
| 12 |
+
str: The text extracted from the mp3 file.
|
| 13 |
+
"""
|
| 14 |
+
try:
|
| 15 |
+
import speech_recognition as sr
|
| 16 |
+
from pydub import AudioSegment
|
| 17 |
+
|
| 18 |
+
audio = AudioSegment.from_mp3(mp3_file_path)
|
| 19 |
+
wav_file = f"{mp3_file_path}.wav"
|
| 20 |
+
audio.export(wav_file, format="wav")
|
| 21 |
+
recognizer = sr.Recognizer()
|
| 22 |
+
|
| 23 |
+
with sr.AudioFile(wav_file) as source:
|
| 24 |
+
audio_data = recognizer.record(source)
|
| 25 |
+
text = recognizer.recognize_google(audio_data)
|
| 26 |
+
return text
|
| 27 |
+
except Exception as e:
|
| 28 |
+
return f"Could not extract text from mp3 file: {e}"
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
@tool
|
| 32 |
+
def extract_text_from_youtube(youtube_id: str) -> str:
|
| 33 |
"""
|
| 34 |
+
Extract text from a youtube video.
|
| 35 |
+
|
| 36 |
+
Args:
|
| 37 |
+
youtube_id (str): ID of the youtube video. Not the full URL. Example: "dQw4w9WgXcQ"
|
| 38 |
+
Returns:
|
| 39 |
+
str: The text extracted from the youtube video.
|
| 40 |
+
"""
|
| 41 |
+
try:
|
| 42 |
+
from youtube_transcript_api import YouTubeTranscriptApi
|
| 43 |
+
|
| 44 |
+
ytt_api = YouTubeTranscriptApi()
|
| 45 |
+
fetched_transcript = ytt_api.fetch(youtube_id)
|
| 46 |
+
plaintext = " ".join(snippet.text for snippet in fetched_transcript)
|
| 47 |
+
return plaintext
|
| 48 |
+
except:
|
| 49 |
+
return "Could not fetch transcript from YouTube video."
|
test.json
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{'task_id': '8e867cd7-cff9-4e6c-867a-ff5ddc2550be', '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.', 'Level': '1', 'file_name': ''},
|
| 3 |
+
{'task_id': 'a1e91b78-d3d8-4675-bb8d-62741b4b68a6', 'question': 'In the video https://www.youtube.com/watch?v=L1vXCYZAYYM, what is the highest number of bird species to be on camera simultaneously?', 'Level': '1', 'file_name': ''},
|
| 4 |
+
{'task_id': '2d83110e-a098-4ebb-9987-066c06fa42d0', 'question': '.rewsna eht sa "tfel" drow eht fo etisoppo eht etirw ,ecnetnes siht dnatsrednu uoy fI', 'Level': '1', 'file_name': ''},
|
| 5 |
+
{'task_id': 'cca530fc-4052-43b2-b130-b30968d8aa44', 'question': "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.", 'Level': '1', 'file_name': 'cca530fc-4052-43b2-b130-b30968d8aa44.png'},
|
| 6 |
+
{'task_id': '4fc2f1ae-8625-45b5-ab34-ad4433bc21f8', 'question': 'Who nominated the only Featured Article on English Wikipedia about a dinosaur that was promoted in November 2016?', 'Level': '1', 'file_name': ''}]
|