From 14838fde4dfaa4b484c8d8c639e813f5dda920d5 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Fri, 6 Mar 2026 19:10:05 +0800 Subject: [PATCH] feat: Add database-backed user and subscription management, update project architecture documentation, and outline technical debt. --- README.md | 331 +++++++++++++++++------------------- README_ZH.md | 332 +++++++++++++++++-------------------- bot_listener.py | 42 ++++- docs/COMMERCIALIZATION.md | 150 ++++++++++++++--- docs/TECH_DEBT.md | 165 +++++++++--------- frontend/README.md | 62 ++++--- src/database/db_manager.py | 109 ++++++++++++ 7 files changed, 696 insertions(+), 495 deletions(-) create mode 100644 src/database/db_manager.py diff --git a/README.md b/README.md index ff9a7b8e..ded9310e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ -# 🌡️ PolyWeather: Intelligent Weather Quant Analysis Bot +# PolyWeather -[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/yangyuan-zhen/PolyWeather) +PolyWeather is a weather intelligence system built around live airport observations, multi-model forecasts, DEB blending, and Telegram alert delivery. -PolyWeather is a multi-source weather analysis and quantification tool. It aggregates high-precision forecasts, real-time airport METAR observations, a math-based probability engine, and AI-driven decision support to provide deep insights for weather-related risk assessment and data-driven decision making. +Current production layout: + +- Frontend: Next.js on Vercel +- Backend API: FastAPI on VPS +- Bot / alert loop: Telegram bot on VPS + +The old FastAPI static web page has been removed. Vercel is the only web entry point.

PolyWeather Demo - Ankara Live Analysis @@ -18,203 +22,164 @@ PolyWeather is a multi-source weather analysis and quantification tool. It aggre 🗺️ Interactive Web Map: Real-time global monitoring with rich data visualization

---- +## Features -## ✨ Core Features +- Multi-source weather aggregation + - Open-Meteo + - METAR live observations + - MGM official data for Ankara + - Multi-model highs such as ECMWF / GFS / ICON / GEM / JMA when available +- DEB blended forecast + - Dynamic weighting based on recent model error +- City dashboard + - Global city list + - City detail panel + - Nearby station map markers + - Trend chart + - Multi-model comparison + - Daily forecast table +- Telegram proactive alerts + - Ankara Center reached DEB + - Momentum spike + - Forecast breakthrough + - Advection / nearby lead station signal +- Late-day suppression + - If the local daily high has likely already passed and the market is cooling off, active alerts are downgraded to status only and are not pushed -### 1. 🌐 Interactive Web Map Dashboard +## Alert Rules -- **Global Overview**: Real-time Leaflet-based dark-themed map pinpointed to official Polymarket settlement airport coordinates. -- **Progressive Background Loading**: Intelligently fetches multi-source data across all cities without hitting API rate limits. -- **Rich Visualization**: Chart.js-powered temperature trends with METAR scatter overlay, multi-model comparison bars, Gaussian probability distribution, and dynamic risk badges. -- **Zoom-based Intelligence**: Map automatically filters minor cities (e.g., Atlanta/Ankara) and local station labels at lower zoom levels to maintain clarity, showing only major global hubs when zoomed out. -- **Technical Guide Interface**: Features an interactive on-map technical guide explaining DEB prediction curves, probability bands, and risk factors. -- **Cinematic Interaction & Sync**: City selection triggers a smooth fly-to zoom animation. The **Multi-Model Forecast** panel automatically synchronizes with the selected day in the 5-day forecast table, showing historical model performance and future projections. -- **Forced Sync & Cache Control**: For specific regions like Ankara, the dashboard supports a 60-second real-time cache TTL with a manual "Force Refresh" button to bypass global caches and fetch the absolute latest MGM/METAR data. -- **Dual-Engine Architecture**: Runs concurrently with the Telegram bot via a FastAPI backend, sharing the same data collection, analysis logic (`analyze_weather_trend`), and AI prompt pipeline. +Implemented rules: -### 2. 🧬 Dynamic Ensemble Blending (DEB Algorithm) +- `ankara_center_deb_hit` + - Only uses `Ankara (Bolge/Center)` station / `istNo=17130` + - This is the official Ankara center station used for the Center signal +- `momentum_spike` + - 30-minute slope exceeds the configured threshold +- `forecast_breakthrough` + - Current observed temperature is above the highest available major model high by margin +- `advection` + - Nearby station leads the airport station and wind regime supports warm advection -The system automatically tracks the historical performance of weather models (ECMWF, GFS, ICON, GEM, JMA) per city: +Suppression rule: -- **Error-Based Weighting**: Dynamically adjusts model weights based on their Mean Absolute Error (MAE) over the past 7 days. Lower error = higher weight. -- **Blended Forecast**: Provides a bias-corrected "DEB Blended High Temperature" recommendation. -- **Multi-Source Training**: Integrates official regional sources (like Turkey's MGM) into the training pipeline alongside international models (ECMWF, GFS, etc.). -- **Accuracy Tracking**: Use the `/deb` command to view DEB's historical settlement hit rate and MAE, compared against individual models. -- **Auto-Cleanup**: Only retains the last 14 days of records to prevent unbounded data growth. +- `peak_passed_guard` + - No active push if the city's local peak has already passed, enough time has elapsed, and the current temperature has materially rolled over from the day's high -### 3. 🎲 Math Probability Engine (Settlement Probability) +Push dedupe rule: -Automatically computes the probability for each possible settlement integer using a Gaussian distribution: +- Same city + same trigger type only pushes once while still active +- It can push again only after the signal clears and re-arms +- Cooldown still applies at city level -- **Reality-Anchored μ**: When actual max temperature is significantly below forecasts during/after the peak window (forecast bust), μ anchors on the observed max instead of failed predictions. Otherwise, uses a weighted average of DEB/multi-model median (70%) and ensemble median (30%). -- **Standard Deviation σ — Three-Layer Pipeline**: - 1. **Ensemble Base**: σ = (P90-P10) / 2.56 - 2. **MAE Floor**: Uses DEB's historical MAE as σ minimum—prevents ensembles from underestimating true uncertainty - 3. **Shock Score Amplifier**: σ × (1 + 0.5 × shock_score) when weather is changing rapidly -- **Time Decay**: Before peak σ×1.0 → During peak σ×0.7 → After peak σ×0.3 -- **Observed Floor**: Temperatures below the current METAR max WU value are excluded -- **Dead Market Override**: When a dead market is confirmed, probability collapses to 100% at the settled value +## Data Semantics -#### 💥 Shock Score: Weather Disruption Soft Scorer (0~1) +Alert message fields: -Evaluates environmental stability from the last 4 METAR observations. Higher = more unstable = wider σ: +- `实测 / Now` + - Uses `METAR current.temp` first + - Falls back to `MGM current.temp` if METAR current temperature is unavailable +- `时间 / Time` + - `local`: city local clock time + - `observed`: observation time attached to the current reading -| Component | Weight | Trigger | -| :-------------------- | :----- | :---------------------------------------------------------------- | -| Wind Direction Change | 0~0.4 | Angle difference × wind speed amplifier (weak winds downweighted) | -| Cloud Cover Jump | 0~0.35 | Cloud code escalation (FEW→BKN, etc.) | -| Pressure Change | 0~0.25 | >2hPa change within 2 hours | +## Deployment -### 4. 🤖 AI Deep Analysis (Groq LLaMA 3.3 70B) +### Backend / bot on VPS -Feeds all weather data into LLaMA 70B, analyzed via a **P0→P4 Priority Chain**: +Requirements: -- **P0 Forecast Bust Detection** (highest priority): Graded severity (light/medium/heavy) when actual temps diverge from forecasts. Requires slope + wind/cloud verification before declaring settlement locked. "Bust ≠ locked" — still checks for second-wave warming. -- **P1 Real-Time Rhythm**: 2 consecutive METAR highs → still warming; 2 non-highs with slope ≤ 0 → dead market. Low-radiation warming → multi-factor (advection/mixing layer/heat island), no single-factor attribution. -- **P2 Inhibitors** (city-aware): Precipitation → strong suppression. High humidity + thick clouds sustained 2+ reports → possible suppression, but thresholds vary by city type (maritime vs. continental). Single factor insufficient. -- **P3 Probability Cross-Check**: References settlement probability for consistency check with P1. Contradictions explained with deviation rationale. -- **P4 Forecast Background**: DEB/forecasts for ceiling estimation; silenced when actuals significantly deviate. -- **Single Source of Truth**: Both web and Telegram bot share the same `analyze_weather_trend` function and `get_ai_analysis` prompt — identical context, identical decisions. -- **High Availability**: Auto-retry + fallback model degradation (70B → 8B). Proxy support for restricted networks. +- Docker +- Docker Compose +- `.env` -### 5. ⏱️ Real-time Airport Observations (Zero-Cache METAR) - -- **Precise Timing**: Extracts actual observation time from raw METAR text (`rawOb`), not the API's rounded `reportTime`. Accurate to the minute. -- **Live Passthrough**: Bypasses CDN caching via dynamic headers and randomized timestamps to obtain first-hand METAR/MGM reports. -- **Settlement Warning**: Automatically calculates the rounding boundary for integer-based settlement (X.5 line). -- **MGM Primary (Ankara)**: For Turkish cities like Ankara, PolyWeather uses official MGM data as a primary source for both real-time observations and 5-day hourly forecasts, ensuring maximum local accuracy. -- **Anomaly Filtering**: Automatically filters out -9999 sentinel values to prevent garbage data in output. - -### 6. 📈 Historical Data Collection - -- Includes `fetch_history.py` to retrieve up to 3 years of hourly historical weather data (temperature, humidity, radiation, pressure, 10+ dimensions), providing data foundation for future ML models (XGBoost/MOS). - ---- - -## ⚡ Deployment - -### Requirements - -- **Python 3.11+** or **Docker & Docker Compose** -- **Environment Variables**: Set parameters in your `.env` file (copy from `.env.example`). - -### 🐳 Docker Deployment (Recommended) - -The easiest and most stable way to deploy without system dependency conflicts. - -1. **Clone and configure** - ```bash - git clone https://github.com/yangyuan-zhen/PolyWeather.git - cd PolyWeather - cp .env.example .env - # Edit .env to add TELEGRAM_BOT_TOKEN, GROQ_API_KEY, etc. - nano .env - ``` -2. **Start the service in the background** - ```bash - docker-compose up -d --build - ``` -3. **View live logs** - ```bash - docker-compose logs -f - ``` - -### 💻 Traditional VPS Deployment - -1. Install dependencies: `pip install -r requirements.txt` -2. Configure your `.env` file. -3. Use the included `update.sh` script for one-click updates and restarts for both the Telegram Bot and the Web Map: - -```bash -# Run the script to update code and restart both services in the background -./update.sh -``` - -_(Note: The `update.sh` script automatically fetches the latest code, kills old processes, clears ports, and launches both `bot_listener.py` and `web/app.py` via `nohup`.)_ - ---- - -## 🕹️ Bot Commands - -| Command | Description | -| :------------------ | :---------------------------------------------------------------------------------------------------------------------------------- | -| `/city [city_name]` | Get weather analysis, settlement probabilities, METAR tracking, and AI insights. (Includes "Bölge/Center" detail for Ankara). | -| `/deb [city_name]` | View DEB accuracy: daily hit/miss breakdown, bias analysis (underestimate/overestimate), model MAE comparison, trading suggestions. | -| `/id` | View the Chat ID of the current conversation. | -| `/help` | Display help information. | - -### Supported Cities - -`lon` (London), `par` (Paris), `ank` (Ankara), `nyc` (New York), `chi` (Chicago), `dal` (Dallas), `mia` (Miami), `atl` (Atlanta), `sea` (Seattle), `tor` (Toronto), `sel` (Seoul), `ba` (Buenos Aires), `wel` (Wellington), etc. - ---- - -## 🏗️ Architecture - -```mermaid -graph TD - User[User] -->|Query| Bot["bot_listener.py (Core Scheduler)"] - User -->|Browser| Web["web/app.py (FastAPI)"] - - subgraph Data Acquisition - Bot --> Collector[WeatherDataCollector] - Web --> Collector - Collector --> OM[Open-Meteo Forecast/Ensemble] - Collector --> MM[Multi-Model ECMWF/GFS/ICON/GEM/JMA] - Collector --> METAR["Live Airport METAR (rawOb)"] - Collector --> MGM["MGM Official (Ankara)"] - end - - subgraph Algorithm Layer - Collector --> Peak[Peak Hour Prediction] - Collector --> DEB[DEB Dynamic Weighting] - DEB --> DB[(daily_records Database)] - Peak --> Prob["Probability Engine (Reality-Anchored μ)"] - Collector --> Prob - METAR --> Shock[Shock Score] - Shock --> Prob - Collector --> Logic["Settlement Boundary / Dead Market"] - end - - subgraph Shared Analysis - Bot --> ATF["analyze_weather_trend()"] - Web --> ATF - ATF --> AI["Groq LLaMA 70B (P0→P4)"] - end - - AI -->|Market Call + Logic + Confidence| Bot - AI -->|Market Call + Logic + Confidence| Web -``` - ---- - -## 💡 Trading Tips - -1. **Real-time Rhythm First**: AI analysis follows P0→P4 priority. If live METAR trends (P1) conflict with math probabilities (P3), always prioritize the live trend. -2. **Watch Settlement Probabilities**: Based on Gaussian models, direction is most certain when a temperature has > 70% probability while P1 rhythm is flat. -3. **Reference DEB Bias**: Use `/deb` to check for systematic bias. If a city is consistently "underestimated," habitually bid one WU notch higher. -4. **Identify Dead Market Signals**: When the system declares a "Dead Market," probability collapses to 100% at the settled value. Warming power is exhausted. -5. **Mind the Boundaries**: When the observed high is near X.5 (e.g., 7.50°C), be wary of rounding up due to tiny fluctuations. -6. **Forecast Bust Awareness**: When the AI reports a forecast bust (especially medium/heavy grade), all model predictions have lost reference value. Focus exclusively on METAR actuals. - ---- - -## 🛠️ Development & Testing - -Run unit tests for the core trend engine and probability models: - -```bash -python -m pytest tests/test_trend_engine.py -v -``` - -Deploying updates to the server: +Deploy: ```bash git pull -./update.sh +docker-compose up -d --build ``` ---- +Main services: -_Updated 2026-03-05_ +- `polyweather_bot` +- `polyweather_web` + +The FastAPI service is now API-only. It does not serve a static website. + +### Frontend on Vercel + +The Vercel project uses the `frontend` directory as root. + +After pushing to Git, Vercel deploys automatically. + +## Environment Variables + +Minimum practical set: + +```env +TELEGRAM_BOT_TOKEN=... +TELEGRAM_CHAT_ID=... +GROQ_API_KEY=... +POLYWEATHER_MAP_URL=https://polyweather-pro.vercel.app/ +WEB_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,https://polyweather-pro.vercel.app +``` + +Push tuning: + +```env +TELEGRAM_ALERT_PUSH_ENABLED=true +TELEGRAM_ALERT_PUSH_INTERVAL_SEC=300 +TELEGRAM_ALERT_PUSH_COOLDOWN_SEC=3600 +TELEGRAM_ALERT_MIN_TRIGGER_COUNT=2 +TELEGRAM_ALERT_MIN_SEVERITY=medium +TELEGRAM_ALERT_CITIES=ankara,london,paris,seoul,toronto,buenos aires,wellington,new york,chicago,dallas,miami,atlanta,seattle,lucknow,sao paulo,munich +``` + +Recommended: + +- Use `3600` seconds cooldown for production paid groups unless you explicitly want more aggressive alerting + +## Bot Commands + +Supported user commands: + +- `/city [city]` +- `/deb [city]` +- `/id` +- `/help` + +`/tradealert` has been removed. Alerts are proactive push only. + +## Architecture + +```mermaid +graph TD + User[Telegram User] --> Bot[bot_listener.py] + User2[Web User] --> Vercel[Next.js on Vercel] + Vercel --> API[FastAPI API on VPS] + Bot --> API + API --> Collector[WeatherDataCollector] + Collector --> OM[Open-Meteo] + Collector --> METAR[METAR] + Collector --> MGM[MGM] + Collector --> MM[Multi-model sources] + API --> DEB[DEB blending] + API --> Alerts[Alert engine] + Alerts --> Bot +``` + +## Testing + +Quick checks used in development: + +```bash +python -m py_compile src/analysis/market_alert_engine.py src/utils/telegram_push.py web/app.py bot_listener.py +node --check frontend/public/static/app.js +npm run build --prefix frontend +``` + +If you want to run pytest, install it first. + +## Status + +Last updated: 2026-03-06 diff --git a/README_ZH.md b/README_ZH.md index 11d39c7b..58d0b093 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -1,10 +1,14 @@ -# 🌡️ PolyWeather: 智能天气量化分析机器人 +# PolyWeather -[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/yangyuan-zhen/PolyWeather) +PolyWeather 是一套围绕实时机场观测、多模型预报、DEB 融合和 Telegram 主动推送构建的天气情报系统。 -PolyWeather 是一款多模型气象分析与量化工具。它通过聚合高精度气象预报、实时机场 METAR 观测,并引入数学概率模型与 AI 决策支持,为气象风险评估和数据驱动的交易决策提供深度洞察。 +当前生产架构: + +- 前端:Vercel 上的 Next.js +- 后端 API:VPS 上的 FastAPI +- 机器人与预警循环:VPS 上的 Telegram Bot + +FastAPI 旧静态网页已经移除。Vercel 是唯一网页入口。

PolyWeather 效果展示 - 安卡拉实时分析 @@ -18,204 +22,164 @@ PolyWeather 是一款多模型气象分析与量化工具。它通过聚合高 🗺️ 交互式网页地图:全球城市实时监控与丰富的数据可视化

---- +## 当前功能 -## ✨ 核心功能 +- 多源天气采集 + - Open-Meteo + - METAR 实时观测 + - 安卡拉官方 MGM 数据 + - ECMWF / GFS / ICON / GEM / JMA 等多模型最高温 +- DEB 融合预报 + - 基于近期误差动态调权 +- 网页仪表盘 + - 全球监控城市列表 + - 城市详情面板 + - 周边站点地图标记 + - 今日趋势图 + - 多模型对比 + - 多日预报表 +- Telegram 主动预警 + - Ankara Center 达到 DEB + - 动量突变 + - 预测突破 + - 暖平流 / 周边站联动 +- 晚盘压制逻辑 + - 当地高温大概率已经兑现且开始回落时,预警降级为状态快照,不主动推送 -### 1. 🌐 交互式网页地图面板 +## 预警规则 -- **全球纵览**:基于 Leaflet 的暗黑全屏实时地图,直接采用官方结算机场经纬度进行追踪与显示。 -- **渐进式数据流加载**:进图后智能在后台无感知拉取,不触发 API 频率限制。 -- **数据可视化**:Chart.js 温度走势图叠加 METAR 实测散点,多模型对比条形图,高斯概率分布条,实时风险等级色彩系统。 -- **智能缩放过滤**:地图会根据缩放等级自动隐藏次要城市(如亚特兰大、安卡拉)和局部观测点标签,以保持全局视野清晰,仅在放大时显示细节。 -- **内置技术指南**:新增交互式技术手册面板,详细解释 DEB 预测曲线、概率区间及各类风险因子。 -- **镜头与日期联动**:点击城市平滑飞入面板。**多模型预报区域**会根据“逐日预报”选中的日期自动刷新,支持查看未来 5 天各模型的历史表现与融合预测值。 -- **强制同步与缓存控制**:针对安卡拉等重点区域,Web 端支持 60 秒极速缓存 TTL,并提供手动“强制刷新”按钮,可穿透全局缓存获取最及时的 MGM/METAR 实测数据。 -- **周边测站热力图**:不仅追踪目标机场,还能并发抓取目标城市周边 20~50 公里内的所有气象站实测。通过地图上的“微型标签”可视化城市热岛效应与锋面推进,辅助判断冷空气过境的时间差。 -- **双引擎共生**:FastAPI 后端与 Telegram Bot 共享同一份分析逻辑(`analyze_weather_trend`)和 AI Prompt 管线。 +当前启用的规则: -### 2. 🧬 动态权重集合预报 (DEB 算法) +- `ankara_center_deb_hit` + - 只使用 `Ankara (Bolge/Center)` 站点,`istNo=17130` + - 这是安卡拉 Center 信号唯一认可的官方站点 +- `momentum_spike` + - 30 分钟温度斜率超过阈值 +- `forecast_breakthrough` + - 当前实测温度高于主流模型最高值,并超过安全边际 +- `advection` + - 周边站领先升温,且风向与暖平流传播方向匹配 -系统会自动追踪各个气象模型(ECMWF, GFS, ICON, GEM, JMA)在特定城市的历史表现: +压制规则: -- **误差加权**:根据过去 7 天的平均绝对误差(MAE),动态调整各模型的权重。误差越小的模型,话语权越大。 -- **融合预报**:给出经过历史偏差修正后的"DEB 融合最高温"建议值。 -- **多源训练集成**:将区域性官方数据源(如土耳其 MGM)同步纳入 DEB 训练管线,与 ECMWF、GFS 等国际模型共同参与权重博弈。 -- **准确率追踪**:通过 `/deb` 命令查看 DEB 融合预测的历史结算命中率和 MAE,并与各个单一模型对比。 -- **自动清理**:只保留最近 14 天的记录,防止数据无限增长。 +- `peak_passed_guard` + - 当地高点已经过去、间隔足够长、且温度已从日内高点明显回落时,不再主动推送 -### 3. 🎲 数学概率引擎 (Settlement Probability) +去重规则: -基于集合预报的正态分布拟合,自动计算每个结算整数温度的概率: +- 同一城市、同一 trigger type,只会在激活时推送一次 +- 只有信号先解除,再重新触发,才允许再次推送 +- 同时仍保留城市级 cooldown -- **实况锚定 μ**:当实测最高温在峰值窗口期间/之后显著低于预报中位数(预报崩盘),μ 直接锚定在实测值上,而非失败的预报。正常情况下使用 DEB/多模型中位数(70%)和集合中位数(30%)的加权平均。 -- **标准差 σ 三层修正管线**: - 1. **集合基础**:σ = (P90-P10) / 2.56 - 2. **MAE 兜底**:用 DEB 历史 MAE 作为 σ 下限——防止集合预报低估真实不确定性 - 3. **Shock Score 放宽**:σ × (1 + 0.5 × shock_score),气象突变时自动加宽 -- **时间衰减**:峰值前 σ×1.0 → 峰值窗口 σ×0.7 → 峰值后 σ×0.3 -- **实测过滤**:已实测 WU 值以下的候选自动排除 -- **死盘覆盖**:确认死盘后,概率直接坍缩为结算值 100% +## 数据语义 -#### 💥 Shock Score:气象突变软评分 (0~1) +预警文案中的字段: -用近 4 条 METAR 报文的风向/云量/气压变化评估环境稳定性,越高 = 越不稳定 = σ 放宽: +- `实测` + - 优先使用 `METAR current.temp` + - 如果 METAR 当前温度不可用,再退回 `MGM current.temp` +- `时间` + - `当地`:城市本地当前时间 + - `观测`:这条实测温度对应的观测时间 -| 分项 | 权重 | 触发条件 | -| :------- | :----- | :------------------------------------ | -| 风向变化 | 0~0.4 | 角度差 × 风速放大系数(弱风降权避噪) | -| 云量阶跃 | 0~0.35 | FEW→BKN 等云码跳变 | -| 气压变化 | 0~0.25 | 2h 内气压差 > 2hPa | +## 部署 -### 4. 🤖 AI 深度分析 (Groq LLaMA 3.3 70B) +### VPS 后端 / 机器人 -将全部气象数据投喂给 LLaMA 70B,按 **P0→P4 分析框架** 决策: +要求: -- **P0 预报失准检测**(最高优先级):分级失准(轻/中/重),根据偏差幅度自动标记。"失准 ≠ 已定局"——还需检查斜率 + 风云条件。支持二次抬升判断。 -- **P1 实况节奏**:连续 2 报创新高 → 升温未止;连续 2 报未创新高且斜率 ≤ 0 → 偏死盘。低辐射升温 → 可能多因子叠加(平流/混合层/热岛),不做单因子归因。 -- **P2 阻碍因子**(需结合城市特性判断):降水 → 强压温。高湿度 + 厚云层持续 2 报以上 → 可能压温,但阈值因城市类型(海洋 vs 大陆)而异。单因子不足以断定。 -- **P3 概率与一致性校验**:参考结算概率分布,与 P1 实况做交叉检查。矛盾时以实况为准并说明偏离原因。 -- **P4 预报背景**(最低优先级):可参考 DEB/预报做上沿评估。实测显著偏离时禁止引用。 -- **统一分析源**:Web 和 Telegram Bot 共用同一个 `analyze_weather_trend` 函数和 `get_ai_analysis` 提示词——完全相同的上下文,完全相同的决策。 -- **高可用保障**:自动重试 + 备用模型降级(70B → 8B)。支持代理配置。 +- Docker +- Docker Compose +- `.env` -### 5. ⏱️ 实时机场观测 (Zero-Cache METAR) - -- **精确时间**:从 METAR 原始报文 (`rawOb`) 中提取真实观测时间,精确到分钟。 -- **实时穿透**:通过动态请求头和随机时间戳绕过 CDN 缓存,获取机场第一手 METAR/MGM 报文。 -- **结算预警**:自动计算结算边界(X.5 进位线),提醒潜在波动。 -- **MGM 官方直连 (安卡拉)**:针对安卡拉,PolyWeather 已将 MGM 提升为一级数据源,同步采集实时观测数据与 5 天逐小时预报,确保本地精度最大化。 -- **异常过滤**:自动过滤 -9999 等哨兵值,避免垃圾数据污染输出。 - -### 6. 📈 历史数据采集 - -- 提供 `fetch_history.py` 脚本,可一键获取各城市过去 3 年的小时级历史气象数据(温度、湿度、辐射、气压等 10+ 维度),为后续机器学习模型(XGBoost/MOS)提供数据基础。 - ---- - -## ⚡ 部署说明 - -### 环境要求 - -- **Python 3.11+** 或 **Docker & Docker Compose** -- **环境变量**: 在 `.env` 中设置关键参数(参考 `.env.example`)。 - -### 🐳 Docker 部署 (推荐) - -最简单、稳定的部署方式,避免系统依赖冲突。 - -1. **克隆项目并配置环境** - ```bash - git clone https://github.com/yangyuan-zhen/PolyWeather.git - cd PolyWeather - cp .env.example .env - # 编辑 .env 文件填入 TELEGRAM_BOT_TOKEN 和 GROQ_API_KEY 等 - nano .env - ``` -2. **后台一键启动服务** - ```bash - docker-compose up -d --build - ``` -3. **查看实时日志** - ```bash - docker-compose logs -f - ``` - -### 💻 传统 VPS 部署方案 - -1. 安装依赖: `pip install -r requirements.txt` -2. 配置 `.env` 文件。 -3. 利用项目中已包含的 `update.sh` 实现机器人和网站的双轨后台一键重启: - -```bash -# 每次代码变更后,只需在 VPS 执行此命令 -./update.sh -``` - -_(该脚本将自动执行 git 抓取、杀僵尸进程、解绑端口、并分别利用 nohup 重新唤醒 bot_listener.py 和 FastAPI app.py 服务。)_ - ---- - -## 🕹️ 机器人指令 - -| 指令 | 说明 | -| :--------------- | :--------------------------------------------------------------------------------------- | -| `/city [城市名]` | 获取深度气象分析、结算概率、实测追踪及 AI 决策建议。(安卡拉支持显示市区 Center 细节)。 | -| `/deb [城市名]` | 查看 DEB 准确率:逐日命中明细、偏差分析(低估/高估)、模型 MAE 对比、交易建议。 | -| `/id` | 查看当前对话的 Chat ID。 | -| `/help` | 显示说明信息。 | - -### 支持城市示例 - -`lon`(伦敦)、`par`(巴黎)、`ank`(安卡拉)、`nyc`(纽约)、`chi`(芝加哥)、`dal`(达拉斯)、`mia`(迈阿密)、`atl`(亚特兰大)、`sea`(西雅图)、`tor`(多伦多)、`sel`(首尔)、`ba`(布宜诺斯艾利斯)、`wel`(惠灵顿) 等。 - ---- - -## 🏗️ 系统架构 - -```mermaid -graph TD - User[用户] -->|查询指令| Bot["bot_listener.py (核心调度器)"] - User -->|浏览器| Web["web/app.py (FastAPI)"] - - subgraph 数据获取层 - Bot --> Collector[WeatherDataCollector] - Web --> Collector - Collector --> OM[Open-Meteo 预报/集合] - Collector --> MM[多模型 ECMWF/GFS/ICON/GEM/JMA] - Collector --> METAR["机场实时 METAR (rawOb)"] - Collector --> MGM["MGM 官方直连 (安卡拉)"] - end - - subgraph 算法层 - Collector --> Peak[峰值时段预测] - Collector --> DEB[DEB 动态权重融合] - DEB --> DB[(每日记录数据库)] - Peak --> Prob["概率引擎 (实况锚定μ)"] - Collector --> Prob - METAR --> Shock[Shock Score 突变评分] - Shock --> Prob - Collector --> Logic["结算边界 / 死盘检测"] - end - - subgraph 共享分析层 - Bot --> ATF["analyze_weather_trend()"] - Web --> ATF - ATF --> AI["Groq LLaMA 70B (P0→P4)"] - end - - AI -->|盘口 + 逻辑 + 置信度| Bot - AI -->|盘口 + 逻辑 + 置信度| Web -``` - ---- - -## 💡 交易提示 - -1. **实况节奏优先**:AI 分析遵循 P0→P4 优先级。如果实况趋势(P1)与数学概率(P3)冲突,以实况走势为准。 -2. **紧盯结算概率**:概率引擎基于数学模型,当某个温度概率 > 70% 且 P1 节奏持平时,方向最为明确。 -3. **参考 DEB 偏差**:通过 `/deb` 查看城市的系统性偏差。如果某个城市经常"低估",交易时应看高 1 个 WU 档位。 -4. **识别死盘信号**:系统判定"死盘"时,概率会直接坍缩为结算值 100%。升温动力彻底枯竭。 -5. **注意结算边界**:实测最高温接近 X.5 时,微小波动可能导致进位,需防范"偷鸡"。 -6. **预报崩盘意识**:当 AI 标记预报失准(尤其中/重级),所有模型预测已失去参考价值,需专注 METAR 实测。 - ---- - -## 🛠️ 开发与测试 - -运行核心分析引擎和概率模型的单元测试: - -```bash -python -m pytest tests/test_trend_engine.py -v -``` - -部署代码更新到服务器: +部署命令: ```bash git pull -./update.sh +docker-compose up -d --build ``` ---- +主要服务: -_更新于 2026-03-05_ +- `polyweather_bot` +- `polyweather_web` + +现在的 FastAPI 只提供 API,不再承载网页静态资源。 + +### Vercel 前端 + +Vercel 项目根目录使用 `frontend`。 + +代码推送后,Vercel 会自动部署。 + +## 环境变量 + +最小可用集合: + +```env +TELEGRAM_BOT_TOKEN=... +TELEGRAM_CHAT_ID=... +GROQ_API_KEY=... +POLYWEATHER_MAP_URL=https://polyweather-pro.vercel.app/ +WEB_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,https://polyweather-pro.vercel.app +``` + +预警推送调优: + +```env +TELEGRAM_ALERT_PUSH_ENABLED=true +TELEGRAM_ALERT_PUSH_INTERVAL_SEC=300 +TELEGRAM_ALERT_PUSH_COOLDOWN_SEC=3600 +TELEGRAM_ALERT_MIN_TRIGGER_COUNT=2 +TELEGRAM_ALERT_MIN_SEVERITY=medium +TELEGRAM_ALERT_CITIES=ankara,london,paris,seoul,toronto,buenos aires,wellington,new york,chicago,dallas,miami,atlanta,seattle,lucknow,sao paulo,munich +``` + +生产环境建议: + +- 付费群默认使用 `3600` 秒 cooldown,避免同一城市短时间内刷屏 + +## 机器人命令 + +当前保留的命令: + +- `/city [city]` +- `/deb [city]` +- `/id` +- `/help` + +`/tradealert` 已移除。预警只支持主动推送。 + +## 架构 + +```mermaid +graph TD + User[Telegram 用户] --> Bot[bot_listener.py] + User2[网页用户] --> Vercel[Next.js on Vercel] + Vercel --> API[FastAPI API on VPS] + Bot --> API + API --> Collector[WeatherDataCollector] + Collector --> OM[Open-Meteo] + Collector --> METAR[METAR] + Collector --> MGM[MGM] + Collector --> MM[多模型数据源] + API --> DEB[DEB 融合] + API --> Alerts[预警引擎] + Alerts --> Bot +``` + +## 测试 + +开发时常用快速检查: + +```bash +python -m py_compile src/analysis/market_alert_engine.py src/utils/telegram_push.py web/app.py bot_listener.py +node --check frontend/public/static/app.js +npm run build --prefix frontend +``` + +如果要跑 pytest,请先安装 pytest。 + +## 状态 + +最后更新:2026-03-06 diff --git a/bot_listener.py b/bot_listener.py index d6854b73..70bcd7ea 100644 --- a/bot_listener.py +++ b/bot_listener.py @@ -14,6 +14,7 @@ from src.utils.telegram_push import start_trade_alert_push_loop # type: ignore from src.data_collection.weather_sources import WeatherDataCollector # type: ignore # noqa: E402 from src.data_collection.city_risk_profiles import get_city_risk_profile # type: ignore # noqa: E402 from src.analysis.deb_algorithm import calculate_dynamic_weights, update_daily_record # noqa: E402 +from src.database.db_manager import DBManager def analyze_weather_trend(weather_data, temp_symbol, city_name=None): @@ -31,6 +32,7 @@ def start_bot(): return bot = telebot.TeleBot(token) + db = DBManager() weather = WeatherDataCollector(config) start_trade_alert_push_loop(bot, config) @@ -41,8 +43,10 @@ def start_bot(): "可用指令:\n" "/city [城市名] - 查询城市天气预测与实测\n" "/deb [城市名] - 查看 DEB 融合预测准确率\n" + "/points - 查看你的积分与排行榜\n" "/id - 获取当前聊天的 Chat ID\n\n" - "示例: /city 伦敦" + "示例: /city 伦敦\n" + "💡 提示: 在群内发言可获得积分,积分可用于后续解锁高级版。" ) bot.reply_to(message, welcome_text, parse_mode="HTML") @@ -54,6 +58,29 @@ def start_bot(): parse_mode="HTML", ) + @bot.message_handler(commands=["points", "rank", "top"]) + def show_points(message): + """显示当前用户的积分及排行榜""" + user = message.from_user + user_info = db.get_user(user.id) + + leaderboard = db.get_leaderboard(limit=5) + rank_text = "🏆 PolyWeather 活跃度排行榜\n" + rank_text += "────────────────────\n" + for i, entry in enumerate(leaderboard): + medal = ["🥇", "🥈", "🥉", " ", " "][i] if i < 5 else " " + rank_text += f"{medal} {entry['username'][:12]}: {entry['points']} 点\n" + + if user_info: + rank_text += "────────────────────\n" + rank_text += ( + f"👤 我的状态:\n" + f"└ 积分: {user_info['points']}\n" + f"└ 发言: {user_info['message_count']} 次" + ) + + bot.send_message(message.chat.id, rank_text, parse_mode="HTML") + @bot.message_handler(commands=["deb"]) def deb_accuracy(message): """查询 DEB 融合预测的历史准确率""" @@ -705,6 +732,19 @@ def start_bot(): logger.error(f"查询失败: {e}\n{traceback.format_exc()}") bot.reply_to(message, f"❌ 查询失败: {e}") + @bot.message_handler(func=lambda message: True, content_types=['text']) + def track_activity(message): + """全量监听消息,用于记录群内发言积分(非指令消息)""" + if message.text.startswith('/'): + return + + user = message.from_user + username = user.username or user.first_name or f"User_{user.id}" + db.upsert_user(user.id, username) + + # 增加积分 (5秒冷却防刷屏,每个自然发言给 1 分) + db.add_message_activity(user.id, points_to_add=1) + logger.info("🤖 Bot 启动中...") bot.infinity_polling() diff --git a/docs/COMMERCIALIZATION.md b/docs/COMMERCIALIZATION.md index 6f6b0bf4..ff509b37 100644 --- a/docs/COMMERCIALIZATION.md +++ b/docs/COMMERCIALIZATION.md @@ -1,35 +1,141 @@ -# PolyWeather 商业化技术升级草案 +# Commercialization Plan -## 1. 核心目标 +## Product Direction -将 PolyWeather 从单人工具转型为支持多用户的 SaaS 产品。 +PolyWeather is being positioned as a paid weather intelligence product built around: +- Web dashboard subscription +- Telegram paid group subscription +- Fast, rules-based weather alerting +- High-confidence Ankara specialization -## 2. 架构调整 (Architecture Upgrade) +Current pricing target: +- Web dashboard: $5 / month +- Telegram paid group: $1 / month -### 2.1 用户与订阅系统 (Auth & Sub) +Current payment direction under discussion: +- Polygon / USDC -- **前端**: 增加 Login 模态框,支持 Telegram 一键登录。 -- **后端 (FastAPI)**: 增加用户数据库 (`users` 表),存储 `telegram_id`, `subscription_status`, `expiry_date`。 -- **权限中间件**: 拦截未经授权的实时 API 请求。 +Important current state: +- Polymarket market-price integration has been removed from the codebase +- The current product focuses on weather intelligence, not exchange/orderbook execution data -### 2.2 网页功能增强 (Web Premium) +## Production Architecture -- **实时性**: 付费用户 30s 刷新一次,免费用户 15min 刷新。 -- **专业视图**: 增加各模型历史 MAE (平均绝对误差) 实时排行榜,让用户知道安卡拉今天该信 MGM 还是 GFS。 -- **推送配置**: 允许用户在网页端订阅特定城市的“突破预警”。 +### Web +- Next.js frontend on Vercel +- Public URL: `https://polyweather-pro.vercel.app/` +- FastAPI backend serves API only -### 2.3 电报机器人深度集成 (Bot Monitization) +### Backend +- FastAPI on VPS +- Shared analysis layer for web and bot +- City data cache in-process -- **邀请管理**: 自动生成独一无二的支付链接或入群链接。 -- **私人简报**: 每小时向 $1 订阅用户私聊发送其关注城市的“结算风险报告”。 +### Telegram +- Bot runs on VPS +- Paid group receives proactive alerts +- Push engine includes dedupe, cooldown, and late-day suppression -## 3. 支付方案 (Payment Integration) +## Alert Product Strategy -- **Polygon (USDC)**: 完美契合 Polymarket 生态。 -- **逻辑**: 用户转账 -> Webhook 回调 -> 自动激活账户权限。 +Current alert strategy is weather-first: +- Ankara Center reached DEB +- Momentum spike +- Forecast breakthrough +- Advection / nearby lead station -## 4. 商业化阶段 +Operational controls already implemented: +- Same city + same trigger type only pushes once while active +- City-level cooldown +- Peak-passed suppression for late-day rollover -- **Phase 1 (Beta)**: 邀请制内测,验证安卡拉等重点城市的数据准确性。 -- **Phase 2 (MVP)**: 上线手动支付激活模式(人工进群)。 -- **Phase 3 (Full)**: 全自动 Web3 登录 + USDC 支付 + 自动入群。 +Ankara special handling: +- Center signal only uses `Ankara (Bolge/Center)` / `17130` +- This should remain a product differentiator and be documented clearly in sales copy + +## Recommended Subscription Structure + +### Tier A: Telegram Group +- Price: $1 / month +- Value proposition: + - Real-time proactive weather alerts + - Fast anomaly delivery + - Focused operational signal, minimal clutter +- Suggested restrictions: + - No raw API access + - No historical analytics export + - No advanced chart controls + +### Tier B: Web Dashboard +- Price: $5 / month +- Value proposition: + - Full city dashboard + - Trend and nearby-station visualization + - Multi-model comparison + - Historical view +- Suggested restrictions: + - View-only unless future premium tools are added + +### Bundle Option +- Optional future bundle: Web + Group +- Use only if conversion data shows users want both together + +## Payment Roadmap + +### Phase 1: Manual Ops +- User pays manually +- Operator manually activates web access / Telegram access +- Lowest engineering cost, fastest launch + +### Phase 2: Polygon / USDC Automation +- Generate unique deposit address or payment intent +- Confirm on-chain payment +- Activate subscription automatically +- Telegram bot issues one-time group invite link + +### Phase 3: Full Subscription Management +- Renewal reminders +- Grace period handling +- Automatic expiry / revocation +- Self-serve billing status page + +## Recommended Near-Term Roadmap + +### Step 1: Stabilize Current Product +- Finish cleaning docs and deployment flow +- Keep Vercel as the only web entry point +- Keep backend API-only +- Tune Telegram cooldown and trigger quality + +### Step 2: Launch Manual Paid Beta +- Start with a small paid Telegram group +- Start web dashboard on invite basis +- Track which alert types users actually value + +### Step 3: Add Access Control +- Web login and session layer +- Subscription table in backend +- Telegram membership verification + +### Step 4: Add Polygon / USDC Collection +- Payment detection +- Subscription activation +- One-time Telegram invite issuance + +## Metrics To Track + +Minimum metrics before scaling: +- Alert-to-action usefulness feedback +- Daily active dashboard users +- Telegram retention after first payment cycle +- Most valuable cities by engagement +- False-positive complaint rate for alerts + +## Constraints To Keep In Mind + +- The current system is strongest in weather intelligence, not execution plumbing +- Ankara is a differentiated niche and should be treated as premium signal inventory +- Over-pushing alerts will destroy paid-group value faster than under-pushing +- Payment automation should come after alert quality is operationally stable + +Last updated: 2026-03-06 diff --git a/docs/TECH_DEBT.md b/docs/TECH_DEBT.md index 32f78856..61a1ad63 100644 --- a/docs/TECH_DEBT.md +++ b/docs/TECH_DEBT.md @@ -1,116 +1,115 @@ -# PolyWeather 技术债与演进路线 +# Technical Debt -> 最后更新:2026-03-05 +Last updated: 2026-03-06 ---- +## Current State -## 一、当前完成度:约 65% +Overall system status: usable and deployable. -### ✅ 已经可用 +Stable pieces: +- Multi-source weather collection +- DEB forecast blending +- Web dashboard on Vercel +- FastAPI API backend +- Telegram proactive push loop +- Alert dedupe and cooldown +- Late-day peak suppression -| 模块 | 状态 | 说明 | -| ---------------- | ------------ | -------------------------------------------------------------- | -| 多源数据采集 | **可用** | Open-Meteo / ECMWF / GFS / ICON / GEM / JMA / METAR / MGM | -| DEB 动态融合预报 | **可用** | 误差加权 + 自学习 + 冷启动处理 | -| 概率引擎 | **基本可用** | Gaussian 拟合 + Shock Score + 时间衰减 + 实况锚定 μ + 死盘覆盖 | -| AI 决策 | **基本可用** | P0→P4 分级框架 + 预报失准分级 + 高可用降级 | -| Telegram Bot | **稳定运行** | 当前最成熟的交互端 | -| Web 仪表盘 | **基本可用** | 全功能地图 + 面板 + 图表,支持 5rd/多模型联动与强制刷新 | -| 部署 | **可用** | Docker + 传统 VPS 双通道,`update.sh` 一键部署 | +Recently removed: +- Old FastAPI static web page +- Polymarket market-price integration +- `/tradealert` preview command -### ⚠️ 真实能力边界 +## High-Priority Debt -1. **概率引擎的 μ 是手工规则(非统计学习的)**。70/30 加权 + 实况锚定的逻辑在多数情况下"看起来合理",但没有经过回测校准,在极端天气下的准确性无统计保障。 -2. **AI 决策是"结构化的猜测"**。Prompt 再精巧,底层仍是 LLM 概率续写。AI 有时自相矛盾,置信度是自评的,不代表真实概率。 -3. **Shock Score 是启发式指标**。风向/云量/气压权重(0.4/0.35/0.25)未经回归验证。 -4. **DEB 自学习窗口只有 7 天**,无法捕捉季节性趋势。 -5. **Web 端图表已对齐实测**。利用 MGM 逐小时预报和实测数据,安卡拉等重点城市的日内曲线已实现预报与实况的实时拟合叠加。 +### 1. Bot orchestration is still too centralized +`bot_listener.py` is operational, but too much runtime behavior is still coordinated from a single entrypoint. ---- +Impact: +- Harder to test +- Harder to evolve subscription logic +- Harder to isolate push bugs -## 二、技术债 +Suggested direction: +- Keep moving push and analysis concerns into `src/utils` and `src/analysis` -### 🔴 高优先级 (✅ 本期已全部清理) +### 2. Alert transparency needs better operator visibility +The system now pushes the correct trigger types more conservatively, but group operators still need better evidence lines. -| 问题 | 影响 | 状态 | -| -------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------- | -| `bot_listener.py` 过于臃肿 | 单文件 1200 行,混杂数据处理、概率计算、趋势分析、AI 调用。可维护性极差 | ✅ **已拆分**:提取近 500 行核心逻辑至 `src/analysis/trend_engine.py` | -| Web 与 Bot 概率引擎重复 | 两端各有独立的概率计算代码。AI 上下文已统一,但概率分布仍各算各的 | ✅ **已统一**:Web 端已完全删除自己的引擎,直接复用 `trend_engine` 输出结果 | -| 无测试覆盖 | 概率引擎、DEB 算法、趋势分析等核心逻辑没有单元测试,任何改动只能人肉验证 | ✅ **已覆盖**:建立 `pytest` 机制,编写 15 个用例完全覆盖核心引擎逻辑 | +Impact: +- Hard to audit why a message fired +- Hard to distinguish strong vs weak advection calls -### 🟡 中优先级 +Suggested direction: +- Add a compact `依据 / Evidence` line to alert messages +- Expose raw trigger metrics in a debug API or operator log -| 问题 | 影响 | 建议 | -| ------------------ | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -| 无回测框架 | 无法用历史数据验证算法改动是否真的提升了准确率,改代码全凭直觉 | 用 `fetch_history.py` 的数据搭回测管线 | -| 硬编码阈值散落各处 | 死盘 (3°C/1.5°C)、forecast bust (2°C)、Shock Score 权重等直接写在业务代码里 | 提取到配置文件或 `constants.py` | -| MGM 数据源不稳定 | 经常 403,数据频率受限 | ✅ **已解决**:采用自定义 Header + 随机时间戳 + 5级 API 遍历抓取,稳定性大幅提升 | +### 3. No persistent application store for subscriptions +Current architecture is ready for commercialization planning, but there is no real subscription state model yet. -### 🟢 低优先级 +Impact: +- No paid access enforcement +- No renewal logic +- No expiry / access revocation -| 问题 | 影响 | 建议 | -| ----------------- | --------------------------------------------------- | -------------------------- | -| 缓存策略粗糙 | Web 端用简单 dict + 过期时间,无 LRU 或容量限制 | 引入 `cachetools` 或 Redis | -| 日志没有结构化 | loguru 直接 print,上线后难做分析和报警 | 改用 JSON 格式 + 集中收集 | -| CI badge 链接失效 | 已移除 GitHub Actions 但 README 之前还留着 CI badge | 已在本次文档更新中修复 | +Suggested direction: +- Add a database-backed subscription table before automating billing ---- +## Medium-Priority Debt -## 三、未完成功能 +### 4. Backtesting is still missing +The system has live rules, but no proper replay framework for validating whether rule changes improve quality. -| # | 功能 | 说明 | -| --- | ------------------- | ---------------------------------------------------------------- | -| 1 | 历史数据消费 | `fetch_history.py` 可采集 3 年数据,但没有任何模型在使用 | -| 2 | 结算自动对账 | 系统已支持通过 `/deb` 查看命中率,但尚未实现自动生成昨日总结推送 | -| 3 | 交易信号输出 | 系统只给分析建议,不输出可执行的交易信号 | -| 4 | Web 身份认证 | 任何人都可以访问 Web 面板 | -| 5 | 主动推送 | 预报崩盘或结算边界预警时不会主动通知用户 | -| 6 | 完整日内 METAR 走势 | `trend.recent` 只保留最近 4 条,无法展示完整日内观测曲线 | +Impact: +- Rule changes are hard to evaluate objectively +- Alert tuning is still partly manual ---- +Suggested direction: +- Build a replay harness from stored observations and forecasts -## 四、演进路线 +### 5. Thresholds remain code-defined +Important thresholds are still embedded in Python. -### 短期(1-2 周)— 偿还核心债务 +Examples: +- Momentum slope threshold +- Peak-passed rollback threshold +- Advection lead delta threshold +- Cooldown defaults -1. **拆分 `bot_listener.py`** - - 将 `analyze_weather_trend` 移到 `src/analysis/trend_engine.py` - - 将概率引擎移到 `src/analysis/probability.py` - - `bot_listener.py` 只保留 Telegram 交互逻辑 +Suggested direction: +- Extract to constants or structured config -2. **概率引擎统一** - - Web 端概率计算应直接调用共享模块的结果 - - 消除两份独立实现 +### 6. Frontend still uses a legacy shell inside Next +The production frontend is on Vercel, but the page is still driven by `public/legacy/index.html` plus static scripts. -3. **核心单元测试** - - 测试范围:μ/σ 计算、死盘判定、forecast bust 检测、DEB 权重计算 - - 不追求覆盖率,追求"改代码时有安全网" +Impact: +- Slower UI evolution +- Harder component-level reuse +- Harder design-system integration -### 中期(1-2 月)— 建立校验能力 +Suggested direction: +- Migrate the legacy dashboard into native Next components incrementally -4. **回测框架** - - 用历史数据跑"过去 90 天每天的 μ 偏差是多少" - - 这是证明概率引擎有效的唯一方式 +## Low-Priority Debt -5. **结算自动对账** - - 每天自动拉取合约实际结算结果 - - 与系统前一天的预测做比对,自动生成准确率报告 +### 7. Caching is simple in-process cache only +Current cache is sufficient for the current deployment size, but not ideal long term. -6. **推送机制** - - 检测到 forecast bust 或结算边界预警时主动推送 Telegram 通知 +Suggested direction: +- Move to Redis or another shared cache if multi-instance deployment is needed -### 长期(3+ 月)— 从规则到模型 +### 8. Test tooling is not fully provisioned everywhere +The repository has tests, but some environments still do not have `pytest` installed. -7. **MOS/XGBoost 替代手工 μ** - - 用历史 METAR + 模型预报训练后处理模型 - - 概率引擎从"合理的猜测"升级到"可校验的预测" +Impact: +- Harder to run full verification on every host -8. **多市场适配** - - 当前只针对温度合约 - - 扩展到降水、风速等需要重构分析框架 +Suggested direction: +- Standardize test dependencies in deployment and CI environments ---- +## Immediate Next Steps -## 五、一句话总结 - -> PolyWeather 目前最大的价值是**信息聚合和格式化**——把分散在多个 API 的气象数据整合成可快速消化的仪表盘。至于"预测准不准",诚实的回答是:**不知道,因为还没有建立衡量准确率的机制**。 +1. Add evidence lines to Telegram alerts +2. Finish cleaning backend naming after removal of old static web flow +3. Design subscription storage for commercialization +4. Start replay/backtest tooling for alert-quality tuning diff --git a/frontend/README.md b/frontend/README.md index ce15b96f..065f8d68 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,14 +1,27 @@ -# PolyWeather Frontend (Next.js) +# PolyWeather Frontend -Standalone web frontend for `polyweather.vercel.app`. +This directory is the only web frontend in production. + +Production URL: +- https://polyweather-pro.vercel.app/ ## Stack -- Next.js 14+ (App Router) +- Next.js App Router - Tailwind CSS - Lucide React -- shadcn/ui base components -- Leaflet (react-leaflet) +- shadcn/ui base layer +- Legacy dashboard shell loaded from `public/legacy/index.html` + +## Production Model + +- Vercel serves the web UI +- FastAPI on VPS serves API only +- The old FastAPI static website has been removed + +Current request flow: +- Browser -> Vercel frontend +- Vercel route handlers -> FastAPI API ## Local Development @@ -19,32 +32,37 @@ npm install npm run dev ``` -Default frontend URL: `http://localhost:3000` +Default local URL: +- http://localhost:3000 -## Backend API +## Required Environment Variable -Set `POLYWEATHER_API_BASE_URL` to your FastAPI service URL. - -Example: - -```bash -POLYWEATHER_API_BASE_URL=https://api.yourdomain.com +```env +POLYWEATHER_API_BASE_URL=https:// ``` -The frontend uses Next Route Handlers as a thin BFF layer: +Examples: +- `http://38.54.27.70:8000` +- `https://api.example.com` +## Route Handlers + +Thin BFF routes currently exposed by Next: - `GET /api/cities` -- `GET /api/city/:name` +- `GET /api/city/[name]` +- `GET /api/history/[name]` ## Vercel Deployment -1. Import this repo in Vercel. -2. Set **Root Directory** to `frontend`. -3. Add environment variable: - - `POLYWEATHER_API_BASE_URL=https://` -4. Deploy. +1. Import the repo into Vercel +2. Set Root Directory to `frontend` +3. Set `POLYWEATHER_API_BASE_URL` +4. Deploy ## Notes -- Backend CORS must allow `https://polyweather.vercel.app`. -- This is phase-1 split: map + city list + detail panel are migrated first. +- Backend CORS must allow `https://polyweather-pro.vercel.app` +- The page shell currently embeds the legacy dashboard HTML from `public/legacy/index.html` +- If you change files under `public/static`, deploy to Vercel to make them live + +Last updated: 2026-03-06 diff --git a/src/database/db_manager.py b/src/database/db_manager.py new file mode 100644 index 00000000..bf9c583c --- /dev/null +++ b/src/database/db_manager.py @@ -0,0 +1,109 @@ +import sqlite3 +import os +from datetime import datetime, timedelta +from typing import Optional, Dict, Any +from loguru import logger + +class DBManager: + def __init__(self, db_path: str = "polyweather.db"): + self.db_path = db_path + self._init_db() + + def _get_connection(self): + return sqlite3.connect(self.db_path) + + def _init_db(self): + """Create tables if they don't exist.""" + # Ensure directory exists + os.makedirs(os.path.dirname(self.db_path), exist_ok=True) + with self._get_connection() as conn: + conn.execute(""" + CREATE TABLE IF NOT EXISTS users ( + telegram_id INTEGER PRIMARY KEY, + username TEXT, + is_web_premium BOOLEAN DEFAULT 0, + web_expiry TIMESTAMP, + is_group_premium BOOLEAN DEFAULT 0, + group_expiry TIMESTAMP, + points INTEGER DEFAULT 0, + message_count INTEGER DEFAULT 0, + last_message_at TIMESTAMP, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + conn.commit() + logger.info("Database initialized successfully.") + + def get_user(self, telegram_id: int) -> Optional[Dict[str, Any]]: + with self._get_connection() as conn: + conn.row_factory = sqlite3.Row + cursor = conn.execute("SELECT * FROM users WHERE telegram_id = ?", (telegram_id,)) + row = cursor.fetchone() + if row: + user = dict(row) + now = datetime.now() + if user['web_expiry']: + expiry = datetime.fromisoformat(user['web_expiry']) + if expiry < now: + user['is_web_premium'] = False + if user['group_expiry']: + expiry = datetime.fromisoformat(user['group_expiry']) + if expiry < now: + user['is_group_premium'] = False + return user + return None + + def upsert_user(self, telegram_id: int, username: str): + with self._get_connection() as conn: + conn.execute(""" + INSERT INTO users (telegram_id, username) + VALUES (?, ?) + ON CONFLICT(telegram_id) DO UPDATE SET + username = excluded.username + """, (telegram_id, username)) + conn.commit() + + def add_message_activity(self, telegram_id: int, points_to_add: int = 1): + """Update message count and add points with simple anti-spam logic.""" + now = datetime.now() + with self._get_connection() as conn: + cursor = conn.execute("SELECT last_message_at FROM users WHERE telegram_id = ?", (telegram_id,)) + row = cursor.fetchone() + if row and row[0]: + last_at = datetime.fromisoformat(row[0]) + if (now - last_at).total_seconds() < 5: # 5 second cooldown + return False + + conn.execute(""" + UPDATE users + SET message_count = message_count + 1, + points = points + ?, + last_message_at = ? + WHERE telegram_id = ? + """, (points_to_add, now.isoformat(), telegram_id)) + conn.commit() + return True + + def set_premium(self, telegram_id: int, plan: str, months: int = 1): + expiry = datetime.now() + timedelta(days=30 * months) + col_is = f"is_{plan}_premium" + col_expiry = f"{plan}_expiry" + with self._get_connection() as conn: + conn.execute(f""" + UPDATE users + SET {col_is} = 1, {col_expiry} = ? + WHERE telegram_id = ? + """, (expiry.isoformat(), telegram_id)) + conn.commit() + logger.info(f"User {telegram_id} upgraded to {plan} premium until {expiry}") + + def get_leaderboard(self, limit: int = 10): + with self._get_connection() as conn: + conn.row_factory = sqlite3.Row + cursor = conn.execute(""" + SELECT username, points, message_count + FROM users + ORDER BY points DESC + LIMIT ? + """, (limit,)) + return [dict(row) for row in cursor.fetchall()]