|
from typing import Any, Optional |
|
from smolagents.tools import Tool |
|
import datetime |
|
import random |
|
import os |
|
import requests |
|
|
|
class GetWeatherForecastTool(Tool): |
|
name = "get_weather_forecast" |
|
description = "Gets the weather forecast for a travel destination." |
|
inputs = { |
|
'destination': {'type': 'string', 'description': 'City or location name'}, |
|
'days': {'type': 'integer', 'description': 'Number of days to forecast (default: 3)', 'nullable': True} |
|
} |
|
output_type = "string" |
|
|
|
def __init__(self, api_key=None): |
|
super().__init__() |
|
|
|
self.api_key = api_key or os.environ.get("WEATHER_API_KEY") |
|
|
|
|
|
self.weather_conditions = [ |
|
"Sunny", "Partly Cloudy", "Cloudy", "Light Rain", |
|
"Heavy Rain", "Thunderstorms", "Windy", "Foggy", "Snow", "Clear" |
|
] |
|
|
|
def forward(self, destination: str, days: int = 3) -> str: |
|
try: |
|
|
|
if self.api_key: |
|
try: |
|
url = f"http://api.openweathermap.org/data/2.5/forecast?q={destination}&appid={self.api_key}&units=metric" |
|
response = requests.get(url) |
|
data = response.json() |
|
|
|
if response.status_code != 200: |
|
|
|
return self._generate_demo_forecast(destination, days) |
|
|
|
|
|
forecast_text = f"🌦️ Weather forecast for {destination}:\n\n" |
|
|
|
|
|
forecasts_by_day = {} |
|
for item in data['list'][:days * 8]: |
|
date = item['dt_txt'].split(' ')[0] |
|
if date not in forecasts_by_day: |
|
forecasts_by_day[date] = [] |
|
forecasts_by_day[date].append(item) |
|
|
|
|
|
for date, items in list(forecasts_by_day.items())[:days]: |
|
day_name = datetime.datetime.strptime(date, "%Y-%m-%d").strftime("%A") |
|
temps = [item['main']['temp'] for item in items] |
|
avg_temp = sum(temps) / len(temps) |
|
conditions = [item['weather'][0]['main'] for item in items] |
|
most_common = max(set(conditions), key=conditions.count) |
|
|
|
precipitation = any('Rain' in item['weather'][0]['main'] or 'Snow' in item['weather'][0]['main'] for item in items) |
|
precipitation_chance = "60%" if precipitation else "0%" |
|
|
|
forecast_text += f"• {day_name}, {date}: {most_common}, {min(temps):.1f}°C to {max(temps):.1f}°C" |
|
if precipitation: |
|
forecast_text += f", {precipitation_chance} chance of precipitation" |
|
forecast_text += "\n" |
|
|
|
|
|
forecast_text += self._generate_packing_tips(forecasts_by_day) |
|
|
|
return forecast_text |
|
|
|
except Exception: |
|
|
|
return self._generate_demo_forecast(destination, days) |
|
|
|
|
|
return self._generate_demo_forecast(destination, days) |
|
|
|
except Exception as e: |
|
return f"Error retrieving weather data for {destination}: {str(e)}" |
|
|
|
def _generate_demo_forecast(self, destination: str, days: int) -> str: |
|
|
|
seed = sum(ord(c) for c in destination) |
|
random.seed(seed) |
|
|
|
|
|
forecast_text = f"🌦️ Weather forecast for {destination}:\n\n" |
|
|
|
today = datetime.datetime.now() |
|
temp_base = random.randint(10, 25) |
|
|
|
for i in range(days): |
|
day = today + datetime.timedelta(days=i) |
|
day_name = day.strftime("%A") |
|
date = day.strftime("%b %d") |
|
|
|
|
|
condition = self.weather_conditions[random.randint(0, len(self.weather_conditions)-1)] |
|
temp_high = temp_base + random.randint(0, 10) |
|
temp_low = temp_high - random.randint(5, 15) |
|
precipitation = random.randint(0, 100) if "Rain" in condition or "Snow" in condition or "Thunder" in condition else 0 |
|
|
|
forecast_text += f"• {day_name}, {date}: {condition}, {temp_low}°C to {temp_high}°C" |
|
if precipitation > 0: |
|
forecast_text += f", {precipitation}% chance of precipitation" |
|
forecast_text += "\n" |
|
|
|
|
|
cold_days = sum(1 for i in range(days) if temp_base + 5 < 15) |
|
rainy_days = sum(1 for i in range(days) if "Rain" in self.weather_conditions[random.randint(0, len(self.weather_conditions)-1)]) |
|
hot_days = sum(1 for i in range(days) if temp_base + 5 > 25) |
|
|
|
forecast_text += "\n🧳 Packing tips: " |
|
if cold_days > days/2: |
|
forecast_text += "Bring warm layers and a jacket. " |
|
elif cold_days > 0: |
|
forecast_text += "Pack a light jacket for cooler periods. " |
|
|
|
if rainy_days > 0: |
|
forecast_text += "Don't forget an umbrella or rain gear. " |
|
|
|
if hot_days > days/2: |
|
forecast_text += "Bring sunscreen, sunglasses, and light clothing. " |
|
|
|
return forecast_text |
|
|
|
def _generate_packing_tips(self, forecasts_by_day): |
|
|
|
all_temps = [] |
|
has_rain = False |
|
has_snow = False |
|
|
|
for day_items in forecasts_by_day.values(): |
|
for item in day_items: |
|
all_temps.append(item['main']['temp']) |
|
if 'Rain' in item['weather'][0]['main']: |
|
has_rain = True |
|
if 'Snow' in item['weather'][0]['main']: |
|
has_snow = True |
|
|
|
min_temp = min(all_temps) if all_temps else 0 |
|
max_temp = max(all_temps) if all_temps else 30 |
|
|
|
|
|
tips = "\n🧳 Packing tips: " |
|
|
|
if min_temp < 5: |
|
tips += "Bring a heavy winter coat, gloves, and hat. " |
|
elif min_temp < 15: |
|
tips += "Pack a warm jacket and layers. " |
|
elif min_temp < 20: |
|
tips += "Bring a light jacket for evenings. " |
|
|
|
if max_temp > 25: |
|
tips += "Pack light, breathable clothing for warm days. " |
|
|
|
if has_rain: |
|
tips += "Don't forget an umbrella and waterproof footwear. " |
|
|
|
if has_snow: |
|
tips += "Bring waterproof boots and warm socks. " |
|
|
|
if max_temp > 22: |
|
tips += "Sunscreen and sunglasses are recommended. " |
|
|
|
return tips |