thatting's picture
Update tools.py
c83d35c verified
from typing import Any, Optional
from smolagents.tools import Tool
import io
import openpyxl
import os
from smolagents import tool
import requests
from PIL import Image
simplify_system_message = """
You are a general AI assistant. I will give you a question and answer, you should simplify answer. Your answer should be a number OR as few words as possible OR a comma separated list of numbers and/or strings. If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise. 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. 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.
"""
@tool
def ToolReverseString(text: str) -> str:
"""
Use this tool only if you encounter text that seems to be written backwards
Args:
text: The string to reverse.
"""
return text[::-1]
@tool
def ToolReadFiles(filepath: str) -> str:
"""
Downloads a .py or .xlsx file from a remote URL and returns its contents as plain text.
Raises a recoverable exception if the file does not end with .py or .xlsx.
Args:
filepath: The path to the Python (.py) or Excel (.xlsx) file.
"""
root_url = "https://agents-course-unit4-scoring.hf.space/files/"
# Strip the file extension from the url before downloading
import os
base, ext = os.path.splitext(filepath)
url = root_url + base
if filepath.endswith('.py'):
response = requests.get(url)
if response.status_code != 200:
raise Exception(f"Recoverable: Failed to download file from {url}")
return response.text
elif filepath.endswith('.xlsx'):
response = requests.get(url)
if response.status_code != 200:
raise Exception(f"Recoverable: Failed to download file from {url}")
wb = openpyxl.load_workbook(io.BytesIO(response.content), data_only=True)
result = []
for sheet in wb.worksheets:
result.append(f"# Sheet: {sheet.title}")
for row in sheet.iter_rows(values_only=True):
result.append(','.join([str(cell) if cell is not None else '' for cell in row]))
return '\n'.join(result)
else:
raise Exception("Recoverable: Only .py and .xlsx files can be read with this tool.")
@tool
def ToolDownloadImage(filepath: str) -> str:
"""
Downloads an image file (.png, .jpg, .jpeg) from a remote URL and returns useful information about the image.
This includes the image URL and basic metadata like dimensions and format.
Raises a recoverable exception if the file is not a supported image type.
Args:
filepath: The path to the image file.
"""
root_url = "https://agents-course-unit4-scoring.hf.space/files/"
base, ext = os.path.splitext(filepath)
url = root_url + base
if ext.lower() in ['.png', '.jpg', '.jpeg']:
response = requests.get(url)
if response.status_code != 200:
raise Exception(f"Recoverable: Failed to download image from {url}")
# Get image metadata using Pillow
try:
img = Image.open(io.BytesIO(response.content))
width, height = img.size
format = img.format
mode = img.mode
# Return useful information about the image
return f"Image URL: {url}\nFormat: {format}\nDimensions: {width}x{height}\nMode: {mode}"
except ImportError:
# Fallback if PIL is not available
content_type = response.headers.get('Content-Type', 'unknown')
content_length = response.headers.get('Content-Length', 'unknown')
return f"Content-Type: {content_type}\nSize: {content_length} bytes"
else:
raise Exception("Recoverable: Only .png, .jpg, and .jpeg files can be processed with this tool.")
#class FinalAnswerTool(Tool):
# name = "final_answer"
# description = "Provides a final answer to the given problem."
# inputs = {'answer': {'type': 'any', 'description': 'The final answer to the problem'}}
# output_type = "any"
# def forward(self, answer: Any) -> Any:
# return answer
# def __init__(self, *args, **kwargs):
# self.is_initialized = False
class FinalAnswerTool(Tool):
name = "simplify_answer"
description = (
"Simplify the final answer."
"Be sure to use this as the last step to prepare the final answer."
)
inputs = {
"question": {
"type": "string",
"description": "The question from the user.",
},
"answer": {
"type": "string",
"description": "The existing answer to be simplified.",
}
}
output_type = "string"
def __init__(self, api_model):
super().__init__()
self.api_model = api_model
def forward(self, question: str, answer: str) -> str:
try:
response_message = self.api_model(messages=[
{"role": MessageRole.SYSTEM, "content": [{"type": "text", "text": simplify_system_message }]},
{"role": MessageRole.ASSISTANT, "content": [{"type": "text", "text": f"QUESTION: {question}"}]},
{"role": MessageRole.ASSISTANT, "content": [{"type": "text", "text": f"ANSWER: {answer}"}]}
])
return response_message.content
except requests.exceptions.Timeout:
return "The request timed out. Please try again later or check the URL."
except RequestException as e:
return f"Error fetching the webpage: {str(e)}"
except Exception as e:
return f"An unexpected error occurred: {str(e)}"