feat: implement multi-source weather data collection for OpenWeatherMap, Visual Crossing, and NOAA METAR, including Polymarket settlement sources.

This commit is contained in:
2569718930@qq.com
2026-02-26 18:20:54 +08:00
parent bf530467ca
commit 766aa76b71
2 changed files with 88 additions and 18 deletions
+69 -18
View File
@@ -201,12 +201,51 @@ def analyze_weather_trend(weather_data, temp_symbol):
# === 核心判断:实测是否已超预报 ===
is_breakthrough = False
# METAR 趋势分析(最近 3-4 条报文)
recent_temps = metar.get("recent_temps", []) # [("15:00", 5), ("14:20", 5), ("14:00", 3)] 倒序
trend_desc = ""
if len(recent_temps) >= 2:
temps_only = [t for _, t in recent_temps] # 倒序:最新在前
latest_val = temps_only[0]
prev_val = temps_only[1]
diff = latest_val - prev_val
if len(temps_only) >= 3:
# 3 条以上:判断整体趋势
all_same = all(t == latest_val for t in temps_only[:3])
all_rising = all(temps_only[i] >= temps_only[i+1] for i in range(min(3, len(temps_only)) - 1))
all_falling = all(temps_only[i] <= temps_only[i+1] for i in range(min(3, len(temps_only)) - 1))
trend_display = "".join([f"{t}{temp_symbol}@{tm}" for tm, t in recent_temps[:3]])
if all_same:
trend_desc = f"📉 温度已停滞({trend_display}),大概率到顶。"
elif all_rising and diff > 0:
trend_desc = f"📈 仍在升温({trend_display})。"
elif all_falling and diff < 0:
trend_desc = f"📉 已开始降温({trend_display})。"
else:
trend_desc = f"📊 温度波动中({trend_display})。"
elif diff == 0:
trend_desc = f"📉 温度持平(最近两条都是 {latest_val}{temp_symbol})。"
elif diff > 0:
trend_desc = f"📈 仍在升温({prev_val}{latest_val}{temp_symbol})。"
else:
trend_desc = f"📉 已开始降温({prev_val}{latest_val}{temp_symbol})。"
if max_so_far is not None and forecast_high is not None:
if max_so_far > forecast_high + 0.5:
is_breakthrough = True
exceed_by = max_so_far - forecast_high
insights.append(f"🚨 <b>实测已超预报</b>:实测最高 {max_so_far}{temp_symbol} 超过了所有预报的天花板 {forecast_high}{temp_symbol},多了 {exceed_by:.1f}°!")
insights.append(f"💡 <b>建议</b>:预报已经不准了,实际温度比所有模型预测的都高,需要重新判断。")
# 合并为一条:事实 + 趋势(不给主观建议)
bt_msg = (
f"🚨 <b>实测已超预报</b>{max_so_far}{temp_symbol} 超过预报上限 "
f"{forecast_high}{temp_symbol}+{exceed_by:.1f}°)。"
)
if trend_desc:
bt_msg += f"\n{trend_desc}"
insights.append(bt_msg)
# === 结算取整分析 (Wunderground 四舍五入到整数) ===
if max_so_far is not None:
@@ -387,26 +426,38 @@ def analyze_weather_trend(weather_data, temp_symbol):
if analysis_wind is not None:
wd = analysis_wind
# 用趋势数据判断风的实际影响
if trend_desc:
# 从趋势中提取关键词
is_stagnant = "停滞" in trend_desc or "持平" in trend_desc
is_rising = "升温" in trend_desc
is_falling = "降温" in trend_desc
else:
is_stagnant = False
is_rising = False
is_falling = False
if 315 <= wd or wd <= 45:
insights.append(f"🌬️ <b>吹北风</b>{wind_source} {wd:.0f}°):从北方来的冷空气,会压制升温。")
effect = ""
if is_stagnant or is_falling:
effect = ",升温确实被压制"
elif is_rising:
effect = ",但温度仍在上升"
insights.append(f"🌬️ <b>吹北风</b>{wind_source} {wd:.0f}°):冷空气{effect}")
elif 135 <= wd <= 225:
gap_to_forecast = forecast_high - (max_so_far if max_so_far is not None else curr_temp)
if is_peak_passed and not is_breakthrough:
insights.append(f"🔥 <b>吹南风</b>{wind_source} {wd:.0f}°):南方的暖空气还在吹过来,但最热时段已过,后劲不足了。")
elif gap_to_forecast > 0.5 or is_breakthrough:
status = "温度还有继续上涨的空间" if not is_breakthrough else "可能把温度推得更高"
insights.append(f"🔥 <b>吹南风</b>{wind_source} {wd:.0f}°):南方的暖空气正在吹过来,{status}")
else:
insights.append(f"🔥 <b>吹南风</b>{wind_source} {wd:.0f}°):南方的暖空气正在吹过来,但温度已接近预报峰值")
effect = ""
if is_rising:
effect = ",温度仍在上升"
elif is_stagnant:
effect = ",但温度已停滞"
elif is_falling:
effect = ",但温度已开始下降"
insights.append(f"🔥 <b>吹南风</b>{wind_source} {wd:.0f}°):暖空气{effect}")
elif 225 < wd < 315:
if wd <= 260:
insights.append(f"🌬️ <b>吹西南风</b>{wind_source} {wd:.0f}°):带有一定暖湿气流,对升温有轻微帮助")
elif wd >= 280:
insights.append(f"🌬️ <b>吹西北风</b>{wind_source} {wd:.0f}°):偏冷的气流,会拖慢升温。")
else:
insights.append(f"🌬️ <b>吹西风</b>{wind_source} {wd:.0f}°):对温度影响不大,主要取决于日照和云量。")
dir_name = "西南风" if wd <= 260 else ("西北风" if wd >= 280 else "西风")
insights.append(f"🌬️ <b>吹{dir_name}</b>{wind_source} {wd:.0f}°)。")
elif 45 < wd < 135:
insights.append(f"🌬️ <b>吹东风</b>{wind_source} {wd:.0f}°):对温度影响较小,主要看日照和云量")
insights.append(f"🌬️ <b>吹东风</b>{wind_source} {wd:.0f}°)。")
except (TypeError, ValueError):
pass
+19
View File
@@ -279,17 +279,35 @@ class WeatherDataCollector:
except:
continue
# 3. 提取最近 4 条报文的温度(用于趋势分析)
recent_temps_raw = [] # [(local_time_str, temp_c), ...]
for obs in data[:4]: # data 已按时间倒序
obs_rt = obs.get("reportTime", "")
obs_temp = obs.get("temp")
if obs_temp is not None:
try:
ct = obs_rt.replace(" ", "T")
if not ct.endswith("Z"): ct += "Z"
rdt = datetime.fromisoformat(ct.replace("Z", "+00:00"))
local_rt = rdt + timedelta(seconds=utc_offset)
recent_temps_raw.append((local_rt.strftime("%H:%M"), obs_temp))
except:
continue
# 转换为单位
if use_fahrenheit:
temp = temp_c * 9 / 5 + 32 if temp_c is not None else None
max_so_far = max_so_far_c * 9 / 5 + 32 if max_so_far_c > -900 else None
dewp = dewp_c * 9 / 5 + 32 if dewp_c is not None else None
unit = "fahrenheit"
# 转换最近温度
recent_temps = [(t, round(v * 9 / 5 + 32, 1)) for t, v in recent_temps_raw]
else:
temp = temp_c
max_so_far = max_so_far_c if max_so_far_c > -900 else None
dewp = dewp_c
unit = "celsius"
recent_temps = [(t, v) for t, v in recent_temps_raw]
result = {
"source": "metar",
@@ -310,6 +328,7 @@ class WeatherDataCollector:
"altimeter": latest.get("altim"),
"clouds": latest.get("clouds", []),
},
"recent_temps": recent_temps, # 最近4条: [("15:00", 5), ("14:20", 5), ...]
"unit": unit,
}