Spaces:
Runtime error
Runtime error
File size: 3,623 Bytes
51c9c1d 9731ab0 268cea4 51c9c1d 859856a 268cea4 859856a 51c9c1d 9731ab0 859856a 51c9c1d 268cea4 51c9c1d 859856a 51c9c1d 268cea4 9731ab0 51c9c1d 9731ab0 859856a 51c9c1d 859856a 268cea4 859856a 268cea4 51c9c1d 859856a 51c9c1d 859856a 51c9c1d 859856a 268cea4 859856a 268cea4 859856a 268cea4 859856a 268cea4 859856a 268cea4 859856a 268cea4 859856a 268cea4 |
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 |
import io
import requests
import pandas as pd
import matplotlib
matplotlib.use("Agg") # headless backend for Hugging Face / servers
import matplotlib.pyplot as plt
import gradio as gr
GEOCODE_URL = "https://geocoding-api.open-meteo.com/v1/search"
FORECAST_URL = "https://api.open-meteo.com/v1/forecast"
def geocode_city(city: str):
city = (city or "").strip()
if not city:
raise ValueError("Please enter a city name.")
r = requests.get(GEOCODE_URL, params={"name": city, "count": 1, "language": "en"}, timeout=10)
r.raise_for_status()
data = r.json()
if not data.get("results"):
raise ValueError(f"City '{city}' not found.")
res = data["results"][0]
return float(res["latitude"]), float(res["longitude"]), f"{res['name']}, {res.get('country','')}"
def fetch_forecast(lat, lon, days, mode, temp_unit, precip_unit):
params = {
"latitude": lat,
"longitude": lon,
"forecast_days": int(days),
"timezone": "auto",
"temperature_unit": "fahrenheit" if temp_unit == "°F" else "celsius",
"precipitation_unit": "inch" if precip_unit == "in" else "mm",
}
if mode == "Daily":
params["daily"] = "temperature_2m_max,temperature_2m_min,precipitation_sum"
else:
params["hourly"] = "temperature_2m,relativehumidity_2m,precipitation"
r = requests.get(FORECAST_URL, params=params, timeout=15)
r.raise_for_status()
return r.json()
def make_plot(x, ys, labels, title, ylabel):
# ensure x is datetime-like for nice plotting
try:
x = pd.to_datetime(x)
except Exception:
# fall back to plain strings
x = list(map(str, x))
plt.figure(figsize=(8, 3.5))
for y, lbl in zip(ys, labels):
plt.plot(x, y, label=lbl)
if labels:
plt.legend()
plt.title(title)
plt.xlabel("Time")
plt.ylabel(ylabel)
plt.tight_layout()
buf = io.BytesIO()
plt.savefig(buf, format="png", dpi=120)
plt.close()
buf.seek(0)
return buf.getvalue()
def run(city, mode, days, temp_unit, precip_unit):
try:
# validate small things
days = int(days)
if days < 1 or days > 14:
raise ValueError("Days must be between 1 and 14.")
lat, lon, place = geocode_city(city)
data = fetch_forecast(lat, lon, days, mode, temp_unit, precip_unit)
if mode == "Daily":
if "daily" not in data:
raise ValueError("Daily data not available for this location.")
d = data["daily"]
df = pd.DataFrame({
"date": d["time"],
"temp_max": d["temperature_2m_max"],
"temp_min": d["temperature_2m_min"],
"precip": d["precipitation_sum"],
})
# return types: (markdown, DataFrame, bytes)
img = make_plot(df["date"], [df["temp_max"], df["temp_min"]],
["Max", "Min"], f"Daily Temperatures — {place}", f"Temp ({temp_unit})")
md = f"### Daily forecast for **{place}**\nNext {days} day(s)\n\nUnits: Temperature **{temp_unit}**, Precipitation **{precip_unit}**"
return md, df, img
else: # Hourly
if "hourly" not in data:
raise ValueError("Hourly data not available for this location.")
h = data["hourly"]
# Ensure we don't slice beyond available length
max_hours = len(h.get("time", []))
requested_hours = min(days * 24, max_hours)
df = pd.DataFrame({
"time": h["time"][:requested_hours]_]()
|