新增中国城市天气日报:AI 生成每日天气摘要并推送至 Telegram 论坛群 General 话题

- 新建 src/utils/daily_weather_report.py,覆盖 7 个中国城市(北京、上海、广州、成都、重庆、武汉、青岛)
- 复用 Open-Meteo + METAR 数据源,MiMo AI 生成自然语言日报
- 注册为 runtime_coordinator 独立后台循环,默认每日 8:00 Asia/Shanghai 发送
- 环境变量:DAILY_WEATHER_REPORT_ENABLED / _HOUR / _MINUTE / _TIMEZONE

Constraint: message_thread_id=0 发送到论坛群 General 子话题
Tested: ruff check pass, Python 语法验证通过
This commit is contained in:
2569718930@qq.com
2026-05-23 09:24:18 +08:00
parent f8f0d69e5c
commit f49a5bfbb2
2 changed files with 329 additions and 6 deletions
+58 -6
View File
@@ -89,6 +89,7 @@ class StartupCoordinator:
self._start_weekly_reward_loop(),
self._start_payment_event_loop(),
self._start_payment_confirm_loop(),
self._start_daily_weather_report_loop(),
]
self._runtime_status = RuntimeStatus(
started_at=datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC"),
@@ -157,7 +158,19 @@ class StartupCoordinator:
details = {
"mode": "airport-periodic",
"interval_sec": interval,
"cities": ["seoul", "busan", "tokyo", "ankara", "helsinki", "amsterdam", "istanbul", "paris", "hong kong", "lau fau shan", "taipei"],
"cities": [
"seoul",
"busan",
"tokyo",
"ankara",
"helsinki",
"amsterdam",
"istanbul",
"paris",
"hong kong",
"lau fau shan",
"taipei",
],
"chat_targets": len(chat_ids),
"window": "DEB proximity ≤3°C",
}
@@ -168,7 +181,9 @@ class StartupCoordinator:
configured_enabled=enabled,
details=details,
validation_error=validation_error,
starter=lambda: import_module("src.utils.telegram_push").start_high_freq_airport_push_loop(
starter=lambda: import_module(
"src.utils.telegram_push"
).start_high_freq_airport_push_loop(
self.bot,
self.config,
),
@@ -222,7 +237,9 @@ class StartupCoordinator:
settle_weekday = min(
7, max(1, _env_int("POLYWEATHER_WEEKLY_REWARD_SETTLE_WEEKDAY", 1))
)
settle_hour = min(23, max(0, _env_int("POLYWEATHER_WEEKLY_REWARD_SETTLE_HOUR", 0)))
settle_hour = min(
23, max(0, _env_int("POLYWEATHER_WEEKLY_REWARD_SETTLE_HOUR", 0))
)
settle_minute = min(
59, max(0, _env_int("POLYWEATHER_WEEKLY_REWARD_SETTLE_MINUTE", 5))
)
@@ -249,9 +266,9 @@ class StartupCoordinator:
configured_enabled=enabled,
details=details,
validation_error=validation_error,
starter=lambda: import_module("src.bot.weekly_reward_loop").start_weekly_reward_loop(
self.bot
),
starter=lambda: import_module(
"src.bot.weekly_reward_loop"
).start_weekly_reward_loop(self.bot),
)
def _start_payment_confirm_loop(self) -> LoopStatus:
@@ -318,6 +335,41 @@ class StartupCoordinator:
).start_payment_event_loop(),
)
def _start_daily_weather_report_loop(self) -> LoopStatus:
enabled = _env_bool("DAILY_WEATHER_REPORT_ENABLED", True)
chat_ids = get_telegram_chat_ids_from_env()
report_hour = _env_int("DAILY_WEATHER_REPORT_HOUR", 8)
report_minute = _env_int("DAILY_WEATHER_REPORT_MINUTE", 0)
tz_name = str(
os.getenv("DAILY_WEATHER_REPORT_TIMEZONE") or "Asia/Shanghai"
).strip()
details = {
"schedule": f"{report_hour:02d}:{report_minute:02d}",
"timezone": tz_name,
"cities": [
"beijing",
"shanghai",
"guangzhou",
"chengdu",
"chongqing",
"wuhan",
"qingdao",
],
"target": "forum_general_topic",
"chat_targets": len(chat_ids),
}
validation_error = None
return self._start_with_validation(
key="daily_weather_report",
label="中国城市天气日报",
configured_enabled=enabled,
details=details,
validation_error=validation_error,
starter=lambda: import_module(
"src.utils.daily_weather_report"
).start_daily_weather_report_loop(self.bot, self.config),
)
def render_runtime_status_html(status: RuntimeStatus) -> str:
lines = [