feat: add weekly reward loop, i18n support, and scan terminal dashboard components

This commit is contained in:
2569718930@qq.com
2026-05-27 07:50:05 +08:00
parent 2670e2f8ee
commit 79d94bed5f
14 changed files with 786 additions and 76 deletions
+52 -8
View File
@@ -22,6 +22,7 @@ except Exception:
from src.data_collection.city_registry import CITY_REGISTRY
from src.data_collection.weather_sources import WeatherDataCollector
from src.utils.telegram_i18n import copy_text, normalize_push_language, telegram_push_language
TARGET_CITIES: List[str] = [
"beijing",
@@ -73,6 +74,14 @@ def _env_int(name: str, default: int, min_val: int = 0) -> int:
return default
def _daily_report_language() -> str:
return telegram_push_language(
"DAILY_WEATHER_REPORT_LANGUAGE",
"TELEGRAM_PUSH_LANGUAGE",
"POLYWEATHER_TELEGRAM_PUSH_LANGUAGE",
)
def _fetch_cma_forecast(city_key: str) -> Optional[Dict[str, Any]]:
"""Scrape today's forecast from weather.com.cn (CMA)."""
code = CMA_CITY_CODES.get(city_key)
@@ -158,13 +167,14 @@ def _fetch_city_data(
collector: WeatherDataCollector, city_key: str
) -> Optional[Dict[str, Any]]:
name = CITY_NAME_ZH.get(city_key, city_key)
info = CITY_REGISTRY.get(city_key)
name_en = str((info or {}).get("name") or city_key.title())
# 1. Try CMA first for weather description
cma = _fetch_cma_forecast(city_key)
# 2. Get Open-Meteo data for temperature fallback
om_high = None
info = CITY_REGISTRY.get(city_key)
if info:
try:
results = collector.fetch_all_sources(
@@ -209,6 +219,7 @@ def _fetch_city_data(
return {
"city": city_key,
"name": name,
"name_en": name_en,
"weather": weather or "?",
"forecast_high": forecast_high,
}
@@ -235,12 +246,40 @@ def _wmo_to_weather(code: Any) -> str:
return ""
def _build_ai_prompt(cities_data: List[Dict[str, Any]], report_date: str) -> str:
lines = [f"今天是 {report_date}。请用自然亲切的中文写一段天气日报。\n"]
lines.append("城市天气数据:")
def _build_ai_prompt(
cities_data: List[Dict[str, Any]],
report_date: str,
language: Optional[str] = None,
) -> str:
language = normalize_push_language(language or _daily_report_language())
if language == "zh":
lines = [f"今天是 {report_date}。请用自然亲切的中文写一段天气日报。\n"]
lines.append("城市天气数据:")
for c in cities_data:
lines.append(f"{c['name']}{c['weather']},最高{c['forecast_high']}")
lines.append("\n要求:每城一行播报,城市名<b>加粗</b>,开头问候,禁止结尾废话。")
return "\n".join(lines)
if language == "en":
lines = [f"Today is {report_date}. Write a concise Telegram weather briefing in English.\n"]
lines.append("City weather data:")
for c in cities_data:
lines.append(
f"{c.get('name_en') or c['city'].title()}: weather={c['weather']}, high={c['forecast_high']}°C"
)
lines.append("\nRequirements: one line per city, bold city names with <b>, start with a short greeting, no generic closing.")
return "\n".join(lines)
lines = [f"Today is {report_date}. Write a bilingual Telegram weather briefing.\n"]
lines.append("City weather data:")
for c in cities_data:
lines.append(f"{c['name']}{c['weather']},最高{c['forecast_high']}")
lines.append("\n要求:每城一行播报,城市名<b>加粗</b>,开头问候,禁止结尾废话。")
lines.append(
f"{c.get('name_en') or c['city'].title()} / {c['name']}: weather={c['weather']}, high={c['forecast_high']}°C"
)
lines.append(
"\nRequirements: one line per city, English first then Chinese in the same line, "
"bold city names with <b>, start with a short bilingual greeting, no generic closing."
)
return "\n".join(lines)
@@ -352,8 +391,9 @@ def _runner(bot: Any, config: Dict[str, Any]) -> None:
time.sleep(60)
continue
language = _daily_report_language()
report_date = now.strftime("%m月%d")
prompt = _build_ai_prompt(cities_data, report_date)
prompt = _build_ai_prompt(cities_data, report_date, language=language)
report_text = _call_ai(prompt)
if not report_text:
@@ -363,7 +403,11 @@ def _runner(bot: Any, config: Dict[str, Any]) -> None:
continue
try:
report_text += "\n\n⚠️ 以上为粗略预测,仅供参考。"
report_text += "\n\n" + copy_text(
language,
"⚠️ Rough forecast only. For reference.",
"⚠️ 以上为粗略预测,仅供参考。",
)
bot.send_message(
FORUM_CHAT_ID,
report_text,