mohammadreza pakzadian commited on
Commit
aa84f48
·
1 Parent(s): 14d28bc

add some useful tools

Browse files
app.py CHANGED
@@ -3,14 +3,20 @@ import gradio as gr
3
  import requests
4
  import pandas as pd
5
  from smolagents import CodeAgent, OpenAIServerModel, HfApiModel
 
 
 
 
6
  from tools.final_answer import FinalAnswerTool
7
  from tools.visit_webpage import VisitWebpageTool
8
  from tools.web_search import DuckDuckGoSearchTool
9
- from tools.youtube_transcript import YoutubeTranscriptTool
 
 
10
 
11
  # (Keep Constants as is)
12
  # --- Constants ---
13
- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
14
 
15
  # --- Basic Agent Definition ---
16
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
@@ -20,8 +26,12 @@ class BasicAgent:
20
  final_answer = FinalAnswerTool()
21
  visit_webpage = VisitWebpageTool()
22
  web_search = DuckDuckGoSearchTool()
23
- youtube_transcript = YoutubeTranscriptTool()
24
- # model = OpenAIServerModel(model_id="gpt-4.1", api_key=os.getenv("OPENAI_API_KEY"))
 
 
 
 
25
  model = HfApiModel(
26
  max_tokens=2096,
27
  temperature=0.5,
@@ -30,11 +40,11 @@ class BasicAgent:
30
  )
31
  self.agent = CodeAgent(
32
  model=model,
33
- tools=[visit_webpage, web_search, final_answer, youtube_transcript],
34
  max_steps=5,
35
  verbosity_level=1,
36
  add_base_tools=True,
37
- # additional_authorized_imports=['random', 'stat', 'time', 'collections', 'itertools', 'queue', 're', 'datetime', 'statistics', 'math', 'unicodedata', 'csv', 'pandas']
38
  )
39
  def __call__(self, question: str) -> str:
40
  print(f"Agent received question (first 50 chars): {question}")
@@ -116,6 +126,11 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
116
  for item in questions_data:
117
  task_id = item.get("task_id")
118
  question_text = item.get("question")
 
 
 
 
 
119
  if not task_id or question_text is None:
120
  print(f"Skipping item with missing task_id or question: {item}")
121
  continue
 
3
  import requests
4
  import pandas as pd
5
  from smolagents import CodeAgent, OpenAIServerModel, HfApiModel
6
+
7
+ from tools.analyze_image import AnalyzeImageTool
8
+ from tools.excel_reader import ExcelReader
9
+ from tools.file_reader import FileReader
10
  from tools.final_answer import FinalAnswerTool
11
  from tools.visit_webpage import VisitWebpageTool
12
  from tools.web_search import DuckDuckGoSearchTool
13
+ from tools.wikipedia_search import WikipediaSearch
14
+ from tools.youtube_transcript import YouTubeTranscript
15
+ from utils import download_files
16
 
17
  # (Keep Constants as is)
18
  # --- Constants ---
19
+ from consts import DEFAULT_API_URL
20
 
21
  # --- Basic Agent Definition ---
22
  # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
 
26
  final_answer = FinalAnswerTool()
27
  visit_webpage = VisitWebpageTool()
28
  web_search = DuckDuckGoSearchTool()
29
+ analyze_image = AnalyzeImageTool()
30
+ excel_reader = ExcelReader()
31
+ file_reader = FileReader()
32
+ wikipedia_search = WikipediaSearch()
33
+ youtube_transcript = YouTubeTranscript()
34
+ # model = OpenAIServerModel(model_id="gpt-4.1", api_key=os.getenv("OPENAI_API_KEY"), api_base=os.getenv("OPENAI_BASE_URL"))
35
  model = HfApiModel(
36
  max_tokens=2096,
37
  temperature=0.5,
 
40
  )
41
  self.agent = CodeAgent(
42
  model=model,
43
+ tools=[visit_webpage, web_search, final_answer, analyze_image, excel_reader, file_reader, wikipedia_search, youtube_transcript],
44
  max_steps=5,
45
  verbosity_level=1,
46
  add_base_tools=True,
47
+ additional_authorized_imports=['random', 'stat', 'time', 'collections', 'itertools', 'queue', 're', 'datetime', 'statistics', 'math', 'unicodedata', 'csv', 'pandas']
48
  )
49
  def __call__(self, question: str) -> str:
50
  print(f"Agent received question (first 50 chars): {question}")
 
126
  for item in questions_data:
127
  task_id = item.get("task_id")
128
  question_text = item.get("question")
129
+ file_name = item.get('file_name')
130
+ if file_name:
131
+ file_path = download_files(task_id, file_name)
132
+ file_format = file_name.split('.')[-1]
133
+ question_text = question_text + f"This question has an associated file at path: {file_path}. The file is in the {file_format} format"
134
  if not task_id or question_text is None:
135
  print(f"Skipping item with missing task_id or question: {item}")
136
  continue
consts.py ADDED
@@ -0,0 +1 @@
 
 
1
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
requirements.txt CHANGED
@@ -7,3 +7,9 @@ requests
7
  duckduckgo_search
8
  pandas
9
  youtube-transcript-api
 
 
 
 
 
 
 
7
  duckduckgo_search
8
  pandas
9
  youtube-transcript-api
10
+ bs4
11
+ wikipedia
12
+ tabulate
13
+ llama_index
14
+ llama-index-readers-youtube-transcript
15
+ openai
tools/analyze_image.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import os
3
+ from smolagents import Tool
4
+ from openai import OpenAI
5
+
6
+ class AnalyzeImageTool(Tool):
7
+ name = "analyze_image_tool"
8
+ description = """This tool performs a custom analysis of the provided image and returns the corresponding result."""
9
+ inputs = {
10
+ "image_path": {"type": "string", "description": "Image path"},
11
+ "task": {"type": "string", "description": "Task to perform on the image, be detailed and clear"},
12
+ }
13
+ output_type = "string"
14
+
15
+ def __init__(self):
16
+ super().__init__()
17
+ self.model_id = "gpt-4.1-mini"
18
+
19
+ def forward(self, image_path: str, task: str) -> str:
20
+ """
21
+ Analyze the image at `image_path` according to `task` and return the textual result.
22
+ """
23
+ header = "Image analysis result:\n\n"
24
+ llm_instruction = (
25
+ "You are a highly capable image analysis tool, designed to examine images and deliver detailed descriptions, "
26
+ "insights, and relevant interpretations based on the task at hand.\n\n"
27
+ "Approach the task methodically and provide a thorough and well-reasoned response to the following:\n\n---\nTask:\n"
28
+ f"{task}\n\n"
29
+ )
30
+ try:
31
+ return header + self._analyze_with_openai(image_path, llm_instruction)
32
+ except Exception as e:
33
+ return f"Error analyzing image: {e}."
34
+
35
+ def _analyze_with_openai(self, image_path: str, task: str) -> str:
36
+ client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL"))
37
+
38
+ with open(image_path, "rb") as f:
39
+ encoded_image = base64.b64encode(f.read()).decode("utf-8")
40
+
41
+ payload = [
42
+ {
43
+ "role": "user",
44
+ "content": [
45
+ {"type": "input_text", "text": task},
46
+ {"type": "input_image", "image_url": f"data:image/jpeg;base64,{encoded_image}"},
47
+ ],
48
+ }
49
+ ]
50
+ response = client.responses.create(model=self.model_id, input=payload)
51
+ return response.output[0].content[0].text
tools/excel_reader.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from smolagents import Tool
2
+ import pandas as pd
3
+ from tabulate import tabulate
4
+
5
+ class ExcelReader(Tool):
6
+ name = 'excel_processor'
7
+ description = "excel reading tool, processed files of .xlsx and .xls format."
8
+ inputs = {
9
+ "file_path": {
10
+ "type": "string",
11
+ "description": "path to the excel file"
12
+ }
13
+ }
14
+ output_type = "string"
15
+
16
+ def forward(self, file_path: str) -> str:
17
+ try:
18
+ df = pd.read_excel(file_path)
19
+ txt_excel = tabulate(df, headers="keys", tablefmt="github", showindex=False)
20
+ return txt_excel
21
+ except Exception as e:
22
+ return f'Error in reading excel file: {str(e)}'
tools/file_reader.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from smolagents import Tool
2
+
3
+ class FileReader(Tool):
4
+ name = 'file_reader'
5
+ description = "reads saved files"
6
+ inputs = {
7
+ "file_path": {
8
+ "type": "string",
9
+ "description": "path to the file"
10
+ }
11
+ }
12
+ output_type = "string"
13
+
14
+ def forward(self, file_path: str) -> str:
15
+ try:
16
+ with open(file_path, "r") as file:
17
+ content = file.read()
18
+ return content
19
+ except Exception as e:
20
+ return f'Error in reading file: {str(e)}'
tools/wikipedia_search.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from smolagents import Tool
2
+ import wikipedia
3
+ from bs4 import BeautifulSoup
4
+
5
+ class WikipediaSearch(Tool):
6
+ name = "wikipedia_search"
7
+ description = "Fetches wikipedia pages."
8
+ inputs = {
9
+ "query": {
10
+ "type": "string",
11
+ "description": "Query to be searched on wikipedia"
12
+ }
13
+ }
14
+ output_type = "string"
15
+
16
+ def forward(self, query:str)->str:
17
+ try:
18
+ res = wikipedia.page(query)
19
+ bs = BeautifulSoup(res.html(), 'html.parser')
20
+ text_only = bs.get_text()
21
+ return text_only
22
+ except Exception as e:
23
+ return f'Error in wikipedia search: {str(e)}'
tools/youtube_transcript.py CHANGED
@@ -1,24 +1,22 @@
1
- from smolagents.tools import Tool
 
2
 
3
- class YoutubeTranscriptTool(Tool):
4
- name = "youtube_transcript"
5
- description = "This tool allows you to retrieve the transcript/subtitles for a given YouTube video. To use this tool you should pass in the video ID, not the video URL. For a video with the URL https://www.youtube.com/watch?v=12345 the ID is 12345."
6
- inputs = {'video_id': {'type': 'string', 'description': 'The Id of YouTube video'}}
7
- output_type = "list[dict]"
 
 
 
 
 
8
 
9
- def __init__(self):
10
- super().__init__()
11
  try:
12
- from youtube_transcript_api import YouTubeTranscriptApi
13
- except ImportError as e:
14
- raise ImportError(
15
- "You must install package `youtube_transcript_api` to run this tool: for instance run `pip install youtube_transcript_api`."
16
- ) from e
17
- self.ytt_api = YouTubeTranscriptApi()
18
-
19
- def forward(self, video_id: str) -> list[dict] | str:
20
- try:
21
- result = self.ytt_api.fetch(video_id)
22
- return result.to_raw_data()
23
  except Exception as e:
24
- return f"An unexpected error occurred: {str(e)}"
 
1
+ from smolagents import Tool
2
+ from llama_index.readers.youtube_transcript import YoutubeTranscriptReader
3
 
4
+ class YouTubeTranscript(Tool):
5
+ name = 'youtube_transcript'
6
+ description = "a tool that returns a transcript for a youtube video. Youtube videos come from urls containing www.youtube.com"
7
+ inputs = {
8
+ "url": {
9
+ "type": "string",
10
+ "description": "url to the youtube video, has 'www.youtube.com' in it."
11
+ }
12
+ }
13
+ output_type = "string"
14
 
15
+ def forward(self, url: str) -> str:
 
16
  try:
17
+ loader = YoutubeTranscriptReader()
18
+ documents = loader.load_data(ytlinks=[url])
19
+ transcript = documents[0].text
20
+ return transcript
 
 
 
 
 
 
 
21
  except Exception as e:
22
+ return f'Error getting youtube transcript: {str(e)}'
utils.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import os
3
+ import tempfile
4
+ from pathlib import Path
5
+ from consts import DEFAULT_API_URL
6
+
7
+ def download_files(task_id, file_name):
8
+ url = f'{DEFAULT_API_URL}/files/{task_id}'
9
+ response = requests.get(url, timeout=15)
10
+ tmp_dir = Path(tempfile.gettempdir()) / "project_files"
11
+ tmp_dir.mkdir(exist_ok=True)
12
+ filepath = os.path.join(tmp_dir, file_name)
13
+ with open(filepath, "wb") as f:
14
+ f.write(response.content)
15
+
16
+ return filepath