Umar4321 commited on
Commit
268cea4
·
verified ·
1 Parent(s): 1b415a5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +30 -38
app.py CHANGED
@@ -2,7 +2,7 @@ import io
2
  import requests
3
  import pandas as pd
4
  import matplotlib
5
- matplotlib.use("Agg") # headless backend for Hugging Face
6
  import matplotlib.pyplot as plt
7
  import gradio as gr
8
 
@@ -11,20 +11,23 @@ FORECAST_URL = "https://api.open-meteo.com/v1/forecast"
11
 
12
 
13
  def geocode_city(city: str):
 
 
 
14
  r = requests.get(GEOCODE_URL, params={"name": city, "count": 1, "language": "en"}, timeout=10)
15
  r.raise_for_status()
16
  data = r.json()
17
  if not data.get("results"):
18
  raise ValueError(f"City '{city}' not found.")
19
  res = data["results"][0]
20
- return res["latitude"], res["longitude"], f"{res['name']}, {res.get('country','')}"
21
 
22
 
23
  def fetch_forecast(lat, lon, days, mode, temp_unit, precip_unit):
24
  params = {
25
  "latitude": lat,
26
  "longitude": lon,
27
- "forecast_days": days,
28
  "timezone": "auto",
29
  "temperature_unit": "fahrenheit" if temp_unit == "°F" else "celsius",
30
  "precipitation_unit": "inch" if precip_unit == "in" else "mm",
@@ -40,10 +43,18 @@ def fetch_forecast(lat, lon, days, mode, temp_unit, precip_unit):
40
 
41
 
42
  def make_plot(x, ys, labels, title, ylabel):
 
 
 
 
 
 
 
43
  plt.figure(figsize=(8, 3.5))
44
  for y, lbl in zip(ys, labels):
45
  plt.plot(x, y, label=lbl)
46
- plt.legend()
 
47
  plt.title(title)
48
  plt.xlabel("Time")
49
  plt.ylabel(ylabel)
@@ -57,10 +68,17 @@ def make_plot(x, ys, labels, title, ylabel):
57
 
58
  def run(city, mode, days, temp_unit, precip_unit):
59
  try:
 
 
 
 
 
60
  lat, lon, place = geocode_city(city)
61
  data = fetch_forecast(lat, lon, days, mode, temp_unit, precip_unit)
62
 
63
  if mode == "Daily":
 
 
64
  d = data["daily"]
65
  df = pd.DataFrame({
66
  "date": d["time"],
@@ -68,44 +86,18 @@ def run(city, mode, days, temp_unit, precip_unit):
68
  "temp_min": d["temperature_2m_min"],
69
  "precip": d["precipitation_sum"],
70
  })
 
71
  img = make_plot(df["date"], [df["temp_max"], df["temp_min"]],
72
  ["Max", "Min"], f"Daily Temperatures — {place}", f"Temp ({temp_unit})")
73
- md = f"### Daily forecast for **{place}**\nNext {days} day(s)"
74
  return md, df, img
75
 
76
  else: # Hourly
 
 
77
  h = data["hourly"]
 
 
 
78
  df = pd.DataFrame({
79
- "time": h["time"][:days*24],
80
- "temperature": h["temperature_2m"][:days*24],
81
- "humidity_%": h["relativehumidity_2m"][:days*24],
82
- "precip": h["precipitation"][:days*24],
83
- })
84
- img = make_plot(df["time"], [df["temperature"]],
85
- ["Temperature"], f"Hourly Temperatures — {place}", f"Temp ({temp_unit})")
86
- md = f"### Hourly forecast for **{place}**\nNext {days} day(s)"
87
- return md, df, img
88
-
89
- except Exception as e:
90
- return f"**Error:** {e}", pd.DataFrame(), None
91
-
92
-
93
- with gr.Blocks() as demo:
94
- gr.Markdown("# 🌦️ Weather Forecast (No API Key Needed)\nUsing **Open-Meteo** free API")
95
-
96
- with gr.Row():
97
- with gr.Column(scale=2):
98
- city = gr.Textbox(label="City", value="Karachi")
99
- mode = gr.Radio(["Daily", "Hourly"], value="Daily", label="Forecast type")
100
- days = gr.Slider(1, 14, value=3, step=1, label="Days")
101
- temp_unit = gr.Radio(["°C", "°F"], value="°C", label="Temperature unit")
102
- precip_unit = gr.Radio(["mm", "in"], value="mm", label="Precipitation unit")
103
- btn = gr.Button("Get Forecast")
104
-
105
- with gr.Column(scale=3):
106
- md = gr.Markdown()
107
- table = gr.Dataframe()
108
- img = gr.Image()
109
-
110
- btn.click(run, [city, mode, days, temp_unit, precip_unit], [md, table, img])
111
-
 
2
  import requests
3
  import pandas as pd
4
  import matplotlib
5
+ matplotlib.use("Agg") # headless backend for Hugging Face / servers
6
  import matplotlib.pyplot as plt
7
  import gradio as gr
8
 
 
11
 
12
 
13
  def geocode_city(city: str):
14
+ city = (city or "").strip()
15
+ if not city:
16
+ raise ValueError("Please enter a city name.")
17
  r = requests.get(GEOCODE_URL, params={"name": city, "count": 1, "language": "en"}, timeout=10)
18
  r.raise_for_status()
19
  data = r.json()
20
  if not data.get("results"):
21
  raise ValueError(f"City '{city}' not found.")
22
  res = data["results"][0]
23
+ return float(res["latitude"]), float(res["longitude"]), f"{res['name']}, {res.get('country','')}"
24
 
25
 
26
  def fetch_forecast(lat, lon, days, mode, temp_unit, precip_unit):
27
  params = {
28
  "latitude": lat,
29
  "longitude": lon,
30
+ "forecast_days": int(days),
31
  "timezone": "auto",
32
  "temperature_unit": "fahrenheit" if temp_unit == "°F" else "celsius",
33
  "precipitation_unit": "inch" if precip_unit == "in" else "mm",
 
43
 
44
 
45
  def make_plot(x, ys, labels, title, ylabel):
46
+ # ensure x is datetime-like for nice plotting
47
+ try:
48
+ x = pd.to_datetime(x)
49
+ except Exception:
50
+ # fall back to plain strings
51
+ x = list(map(str, x))
52
+
53
  plt.figure(figsize=(8, 3.5))
54
  for y, lbl in zip(ys, labels):
55
  plt.plot(x, y, label=lbl)
56
+ if labels:
57
+ plt.legend()
58
  plt.title(title)
59
  plt.xlabel("Time")
60
  plt.ylabel(ylabel)
 
68
 
69
  def run(city, mode, days, temp_unit, precip_unit):
70
  try:
71
+ # validate small things
72
+ days = int(days)
73
+ if days < 1 or days > 14:
74
+ raise ValueError("Days must be between 1 and 14.")
75
+
76
  lat, lon, place = geocode_city(city)
77
  data = fetch_forecast(lat, lon, days, mode, temp_unit, precip_unit)
78
 
79
  if mode == "Daily":
80
+ if "daily" not in data:
81
+ raise ValueError("Daily data not available for this location.")
82
  d = data["daily"]
83
  df = pd.DataFrame({
84
  "date": d["time"],
 
86
  "temp_min": d["temperature_2m_min"],
87
  "precip": d["precipitation_sum"],
88
  })
89
+ # return types: (markdown, DataFrame, bytes)
90
  img = make_plot(df["date"], [df["temp_max"], df["temp_min"]],
91
  ["Max", "Min"], f"Daily Temperatures — {place}", f"Temp ({temp_unit})")
92
+ md = f"### Daily forecast for **{place}**\nNext {days} day(s)\n\nUnits: Temperature **{temp_unit}**, Precipitation **{precip_unit}**"
93
  return md, df, img
94
 
95
  else: # Hourly
96
+ if "hourly" not in data:
97
+ raise ValueError("Hourly data not available for this location.")
98
  h = data["hourly"]
99
+ # Ensure we don't slice beyond available length
100
+ max_hours = len(h.get("time", []))
101
+ requested_hours = min(days * 24, max_hours)
102
  df = pd.DataFrame({
103
+ "time": h["time"][:requested_hours]_]()