import openmeteo_requests import pandas as pd import requests_cache from retry_requests import retry from geopy.geocoders import Nominatim def call_openmeteo_current(city: str, variable: str) -> str: # Setup the Open-Meteo API client with cache and retry on error cache_session = requests_cache.CachedSession('.cache', expire_after = 3600) retry_session = retry(cache_session, retries = 5, backoff_factor = 0.2) openmeteo = openmeteo_requests.Client(session = retry_session) url = "https://api.open-meteo.com/v1/forecast" lat, lon = get_coordinates(city) params = { "latitude": lat, "longitude": lon, "current": variable, } responses = openmeteo.weather_api(url, params=params) response = responses[0] current = response.Current() variable = current.Variables(0).Value() return variable def get_current_weather(city: str) -> str: """Get the summary of the current weather in a city.""" weather = call_openmeteo_current(city, "weather_code") weather_str = weather_code_to_description(weather) return weather_str def get_current_temperature(city: str) -> str: """Get the current temperature in a city.""" temperature = call_openmeteo_current(city, "temperature_2m") return str(round(temperature)) def get_current_wind_speed(city: str) -> str: """Get the current wind speed (10m) in a city.""" wind = call_openmeteo_current(city, "wind_speed_10m") return str(round(wind)) + " m/s" def get_coordinates(city: str): geolocator = Nominatim(user_agent="NewApp") location = geolocator.geocode(city) return location.latitude, location.longitude def weather_code_to_description(code: float | int) -> str: """ Convert Open-Meteo (WMO) weather codes to human-readable descriptions. Accepts int or float values (e.g., 1.0 -> 1). """ code = int(code) WEATHER_CODE_MAP = { 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 snowfall", 73: "Moderate snowfall", 75: "Heavy snowfall", 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", } return WEATHER_CODE_MAP.get(code, f"Unknown weather code: {code}")