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", {}) open_meteo = weather_data.get("open-meteo", {})
metar = weather_data.get("metar", {}) metar = weather_data.get("metar", {})
mgm = weather_data.get("mgm", {}) mgm = weather_data.get("mgm") or {}
# 数值归一化 # 数值归一化
def _sf(v): def _sf(v):
+5
View File
@@ -60,6 +60,7 @@ def analyze_weather_trend(
metar = weather_data.get("metar", {}) metar = weather_data.get("metar", {})
open_meteo = weather_data.get("open-meteo", {}) open_meteo = weather_data.get("open-meteo", {})
mgm = weather_data.get("mgm") or {}
mb = weather_data.get("meteoblue", {}) mb = weather_data.get("meteoblue", {})
nws = weather_data.get("nws", {}) nws = weather_data.get("nws", {})
@@ -83,6 +84,10 @@ def analyze_weather_trend(
if nws.get("today_high") is not None: if nws.get("today_high") is not None:
current_forecasts["NWS"] = _sf(nws.get("today_high")) 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", {}) mm_forecasts = weather_data.get("multi_model", {}).get("forecasts", {})
for m_name, m_val in mm_forecasts.items(): for m_name, m_val in mm_forecasts.items():
if m_val is not None: if m_val is not None:
+26 -4
View File
@@ -506,16 +506,24 @@ class WeatherDataCollector:
if daily_resp.status_code == 200: if daily_resp.status_code == 200:
forecasts = daily_resp.json() forecasts = daily_resp.json()
if forecasts and isinstance(forecasts, list): if forecasts and isinstance(forecasts, list):
# Store today extra clearly
today = forecasts[0] today = forecasts[0]
high_val = today.get("enYuksekGun1") high_val = today.get("enYuksekGun1")
low_val = today.get("enDusukGun1") low_val = today.get("enDusukGun1")
if high_val is not None: if high_val is not None:
results["today_high"] = high_val results["today_high"] = high_val
results["today_low"] = low_val results["today_low"] = low_val
logger.info( logger.info(f"📋 MGM 每日预报: 今天的最高温 {high_val}°C")
f"📋 MGM 每日预报: 最高 {high_val}°C, 最低 {low_val}°C (from {forecast_url})"
) # Store all 5 days for multi_model_daily
break 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: else:
# 记录所有可用字段,方便调试 # 记录所有可用字段,方便调试
available_keys = [ available_keys = [
@@ -556,6 +564,20 @@ class WeatherDataCollector:
except Exception as e: except Exception as e:
logger.debug(f"MGM hourly failed: {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 return results if "current" in results else None
except Exception as e: except Exception as e:
logger.error(f"MGM API 请求失败 ({istno}): {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) raw = _weather.fetch_all_sources(city, lat=lat, lon=lon)
om = raw.get("open-meteo", {}) om = raw.get("open-meteo", {})
metar = raw.get("metar", {}) metar = raw.get("metar", {})
mgm = raw.get("mgm", {}) mgm = raw.get("mgm") or {}
ens_raw = raw.get("ensemble", {}) ens_raw = raw.get("ensemble", {})
mm = raw.get("multi_model", {}) mm = raw.get("multi_model", {})
risk = CITY_RISK_PROFILES.get(city, {}) 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: if i < len(maxtemps) and maxtemps[i] is not None:
day_m["Open-Meteo"] = _sf(maxtemps[i]) 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, "" d_val, d_winfo = None, ""
if day_m: if day_m:
try: try: