feat: Extract weather trend analysis into a new shared module and add initial web application and data collection components.

This commit is contained in:
2569718930@qq.com
2026-03-04 19:47:19 +08:00
parent 00bd2539fa
commit 9e5fc418de
4 changed files with 38 additions and 6 deletions
+1 -1
View File
@@ -349,7 +349,7 @@ def start_bot():
)
open_meteo = weather_data.get("open-meteo", {})
metar = weather_data.get("metar", {})
mgm = weather_data.get("mgm", {})
mgm = weather_data.get("mgm") or {}
# 数值归一化
def _sf(v):
+5
View File
@@ -60,6 +60,7 @@ def analyze_weather_trend(
metar = weather_data.get("metar", {})
open_meteo = weather_data.get("open-meteo", {})
mgm = weather_data.get("mgm") or {}
mb = weather_data.get("meteoblue", {})
nws = weather_data.get("nws", {})
@@ -82,6 +83,10 @@ def analyze_weather_trend(
current_forecasts["Meteoblue"] = _sf(mb.get("today_high"))
if nws.get("today_high") is not None:
current_forecasts["NWS"] = _sf(nws.get("today_high"))
mgm = weather_data.get("mgm", {})
if mgm and mgm.get("today_high") is not None:
current_forecasts["MGM"] = _sf(mgm.get("today_high"))
mm_forecasts = weather_data.get("multi_model", {}).get("forecasts", {})
for m_name, m_val in mm_forecasts.items():
+26 -4
View File
@@ -506,16 +506,24 @@ class WeatherDataCollector:
if daily_resp.status_code == 200:
forecasts = daily_resp.json()
if forecasts and isinstance(forecasts, list):
# Store today extra clearly
today = forecasts[0]
high_val = today.get("enYuksekGun1")
low_val = today.get("enDusukGun1")
if high_val is not None:
results["today_high"] = high_val
results["today_low"] = low_val
logger.info(
f"📋 MGM 每日预报: 最高 {high_val}°C, 最低 {low_val}°C (from {forecast_url})"
)
break
logger.info(f"📋 MGM 每日预报: 今天的最高温 {high_val}°C")
# Store all 5 days for multi_model_daily
results["daily_forecasts"] = {}
for i, day in enumerate(forecasts[:5]):
d_high = day.get("enYuksekGun1")
if d_high is not None:
# Calculate date (today + offset)
target_date = (datetime.now() + timedelta(days=i)).strftime("%Y-%m-%d")
results["daily_forecasts"][target_date] = d_high
break
else:
# 记录所有可用字段,方便调试
available_keys = [
@@ -556,6 +564,20 @@ class WeatherDataCollector:
except Exception as e:
logger.debug(f"MGM hourly failed: {e}")
# 4. Fallback for today_high (if daily forecast is missing it)
if "today_high" not in results:
# Try from current max
cur_max = results.get("current", {}).get("mgm_max_temp")
if cur_max is not None:
results["today_high"] = cur_max
logger.info(f"📋 MGM 每日预报: 使用当前测站最高温作为今日预报回退: {cur_max}°C")
elif "hourly" in results and results["hourly"]:
# Try from hourly
h_max = max((h["temp"] for h in results["hourly"] if h["temp"] is not None), default=None)
if h_max is not None:
results["today_high"] = h_max
logger.info(f"📋 MGM 每日预报: 使用小时预报最高温作为今日预报回退: {h_max}°C")
return results if "current" in results else None
except Exception as e:
logger.error(f"MGM API 请求失败 ({istno}): {e}")
+6 -1
View File
@@ -105,7 +105,7 @@ def _analyze(city: str, force_refresh: bool = False) -> Dict[str, Any]:
raw = _weather.fetch_all_sources(city, lat=lat, lon=lon)
om = raw.get("open-meteo", {})
metar = raw.get("metar", {})
mgm = raw.get("mgm", {})
mgm = raw.get("mgm") or {}
ens_raw = raw.get("ensemble", {})
mm = raw.get("multi_model", {})
risk = CITY_RISK_PROFILES.get(city, {})
@@ -412,6 +412,11 @@ def _analyze(city: str, force_refresh: bool = False) -> Dict[str, Any]:
if i < len(maxtemps) and maxtemps[i] is not None:
day_m["Open-Meteo"] = _sf(maxtemps[i])
# Add MGM per-day forecast
mgm_daily = mgm.get("daily_forecasts", {})
if d_str in mgm_daily:
day_m["MGM"] = _sf(mgm_daily[d_str])
d_val, d_winfo = None, ""
if day_m:
try: