feat: Introduce new ai_analyzer and trend_engine modules for comprehensive weather trend and AI analysis.

This commit is contained in:
2569718930@qq.com
2026-03-12 10:26:28 +08:00
parent 20d3e940e0
commit 0877efe0c3
2 changed files with 56 additions and 3 deletions
+10
View File
@@ -88,6 +88,15 @@ P1 **实况节奏**
- 连续2报创新高 → 升温未止;连续2报未创新高且斜率≤0 → 偏死盘。
- 升温出现在低辐射时段 → 可能有多因子叠加(平流/混合层/热岛),不可单因子归因。
P1.5 **高温时段约束(强制)**:
- 先读取输入里的峰值窗口状态(before / in_window / past)。
- 若状态是 before(尚未进入峰值窗口):
- 禁止给出“已确认底线/已锁定/大概率到顶”。
- 盘口结论必须是“上沿待确认”或“仍有上行变数”。
- 若状态是 in_window
- 允许谨慎偏空,但仍不能直接“锁定”;需强调继续观察后续报文是否再创新高。
- 只有状态是 past 且同时满足“连续未创新高+回落/抑制因子”,才可使用“已确认底线/锁定”。
P2 **阻碍因子**(需结合城市特性判断):
- 降水已出现(非trace) → 强压温。
- 高湿度+厚云层持续2报以上 → 压温可能有效,但阈值因城市(海洋型 vs 大陆型)而异,不可套用固定数值。
@@ -112,6 +121,7 @@ P4 **预报背景**(最低优先级):
- 🎯 置信度: [1-10]/10
3. **禁止输出分析框架本身**。不要输出 P0/P1/P2/P3/P4 的分析过程或标题。只输出上方三行格式,不要多余内容。
4. 若输入出现“尚未进入峰值窗口 / 距最热时段开始还有 / 状态=before”,盘口行必须包含“上沿待确认”或同义表达,且逻辑行必须明确“时间窗未到,不能锁定”。
"""
# Use proxy if configured
+46 -3
View File
@@ -175,6 +175,7 @@ def analyze_weather_trend(
recent_temps = metar.get("recent_temps", [])
trend_desc = ""
trend_direction = "unknown"
trend_display = ""
if len(recent_temps) >= 2:
temps_only = [t for _, t in recent_temps]
latest_val = temps_only[0]
@@ -194,7 +195,7 @@ def analyze_weather_trend(
[f"{t}{temp_symbol}@{tm}" for tm, t in recent_temps[:3]]
)
if all_same:
trend_desc = f"📉 温度停滞({trend_display},大概率到顶"
trend_desc = f"📉 温度暂时停滞({trend_display})。"
trend_direction = "stagnant"
elif all_rising and diff > 0:
trend_desc = f"📈 仍在升温({trend_display})。"
@@ -206,16 +207,28 @@ def analyze_weather_trend(
trend_desc = f"📊 温度波动中({trend_display})。"
trend_direction = "mixed"
elif diff == 0:
trend_desc = f"📉 温度持平(最近两条都是 {latest_val}{temp_symbol})。"
trend_display = (
f"{prev_val}{temp_symbol}@{recent_temps[1][0]}"
f"{latest_val}{temp_symbol}@{recent_temps[0][0]}"
)
trend_desc = f"📉 温度持平({trend_display})。"
trend_direction = "stagnant"
elif diff > 0:
trend_display = (
f"{prev_val}{temp_symbol}@{recent_temps[1][0]}"
f"{latest_val}{temp_symbol}@{recent_temps[0][0]}"
)
trend_desc = f"📈 仍在升温({prev_val}{latest_val}{temp_symbol})。"
trend_direction = "rising"
else:
trend_display = (
f"{prev_val}{temp_symbol}@{recent_temps[1][0]}"
f"{latest_val}{temp_symbol}@{recent_temps[0][0]}"
)
trend_desc = f"📉 已开始降温({prev_val}{latest_val}{temp_symbol})。"
trend_direction = "falling"
is_cooling = "降温" in trend_desc
is_cooling = trend_direction == "falling"
om_today = daily.get("temperature_2m_max", [None])[0]
@@ -241,6 +254,28 @@ def analyze_weather_trend(
else:
peak_status = "before"
if trend_direction == "stagnant":
if peak_status == "before":
trend_desc = (
f"🕒 峰值窗口前温度暂时停滞({trend_display or '近2-3报持平'}),"
"尚不能据此判定到顶。"
)
elif peak_status == "in_window":
trend_desc = (
f"⏱️ 峰值窗口内温度停滞({trend_display or '近2-3报持平'}),"
"需继续观察后续是否再创新高。"
)
else:
trend_desc = (
f"📉 峰值窗口后温度停滞({trend_display or '近2-3报持平'}),"
"存在到顶迹象。"
)
elif trend_direction == "falling" and peak_status == "before":
trend_desc = (
f"📉 峰值窗口前出现回落({trend_display or '近2报回落'}),"
"暂不能单凭回落判定今日高温已锁定。"
)
# === Ensemble ===
ensemble = weather_data.get("ensemble", {})
ens_p10 = _sf(ensemble.get("p10"))
@@ -461,6 +496,10 @@ def analyze_weather_trend(
if len(peak_hours) > 1
else peak_hours[0]
)
ai_features.append(
f"🧭 峰值窗口判定: 当前 {local_hour:02d}:{local_minute:02d}"
f"预报最热窗口 {window},状态={peak_status}"
)
if local_hour <= last_peak_h:
if last_peak_h < 6:
ai_features.append("⚠️ <b>提示</b>:预测最热在凌晨,后续气温可能一路走低。")
@@ -475,6 +514,7 @@ def analyze_weather_trend(
remain_hrs = first_peak_h - local_hour_frac
if local_hour_frac > last_peak_h:
ai_features.append(f"⏱️ 状态: 预报峰值时段已过 ({window})。")
ai_features.append("✅ 判定约束: 峰值窗口已过,可结合回落幅度判断是否锁定。")
elif first_peak_h <= local_hour_frac <= last_peak_h:
remain_in_window = last_peak_h - local_hour_frac
if remain_in_window < 1:
@@ -485,12 +525,15 @@ def analyze_weather_trend(
ai_features.append(
f"⏱️ 状态: 正处于预报最热窗口 ({window})内,距窗口结束约 {remain_in_window:.1f}h。"
)
ai_features.append("⚠️ 判定约束: 窗口内即使停滞,也需后续2报确认未再创新高。")
elif remain_hrs < 1:
ai_features.append(
f"⏱️ 状态: 距最热时段开始还有约 {int(remain_hrs * 60)} 分钟 ({window}),尚未进入峰值窗口。"
)
ai_features.append("🚫 判定约束: 峰值窗口前禁止判定‘已锁定/已确认底线’。")
else:
ai_features.append(f"⏱️ 状态: 距最热时段开始还有约 {remain_hrs:.1f}h ({window})。")
ai_features.append("🚫 判定约束: 峰值窗口前禁止判定‘已锁定/已确认底线’。")
# === AI fact features ===
if cur_temp is not None: