Open-Metro
def get_current_weather(
self,
city: str = Field(
"Unknown",
description="City name for the weather"
),
) -> str:
"""
Get the current weather + 7-day forecast for a given city using Open-Meteo.
"""
import requests
from datetime import datetime
# Polite follow-up if city is not provided
if not city or city.strip().lower() == "unknown":
return "Which city would you like the weather for?"
# Open-Meteo weather code mapping
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",
}
def format_date(date_str: str) -> str:
try:
d = datetime.fromisoformat(date_str).date()
return d.strftime("%a %d %b")
except Exception:
return date_str
try:
# 1) Geocode city → lat/lon
geo_url = "https://geocoding-api.open-meteo.com/v1/search"
geo_params = {
"name": city,
"count": 1,
"language": "en",
"format": "json",
}
geo_resp = requests.get(geo_url, params=geo_params, timeout=10)
geo_resp.raise_for_status()
geo_data = geo_resp.json()
if "results" not in geo_data or not geo_data["results"]:
return f"I couldn’t find a location called “{city}”."
location = geo_data["results"][0]
latitude = location["latitude"]
longitude = location["longitude"]
location_name = f"{location['name']}, {location.get('country', '')}"
# 2) Fetch current weather + daily forecast (7 days) with local timezone
weather_url = "https://api.open-meteo.com/v1/forecast"
weather_params = {
"latitude": latitude,
"longitude": longitude,
"timezone": "auto",
"current_weather": True,
"daily": "weathercode,temperature_2m_max,temperature_2m_min,precipitation_sum,wind_speed_10m_max",
"forecast_days": 7,
}
weather_resp = requests.get(weather_url, params=weather_params, timeout=10)
weather_resp.raise_for_status()
weather_data = weather_resp.json()
if "current_weather" not in weather_data:
return "Weather data is currently unavailable."
current = weather_data["current_weather"]
temperature = current.get("temperature")
wind_speed = current.get("windspeed")
weather_code = current.get("weathercode")
weather_text = weather_codes.get(weather_code, "Unknown conditions")
# Local time handling
local_time_str = current.get("time")
timezone = weather_data.get("timezone", "local time")
try:
local_time = datetime.fromisoformat(local_time_str)
formatted_time = local_time.strftime("%A, %d %B %Y %I:%M %p")
except Exception:
formatted_time = local_time_str
# 3) Daily forecast parsing (7 days)
daily = weather_data.get("daily", {})
times = daily.get("time", [])
codes = daily.get("weathercode", [])
tmax = daily.get("temperature_2m_max", [])
tmin = daily.get("temperature_2m_min", [])
precip = daily.get("precipitation_sum", [])
windmax = daily.get("wind_speed_10m_max", [])
forecast_lines = []
days = min(
len(times),
len(codes),
len(tmax),
len(tmin),
len(precip),
len(windmax),
)
for i in range(days):
day_label = format_date(times[i])
day_text = weather_codes.get(codes[i], "Unknown")
forecast_lines.append(
f"- {day_label}: {day_text}, {tmin[i]}–{tmax[i]}°C, rain {precip[i]} mm, wind {windmax[i]} km/h"
)
forecast_block = "\n".join(forecast_lines) if forecast_lines else "No forecast available."
return (
f"Weather in {location_name}:\n"
f"- Conditions: {weather_text}\n"
f"- Temperature: {temperature}°C\n"
f"- Wind: {wind_speed} km/h\n"
f"- Local time: {formatted_time} ({timezone})\n\n"
f"7-day forecast:\n"
f"{forecast_block}"
)
except requests.RequestException:
return (
"I can’t reach the weather service from this server. "
"Please check outbound internet access."
)