hammaad-swe commited on
Commit
87394ed
·
1 Parent(s): ff5ced3

feat: added Excel Tool

Browse files
Files changed (3) hide show
  1. agent.py +76 -9
  2. logic.py +44 -1
  3. requirements.txt +2 -1
agent.py CHANGED
@@ -1,37 +1,104 @@
1
  import os
 
 
2
 
 
3
  from dotenv import load_dotenv
4
- from smolagents import (CodeAgent, DuckDuckGoSearchTool, FinalAnswerTool, LiteLLMModel,
5
- PythonInterpreterTool, VisitWebpageTool, WikipediaSearchTool)
 
 
 
 
 
 
 
 
6
 
 
7
  load_dotenv()
8
 
 
9
  model = LiteLLMModel(
10
  model_id=os.getenv("GEMINI_MODEL"),
11
  api_key=os.getenv("GEMINI_API_KEY")
 
 
 
 
 
 
 
 
 
 
12
  )
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  class GaiaAgent:
16
- """
17
- An agent designed to answer questions using a combination of tools,
18
- including search engines, web page access, a Python interpreter, and more.
19
- """
20
  def __init__(self):
21
  print("GaiaAgent initialized with tools.")
22
 
23
  tools = [
24
  DuckDuckGoSearchTool(),
25
- VisitWebpageTool(),
26
  WikipediaSearchTool(),
 
27
  PythonInterpreterTool(),
28
  FinalAnswerTool(),
29
  ]
30
 
31
- self.agent = CodeAgent(model=model, tools=tools)
 
 
 
 
 
32
 
33
  def __call__(self, task_id: str, question: str) -> str:
34
- print(f"Agent received {task_id=}\n{question[:50]=}...")
35
  answer = self.agent.run(question)
36
  print(f"Agent returning answer: {answer}")
37
  return answer
 
1
  import os
2
+ from pathlib import Path
3
+ from typing import Optional, Union
4
 
5
+ import pandas as pd
6
  from dotenv import load_dotenv
7
+ from smolagents import (
8
+ CodeAgent,
9
+ DuckDuckGoSearchTool,
10
+ FinalAnswerTool,
11
+ LiteLLMModel,
12
+ PythonInterpreterTool,
13
+ WikipediaSearchTool,
14
+ )
15
+ from smolagents.tools import Tool
16
+ from tabulate import tabulate
17
 
18
+ # Load environment variables
19
  load_dotenv()
20
 
21
+ # Initialize the model
22
  model = LiteLLMModel(
23
  model_id=os.getenv("GEMINI_MODEL"),
24
  api_key=os.getenv("GEMINI_API_KEY")
25
+ )
26
+
27
+
28
+ class ExcelToTextTool(Tool):
29
+ """Render an Excel worksheet as a Markdown table."""
30
+
31
+ name = "excel_to_text"
32
+ description = (
33
+ "Read an Excel file and return a Markdown table of the requested sheet. "
34
+ "Accepts either the sheet name or a zero-based index (as a string)."
35
  )
36
 
37
+ inputs = {
38
+ "excel_path": {
39
+ "type": "string",
40
+ "description": "Path to the Excel file (.xlsx or .xls).",
41
+ },
42
+ "sheet_name": {
43
+ "type": "string",
44
+ "description": (
45
+ "Worksheet name or zero-based index (as a string). "
46
+ "Optional; defaults to the first sheet."
47
+ ),
48
+ "nullable": True,
49
+ },
50
+ }
51
+
52
+ output_type = "string"
53
+
54
+ def forward(self, excel_path: str, sheet_name: Optional[str] = None) -> str:
55
+ """Load the Excel file and return the sheet as a Markdown table."""
56
+
57
+ file_path = Path(excel_path).expanduser().resolve()
58
+ if not file_path.is_file():
59
+ return f"Error: Excel file not found at {file_path}"
60
+
61
+ try:
62
+ sheet: Union[str, int] = (
63
+ int(
64
+ sheet_name
65
+ ) if sheet_name and sheet_name.isdigit() else sheet_name or 0
66
+ )
67
+
68
+ df = pd.read_excel(file_path, sheet_name=sheet)
69
+
70
+ if hasattr(df, "to_markdown"):
71
+ return df.to_markdown(index=False)
72
+
73
+ return tabulate(df, headers="keys", tablefmt="github", showindex=False)
74
+
75
+ except Exception as e:
76
+ return f"Error reading Excel file: {e}"
77
+
78
 
79
  class GaiaAgent:
80
+ """An agent capable of using tools to answer general questions."""
81
+
 
 
82
  def __init__(self):
83
  print("GaiaAgent initialized with tools.")
84
 
85
  tools = [
86
  DuckDuckGoSearchTool(),
 
87
  WikipediaSearchTool(),
88
+ ExcelToTextTool(),
89
  PythonInterpreterTool(),
90
  FinalAnswerTool(),
91
  ]
92
 
93
+ self.agent = CodeAgent(
94
+ model=model,
95
+ tools=tools,
96
+ add_base_tools=True,
97
+ additional_authorized_imports=["pandas", "numpy", "csv", "subprocess"],
98
+ )
99
 
100
  def __call__(self, task_id: str, question: str) -> str:
101
+ print(f"Agent received task_id='{task_id}' | question='{question[:50]}...'")
102
  answer = self.agent.run(question)
103
  print(f"Agent returning answer: {answer}")
104
  return answer
logic.py CHANGED
@@ -1,5 +1,7 @@
1
  from typing import Dict, List, Tuple
2
-
 
 
3
  import pandas as pd
4
  import requests
5
  from agent import GaiaAgent
@@ -9,6 +11,7 @@ from pandas import DataFrame
9
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
10
  QUESTIONS_URL = f"{DEFAULT_API_URL}/questions"
11
  SUBMIT_URL = f"{DEFAULT_API_URL}/submit"
 
12
 
13
 
14
  # --- Helper Methods ---
@@ -142,6 +145,7 @@ def run_agent(
142
  for item in questions_data:
143
  task_id = item.get("task_id")
144
  question_text = item.get("question")
 
145
  if not task_id or question_text is None:
146
  print(f"⚠️ Skipping invalid item (missing task_id or question): {item}")
147
  continue
@@ -162,3 +166,42 @@ def run_agent(
162
  }
163
  )
164
  return results_log, answers_payload
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from typing import Dict, List, Tuple
2
+ import re
3
+ import tempfile
4
+ from pathlib import Path
5
  import pandas as pd
6
  import requests
7
  from agent import GaiaAgent
 
11
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
12
  QUESTIONS_URL = f"{DEFAULT_API_URL}/questions"
13
  SUBMIT_URL = f"{DEFAULT_API_URL}/submit"
14
+ FILE_PATH = f"{DEFAULT_API_URL}/files/"
15
 
16
 
17
  # --- Helper Methods ---
 
145
  for item in questions_data:
146
  task_id = item.get("task_id")
147
  question_text = item.get("question")
148
+ question_text = process_file(task_id, question_text)
149
  if not task_id or question_text is None:
150
  print(f"⚠️ Skipping invalid item (missing task_id or question): {item}")
151
  continue
 
166
  }
167
  )
168
  return results_log, answers_payload
169
+
170
+
171
+ def process_file(task_id: str, question_text: str) -> str:
172
+ """
173
+ Attempt to download a file associated with a task from the API.
174
+
175
+ - If the file exists (HTTP 200), it is saved to a temp directory and the local file path is returned.
176
+ - If no file is found (HTTP 404), returns None.
177
+ - For all other HTTP errors, the exception is propagated to the caller.
178
+ """
179
+ file_url = f"{FILE_PATH}{task_id}"
180
+
181
+ try:
182
+ response = requests.get(file_url, timeout=30)
183
+ response.raise_for_status()
184
+ except requests.exceptions.RequestException as exc:
185
+ print(f"Exception in download_file>> {str(exc)}")
186
+ return question_text # Unable to get the file
187
+
188
+ # Determine filename from 'Content-Disposition' header, fallback to task_id
189
+ content_disposition = response.headers.get("content-disposition", "")
190
+ filename = task_id
191
+ match = re.search(r'filename="([^"]+)"', content_disposition)
192
+ if match:
193
+ filename = match.group(1)
194
+
195
+ # Save file in a temp directory
196
+ temp_storage_dir = Path(tempfile.gettempdir()) / "gaia_cached_files"
197
+ temp_storage_dir.mkdir(parents=True, exist_ok=True)
198
+
199
+ file_path = temp_storage_dir / filename
200
+ file_path.write_bytes(response.content)
201
+ return (
202
+ f"{question_text}\n\n"
203
+ f"---\n"
204
+ f"A file was downloaded for this task and saved locally at:\n"
205
+ f"{str(file_path)}\n"
206
+ f"---\n\n"
207
+ )
requirements.txt CHANGED
@@ -6,4 +6,5 @@ pandas
6
  smolagents
7
  wikipedia-api
8
  google-generativeai
9
- smolagents[litellm]
 
 
6
  smolagents
7
  wikipedia-api
8
  google-generativeai
9
+ smolagents[litellm]
10
+ tabulate