File size: 7,637 Bytes
ba960dd db72768 ba960dd db72768 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
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__()
# You can set an API key for a real weather service like OpenWeatherMap
self.api_key = api_key or os.environ.get("WEATHER_API_KEY")
# Weather conditions for demo/fallback
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:
# Try to use a real weather API if the API key is available
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:
# Fall back to demo method if API call fails
return self._generate_demo_forecast(destination, days)
# Process and format forecast data
forecast_text = f"🌦️ Weather forecast for {destination}:\n\n"
# Group forecasts by day
forecasts_by_day = {}
for item in data['list'][:days * 8]: # API returns data in 3-hour intervals
date = item['dt_txt'].split(' ')[0]
if date not in forecasts_by_day:
forecasts_by_day[date] = []
forecasts_by_day[date].append(item)
# Format each day's forecast
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"
# Add packing recommendations
forecast_text += self._generate_packing_tips(forecasts_by_day)
return forecast_text
except Exception:
# Fall back to demo method if any error occurs
return self._generate_demo_forecast(destination, days)
# If no API key is available, use the demo method
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:
# Create a deterministic but seemingly random forecast based on destination name
seed = sum(ord(c) for c in destination)
random.seed(seed)
# Generate forecast data
forecast_text = f"🌦️ Weather forecast for {destination}:\n\n"
today = datetime.datetime.now()
temp_base = random.randint(10, 25) # Base temperature varies by destination
for i in range(days):
day = today + datetime.timedelta(days=i)
day_name = day.strftime("%A")
date = day.strftime("%b %d")
# "Random" but deterministic weather for the demo
condition = self.weather_conditions[random.randint(0, len(self.weather_conditions)-1)]
temp_high = temp_base + random.randint(0, 10) # Celsius
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"
# Add packing recommendations
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):
# Extract temperature ranges across all days
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
# Generate packing tips based on conditions
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 |