feat: Add database-backed user and subscription management, update project architecture documentation, and outline technical debt.

This commit is contained in:
2569718930@qq.com
2026-03-06 19:10:05 +08:00
parent ce2a553e08
commit 14838fde4d
7 changed files with 696 additions and 495 deletions
+148 -183
View File
@@ -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.
<p align="center">
<img src="docs/images/demo_ankara.png" alt="PolyWeather Demo - Ankara Live Analysis" width="420">
@@ -18,203 +22,164 @@ PolyWeather is a multi-source weather analysis and quantification tool. It aggre
<em>🗺️ Interactive Web Map: Real-time global monitoring with rich data visualization</em>
</p>
---
## 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
+148 -184
View File
@@ -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
- 后端 APIVPS 上的 FastAPI
- 机器人与预警循环:VPS 上的 Telegram Bot
FastAPI 旧静态网页已经移除。Vercel 是唯一网页入口。
<p align="center">
<img src="docs/images/demo_ankara.png" alt="PolyWeather 效果展示 - 安卡拉实时分析" width="420">
@@ -18,204 +22,164 @@ PolyWeather 是一款多模型气象分析与量化工具。它通过聚合高
<em>🗺️ 交互式网页地图:全球城市实时监控与丰富的数据可视化</em>
</p>
---
## 当前功能
## ✨ 核心功能
- 多源天气采集
- 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
+41 -1
View File
@@ -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"
"示例: <code>/city 伦敦</code>"
"示例: <code>/city 伦敦</code>\n"
"💡 <i>提示: 在群内发言可获得积分,积分可用于后续解锁高级版。</i>"
)
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 = "🏆 <b>PolyWeather 活跃度排行榜</b>\n"
rank_text += "────────────────────\n"
for i, entry in enumerate(leaderboard):
medal = ["🥇", "🥈", "🥉", " ", " "][i] if i < 5 else " "
rank_text += f"{medal} {entry['username'][:12]}: <b>{entry['points']}</b> 点\n"
if user_info:
rank_text += "────────────────────\n"
rank_text += (
f"👤 <b>我的状态:</b>\n"
f"└ 积分: <code>{user_info['points']}</code>\n"
f"└ 发言: <code>{user_info['message_count']}</code> 次"
)
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()
+128 -22
View File
@@ -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
+82 -83
View File
@@ -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
+40 -22
View File
@@ -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://<your-fastapi-host>
```
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://<your-fastapi-host>`
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
+109
View File
@@ -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()]