ahmedelgendy's picture
Update app.py
e795a77 verified
# Installation of required packages
# pip install smolagents requests pytz pyyaml beautifulsoup4 Pillow
from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, load_tool, tool
import datetime
import requests
import pytz
import yaml
from tools.final_answer import FinalAnswerTool
from Gradio_UI import GradioUI
import bs4
from PIL import Image
import io
import base64
# Weather tool using Open Meteo (completely free, no API key required)
@tool
def get_weather(location: str) -> str:
"""Fetch current weather information for a specified location.
Args:
location: A string representing the city name.
"""
try:
# First, geocode the location to get coordinates
geocoding_url = f"https://nominatim.openstreetmap.org/search"
params = {
'q': location,
'format': 'json',
'limit': 1
}
headers = {
'User-Agent': 'WeatherToolAgent/1.0' # OpenStreetMap requires a user agent
}
geo_response = requests.get(geocoding_url, params=params, headers=headers)
geo_data = geo_response.json()
if not geo_data:
return f"Could not find coordinates for location: {location}"
# Extract latitude and longitude
lat = float(geo_data[0]['lat'])
lon = float(geo_data[0]['lon'])
display_name = geo_data[0]['display_name']
# Now get weather data from Open-Meteo
weather_url = "https://api.open-meteo.com/v1/forecast"
weather_params = {
'latitude': lat,
'longitude': lon,
'current': 'temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,wind_speed_10m',
'timezone': 'auto'
}
weather_response = requests.get(weather_url, params=weather_params)
weather_data = weather_response.json()
if 'current' not in weather_data:
return f"Error fetching weather data for {location}"
# WMO Weather interpretation codes (https://open-meteo.com/en/docs)
weather_codes = {
0: "Clear sky",
1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast",
45: "Fog", 48: "Depositing rime fog",
51: "Light drizzle", 53: "Moderate drizzle", 55: "Dense drizzle",
56: "Light freezing drizzle", 57: "Dense freezing drizzle",
61: "Slight rain", 63: "Moderate rain", 65: "Heavy rain",
66: "Light freezing rain", 67: "Heavy freezing rain",
71: "Slight snow fall", 73: "Moderate snow fall", 75: "Heavy snow fall",
77: "Snow grains",
80: "Slight rain showers", 81: "Moderate rain showers", 82: "Violent rain showers",
85: "Slight snow showers", 86: "Heavy snow showers",
95: "Thunderstorm", 96: "Thunderstorm with slight hail", 99: "Thunderstorm with heavy hail"
}
current = weather_data['current']
weather_description = weather_codes.get(current['weather_code'], "Unknown")
weather_info = (
f"Weather in {display_name}:\n"
f"Condition: {weather_description}\n"
f"Temperature: {current['temperature_2m']}°C\n"
f"Feels like: {current['apparent_temperature']}°C\n"
f"Humidity: {current['relative_humidity_2m']}%\n"
f"Wind Speed: {current['wind_speed_10m']} km/h\n"
f"Precipitation: {current['precipitation']} mm"
)
return weather_info
except Exception as e:
return f"Error fetching weather for {location}: {str(e)}"
# Web scraping tool
@tool
def web_scrape(url: str, selector: str = None) -> str:
"""Scrape content from a webpage.
Args:
url: The URL of the webpage to scrape.
selector: Optional CSS selector to extract specific elements (default: None, returns full page text).
"""
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
response = requests.get(url, headers=headers)
if response.status_code != 200:
return f"Failed to access the URL. Status code: {response.status_code}"
soup = bs4.BeautifulSoup(response.text, 'html.parser')
# Remove script and style elements
for script in soup(["script", "style"]):
script.extract()
if selector:
elements = soup.select(selector)
if not elements:
return f"No elements found matching selector: {selector}"
content = "\n".join([elem.get_text(strip=True) for elem in elements])
else:
# Get all text
content = soup.get_text(separator='\n', strip=True)
# Truncate if too long
if len(content) > 5000:
content = content[:5000] + "... (content truncated)"
return content
except Exception as e:
return f"Error scraping {url}: {str(e)}"
# Image processing tool
@tool
def process_image(image_url: str, operation: str = "info") -> str:
"""Process an image with various operations.
Args:
image_url: URL of the image to process.
operation: The operation to perform (options: "info", "resize", "grayscale", "blur").
"""
try:
response = requests.get(image_url)
if response.status_code != 200:
return f"Failed to download image. Status code: {response.status_code}"
image = Image.open(io.BytesIO(response.content))
if operation == "info":
info = {
"format": image.format,
"mode": image.mode,
"width": image.width,
"height": image.height,
"size_kb": len(response.content) / 1024
}
return f"Image information:\n" + "\n".join([f"{k}: {v}" for k, v in info.items()])
elif operation == "resize":
# Resize to 50% of original size
new_size = (image.width // 2, image.height // 2)
resized = image.resize(new_size)
# Convert to base64 for return
buffered = io.BytesIO()
resized.save(buffered, format=image.format if image.format else "JPEG")
img_str = base64.b64encode(buffered.getvalue()).decode()
return f"Resized image (now {new_size[0]}x{new_size[1]}):\ndata:image/{image.format.lower() if image.format else 'jpeg'};base64,{img_str}"
elif operation == "grayscale":
grayscale = image.convert('L')
# Convert to base64 for return
buffered = io.BytesIO()
grayscale.save(buffered, format=image.format if image.format else "JPEG")
img_str = base64.b64encode(buffered.getvalue()).decode()
return f"Grayscale image:\ndata:image/{image.format.lower() if image.format else 'jpeg'};base64,{img_str}"
elif operation == "blur":
from PIL import ImageFilter
blurred = image.filter(ImageFilter.GaussianBlur(radius=5))
# Convert to base64 for return
buffered = io.BytesIO()
blurred.save(buffered, format=image.format if image.format else "JPEG")
img_str = base64.b64encode(buffered.getvalue()).decode()
return f"Blurred image:\ndata:image/{image.format.lower() if image.format else 'jpeg'};base64,{img_str}"
else:
return f"Unknown operation: {operation}. Available operations: info, resize, grayscale, blur"
except Exception as e:
return f"Error processing image: {str(e)}"
# Keeping your existing custom tools
@tool
def my_custom_tool(arg1:str, arg2:int)-> str:
"""A tool that does nothing yet
Args:
arg1: the first argument
arg2: the second argument
"""
return "What magic will you build ?"
@tool
def get_current_time_in_timezone(timezone: str) -> str:
"""A tool that fetches the current local time in a specified timezone.
Args:
timezone: A string representing a valid timezone (e.g., 'America/New_York').
"""
try:
# Create timezone object
tz = pytz.timezone(timezone)
# Get current time in that timezone
local_time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")
return f"The current local time in {timezone} is: {local_time}"
except Exception as e:
return f"Error fetching time for timezone '{timezone}': {str(e)}"
final_answer = FinalAnswerTool()
# Model setup
model = HfApiModel(
max_tokens=2096,
temperature=0.5,
model_id='Qwen/Qwen2.5-Coder-32B-Instruct',
custom_role_conversions=None,
)
# Import tool from Hub
image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)
with open("prompts.yaml", 'r') as stream:
prompt_templates = yaml.safe_load(stream)
agent = CodeAgent(
model=model,
tools=[
final_answer,
get_weather,
web_scrape,
process_image,
get_current_time_in_timezone,
my_custom_tool,
image_generation_tool
], # Added the new tools here
max_steps=6,
verbosity_level=1,
grammar=None,
planning_interval=None,
name=None,
description=None,
prompt_templates=prompt_templates
)
GradioUI(agent).launch()