Spaces:
Sleeping
Sleeping
File size: 5,110 Bytes
1d20c3b be94c44 1d20c3b be94c44 ce62384 be94c44 ce62384 1d20c3b be94c44 ce62384 be94c44 ce62384 be94c44 1d20c3b be94c44 1d20c3b 53edcd0 8e2d880 |
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 |
import os
import requests
import pandas as pd
import gradio as gr
from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo
# --- CONFIG ---
TOMORROW_API_KEY = os.getenv("TOMORROW_API_KEY", "teKj9Rkys1UzWxKBEs36pAR8paCXnPW6")
METEOMATICS_USERNAME = os.getenv("METEO_USERNAME", "ptbukitteknologidigital_tudjuka_ricky")
METEOMATICS_PASSWORD = os.getenv("METEO_PASSWORD", "u5n25MwaviEG3O3v8q94")
DEFAULT_LAT = 0.46876
DEFAULT_LON = 116.16879
LOCAL_TZ = ZoneInfo("Asia/Kuala_Lumpur") # ✅ changed from Asia/Jakarta to Asia/Kuala_Lumpur
MM_VAR_RAIN = "precip_1h:mm"
MM_VAR_PROB = "prob_precip_1h:p"
DEFAULT_MODEL = "ecmwf-ifs"
# --- Tomorrow.io fetch ---
def fetch_tomorrow(lat, lon, hours=24):
if not TOMORROW_API_KEY:
raise RuntimeError("Missing TOMORROW_API_KEY")
url = "https://api.tomorrow.io/v4/weather/forecast"
params = {
"location": f"{lat},{lon}",
"units": "metric",
"fields": "rainIntensity,precipitationProbability",
"apikey": TOMORROW_API_KEY,
}
r = requests.get(url, params=params, timeout=25)
if r.status_code != 200:
raise RuntimeError(f"Tomorrow.io API error: {r.status_code} {r.text}")
data = r.json().get("timelines", {}).get("hourly", [])
if not data:
raise RuntimeError("Tomorrow.io: no hourly data returned")
rows = []
for p in data[:hours]:
ts = pd.to_datetime(p["time"], utc=True).tz_convert(LOCAL_TZ)
vals = p.get("values", {})
rain = float(vals.get("rainIntensity", 0.0) or 0.0)
prob = float(vals.get("precipitationProbability", 0.0) or 0.0)
rows.append({"time": ts, "tio_rain": rain, "tio_prob": prob})
return pd.DataFrame(rows)
# --- Meteomatics fetch ---
def fetch_meteomatics(lat, lon, hours=24):
if not METEOMATICS_USERNAME or not METEOMATICS_PASSWORD:
raise RuntimeError("Missing METEOMATICS credentials")
start = datetime.now(timezone.utc).replace(minute=0, second=0, microsecond=0)
end = start + timedelta(hours=hours - 1)
timepath = f"{start.isoformat().replace('+00:00','Z')}--{end.isoformat().replace('+00:00','Z')}:PT1H"
url = f"https://api.meteomatics.com/{timepath}/{MM_VAR_RAIN},{MM_VAR_PROB}/{lat},{lon}/json"
params = {"model": DEFAULT_MODEL}
r = requests.get(url, auth=(METEOMATICS_USERNAME, METEOMATICS_PASSWORD), params=params, timeout=25)
if r.status_code != 200:
raise RuntimeError(f"Meteomatics API error: {r.status_code} {r.text}")
js = r.json().get("data", [])
if not js:
raise RuntimeError("Meteomatics: no data returned")
time_map = {}
for entry in js:
var = entry.get("parameter")
for d in entry["coordinates"][0]["dates"]:
ts = pd.to_datetime(d["date"], utc=True).tz_convert(LOCAL_TZ)
val = float(d.get("value", 0.0) or 0.0)
rec = time_map.setdefault(ts, {})
if var == MM_VAR_RAIN:
rec["mm_rain"] = val
elif var == MM_VAR_PROB:
rec["mm_prob"] = val
df = pd.DataFrame([
{"time": t, "mm_rain": rec.get("mm_rain", 0.0), "mm_prob": rec.get("mm_prob", 0.0)}
for t, rec in sorted(time_map.items())
])
return df
# --- Combine & table ---
def build_table(lat, lon):
df_tio = fetch_tomorrow(lat, lon, 24)
df_mm = fetch_meteomatics(lat, lon, 24)
df = pd.merge(df_tio, df_mm, on="time", how="outer").sort_values("time")
table = pd.DataFrame({
"Time (Asia/Kuala_Lumpur)": df["time"].dt.strftime("%Y-%m-%d %H:%M"),
"Tomorrow.io Rain (mm/hr)": df["tio_rain"].round(3),
"Tomorrow.io Prob (%)": df["tio_prob"].round(1),
"Meteomatics Rain (mm/hr)": df["mm_rain"].round(3),
"Meteomatics Prob (%)": df["mm_prob"].round(1),
})
return table
def run_table(lat, lon):
try:
table = build_table(lat, lon)
info = f"<small>Location: {lat:.5f}, {lon:.5f} | Model: <b>{DEFAULT_MODEL}</b> | Timezone: <b>Asia/Kuala_Lumpur</b> | Units: <b>mm/hr</b> | Horizon: 24 hours</small>"
return table, info
except Exception as e:
return None, f"<p><b>Error:</b> {e}</p>"
# --- Gradio UI ---
with gr.Blocks(title="Next 24 Hours — Tomorrow.io + Meteomatics Table (mm/hr)") as demo:
gr.Markdown("## 🌧️ Next 24 Hours — **Tomorrow.io** & **Meteomatics** (All in mm/hr)\n"
"Side-by-side hourly rain and probability forecasts for the next 24 hours.")
with gr.Row():
lat = gr.Number(label="Latitude", value=DEFAULT_LAT)
lon = gr.Number(label="Longitude", value=DEFAULT_LON)
btn = gr.Button("Fetch 24h Table")
table_out = gr.Dataframe(interactive=False, wrap=True)
info_out = gr.HTML()
btn.click(run_table, inputs=[lat, lon], outputs=[table_out, info_out])
# if __name__ == "__main__":
# os.environ["GRADIO_ANALYTICS_ENABLED"]="false"
# os.environ["HF_HUB_DISABLE_TELEMETRY"]="1"
# demo.launch(server_name="127.0.0.1", server_port=7861, show_error=True, inbrowser=False, debug=True)
if __name__ == "__main__":
demo.launch() |