Corin1998's picture
Create weather.py
3d3f75a verified
from __future__ import annotations
from typing import Optional, Dict
import requests
from datetime import datetime, timezone
import os
UA = {"User-Agent": "HF-Space-Trip-Planner/1.0 (+weather)"}
# WMO weather codes -> 簡易条件
# https://open-meteo.com/en/docs#api-formats
def _code_to_condition(code: int) -> str:
if code == 0:
return "sunny"
if 1 <= code <= 3:
return "cloudy"
if 45 <= code <= 48:
return "cloudy" # 霧・もや
if 51 <= code <= 67:
return "rainy" # 霧雨〜凍雨
if 71 <= code <= 77:
return "snowy" # 雪
if 80 <= code <= 82:
return "rainy" # にわか雨
if 85 <= code <= 86:
return "snowy" # にわか雪
if 95 <= code <= 99:
return "rainy" # 雷雨(豪雨側に丸め)
return "cloudy"
def _today_iso() -> str:
# Hugging Face の実行環境ではUTC基準になりがちだが、日付文字列だけ必要
return datetime.now(timezone.utc).date().isoformat()
def get_weather_summary(
lat: float,
lon: float,
date: Optional[str] = None,
override: Optional[str] = None,
) -> Dict[str, object]:
"""
外部API(Open-Meteo)を使って指定日の天気を簡約化して返す。
失敗時は 'cloudy' を返すフェイルセーフ。
返り値例:
{
"condition": "sunny|cloudy|rainy|snowy",
"temp_c": 27.3, # あれば
"source": "open-meteo",
"date": "YYYY-MM-DD"
}
"""
# UI のオーバーライド優先
if override and override != "(auto)":
return {"condition": override, "source": "override", "date": date or _today_iso()}
use_date = (date or _today_iso())
try:
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": lat,
"longitude": lon,
"daily": "weathercode,temperature_2m_max,temperature_2m_min,precipitation_probability_max",
"timezone": "auto",
"start_date": use_date,
"end_date": use_date,
}
r = requests.get(url, params=params, headers=UA, timeout=20)
r.raise_for_status()
j = r.json()
days = j.get("daily", {})
if not days:
raise RuntimeError("no daily in response")
codes = days.get("weathercode") or []
tmax = days.get("temperature_2m_max") or []
tmin = days.get("temperature_2m_min") or []
ppop = days.get("precipitation_probability_max") or []
code = int(codes[0]) if codes else 1
condition = _code_to_condition(code)
# 気温は平均っぽく
temp_c = None
if tmax and tmin:
temp_c = round((float(tmax[0]) + float(tmin[0])) / 2.0, 1)
elif tmax:
temp_c = round(float(tmax[0]), 1)
# 強い降水確率なら rainy に寄せる
if ppop:
try:
if int(ppop[0]) >= 60:
condition = "rainy" if condition != "snowy" else "snowy"
except Exception:
pass
out = {"condition": condition, "source": "open-meteo", "date": use_date}
if temp_c is not None:
out["temp_c"] = temp_c
return out
except Exception:
# API失敗時のフォールバック
return {"condition": "cloudy", "source": "fallback", "date": use_date}