Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 72 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,46 @@
# model.tracker

自动监控全球主流 AI 厂商的模型发布、定价、性能表现。每日更新。
**English** | [简体中文](README.zh-CN.md)

## 覆盖范围
Automatically tracks model releases, pricing, and performance across the world's major AI vendors. Updated daily.

**14 家厂商:**
## Coverage

- 海外:OpenAI · Anthropic · Google · Meta · Mistral · xAI · Cohere
- 国内:DeepSeek · 通义千问(阿里)· 智谱 GLM · 豆包(字节)· Kimi(Moonshot)· 百川 · 混元(腾讯)
**14 vendors:**

**3 类性能数据源:**
- International: OpenAI · Anthropic · Google · Meta · Mistral · xAI · Cohere
- China: DeepSeek · Qwen (Alibaba) · Zhipu GLM · Doubao (ByteDance) · Kimi (Moonshot) · Baichuan · Hunyuan (Tencent)

- LMSYS Chatbot Arena(人类盲测 Elo)
- Artificial Analysis(独立第三方测速 + 质量)
- 学术 benchmark(MMLU / GPQA / HumanEval / SWE-bench / MATH)
**3 kinds of performance data sources:**

## 架构
- LMSYS Chatbot Arena (human blind-test Elo)
- Artificial Analysis (independent third-party speed + quality benchmarks)
- Academic benchmarks (MMLU / GPQA / HumanEval / SWE-bench / MATH)

## Architecture

```
┌─────────────────────┐
│ GitHub Actions │ 每日 02:00 UTC cron
│ GitHub Actions │ daily 02:00 UTC cron
│ scrapers/run.py │
└──────────┬──────────┘
发现 + 自动晋升
discovery + auto-promote
┌──────────────────────────────────────────┐
│ discovery: 厂商官方 Models API (权威) │→ 未收录模型 自动入库
│ + benchmark 榜单 (噪声→仅记录)
│ discovery: vendor Models APIs (trusted) │→ unseen models auto-registered
│ + benchmark boards (noise→log)
└───────────────┬──────────────────────────┘
│ register_extra → 统一注册表 (catalog ∪ 自动发现)
采集
│ register_extra → unified registry (catalog ∪ auto-discovered)
scrape
┌──────────────────────────────────────────┐
│ vendor scrapers benchmarks LLM fallback │
│ (价格/规格) (Elo/跑分) (Claude Haiku)
│ (price/specs) (Elo/scores) (Claude Haiku)│
└───────────────┬──────────────────────────┘
归一化精确匹配 (model_registry) — 绝不错配
校验闸
normalized exact matching (model_registry) — never mismatch
validation gate
┌──────────────────────────────────────────┐
│ validation: 价格>3× / ELO>100 跳变 → 隔离防脏值覆盖
│ benchmark 覆盖骤降 → 漂移告警
│ validation: price >3× / ELO >100 jumps quarantined, no dirty writes
│ benchmark coverage drop alert
└───────────────┬──────────────────────────┘
┌────────────────┐
Expand All @@ -48,94 +50,94 @@
└────────┬───────┘
┌────────────────┐
│ Next.js ISR │ apps/web ( /health 数据健康页)
│ on Vercel CDN │ push→git 自动部署;数据靠 ISR 刷新
│ Next.js ISR │ apps/web (incl. /health data-health page)
│ on Vercel CDN │ push→git auto-deploy; data refreshes via ISR
└────────────────┘
```

**健壮性设计**(详见 `IMPLEMENTATION_CHECKLIST.md` 的"健壮性大修"章节):
**Robustness design** (see the "robustness overhaul" section in `IMPLEMENTATION_CHECKLIST.md`):

- **不漏新模型**:厂商官方 Models API 是权威信号,发现未收录模型即**自动入库**(稀疏元数据,价格/Elo 由采集层随后自动补,绝不编造)。arena/AA 榜单名是噪声,**永不自动收**、也不骚扰,仅在 `/health` 页可选查看。
- **不错配**:单一身份注册表(`core/model_registry.py`)从 catalog ∪ 自动发现派生,**归一化精确匹配**(受控地剥离 `-thinking`/日期等模式后缀,绝不剥 size/version),CI 强制无别名碰撞。一个模型只在一处定义。
- **防脏值**:异常闸隔离离谱跳变(曾导致价格来回跳的根因),同值持续 2 次才确认应用。
- **不静默失败**:匹配不上 = 登记为发现候选 + 漂移告警,全在 `/health` 暴露。
- **Never miss a new model**: vendor official Models APIs are the trusted signal — any unseen model is **auto-registered** (sparse metadata; price/Elo get filled in later by the scrape layer, never fabricated). Arena/AA leaderboard names are noise: **never auto-registered**, never nagging, only optionally viewable on `/health`.
- **Never mismatch**: a single identity registry (`core/model_registry.py`) derived from catalog ∪ auto-discovered models, with **normalized exact matching** (controlled stripping of `-thinking`/date-style suffixes only — size/version is never stripped). CI enforces zero alias collisions. Each model is defined in exactly one place.
- **No dirty values**: an anomaly gate quarantines wild jumps (the root cause of prices once flip-flopping); a value is only confirmed after appearing 2 consecutive times.
- **No silent failures**: an unmatched name is logged as a discovery candidate + drift alert — everything surfaces on `/health`.

## 目录结构
## Directory layout

```
apps/web/ Next.js 前端(含 /health 数据健康页)
scrapers/ Python 爬虫
vendors/ 每家厂商一个 module(catalog 驱动)
benchmarks/ LMSYS / Artificial Analysis / 学术
discovery/ 发现层:厂商官方 Models API 等可信源
apps/web/ Next.js frontend (incl. /health data-health page)
scrapers/ Python scrapers
vendors/ one module per vendor (catalog-driven)
benchmarks/ LMSYS / Artificial Analysis / academic
discovery/ discovery layer: trusted vendor Models APIs etc.
core/
model_registry.py 单一身份注册表(catalog ∪ 自动发现,精确匹配)
discovery.py 发现过滤 + 厂商推断(纯逻辑)
promotion.py 自动晋升:可信源 → 模型记录(纯逻辑)
validation.py 价格/ELO 异常闸(纯逻辑)
model_registry.py single identity registry (catalog ∪ auto-discovered, exact matching)
discovery.py discovery filtering + vendor inference (pure logic)
promotion.py auto-promotion: trusted source → model record (pure logic)
validation.py price/ELO anomaly gate (pure logic)
extractor / db / differ / registry
tests/ registry / discovery / validation / promotion 单测(CI)
alert_candidates.py 数据健康告警(隔离值)→ GitHub issue
supabase/migrations/ Postgres schema0001–0007
.github/workflows/ scrape-dailycron+ testpytest on PR
tests/ registry / discovery / validation / promotion unit tests (CI)
alert_candidates.py data-health alerts (quarantined values) → GitHub issue
supabase/migrations/ Postgres schema (0001–0007)
.github/workflows/ scrape-daily (cron) + test (pytest on PR)
```

## 本地开发
## Local development

### 前端
### Frontend

```bash
cd apps/web
npm install
cp ../../.env.example .env.local # 填入 SUPABASE_URL + SUPABASE_ANON_KEY
cp ../../.env.example .env.local # fill in SUPABASE_URL + SUPABASE_ANON_KEY
npm run dev
```

### 爬虫
### Scrapers

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r scrapers/requirements.txt
playwright install chromium

cp .env.example .env # 填入所有 KEY
python -m scrapers.run --dry-run # 跑一遍但不写库
python -m scrapers.run # 真跑
python -m scrapers.run --vendor openai # 只跑一家
python -m scrapers.run --skip-discovery # 跳过发现/自动晋升
pytest scrapers/tests/ # 跑单测(注册表/发现/校验/晋升)
cp .env.example .env # fill in all KEYs
python -m scrapers.run --dry-run # full run without writing to the DB
python -m scrapers.run # real run
python -m scrapers.run --vendor openai # single vendor only
python -m scrapers.run --skip-discovery # skip discovery/auto-promotion
pytest scrapers/tests/ # unit tests (registry/discovery/validation/promotion)
```

### Supabase

```bash
# https://supabase.com/dashboard 建项目,拿 URL + Service Key
# SQL Editor 按序执行所有 migration,再灌 seed
# supabase/migrations/0001_initial.sql 初始 6 + 视图 + RLS
# Create a project at https://supabase.com/dashboard, grab the URL + Service Key.
# Run all migrations in order in the SQL Editor, then load the seed:
# supabase/migrations/0001_initial.sql initial 6 tables + views + RLS
# supabase/migrations/0002_dedupe_benchmarks.sql
# supabase/migrations/0003_add_model_license.sql
# supabase/migrations/0004_discovery_candidates.sql 发现候选表
# supabase/migrations/0005_pending_changes.sql 异常隔离表
# supabase/migrations/0006_data_health_views.sql 脱敏错误视图
# supabase/migrations/0004_discovery_candidates.sql discovery candidates table
# supabase/migrations/0005_pending_changes.sql anomaly quarantine table
# supabase/migrations/0006_data_health_views.sql sanitized error views
# supabase/migrations/0007_auto_discovered.sql models.auto_discovered
# supabase/seed.sql
```

## 数据 schema
## Data schema

| / 视图 | 说明 |
| Table / view | Description |
|---|---|
| `vendors` | 厂商主数据(OpenAI / Anthropic / ... |
| `models` | 模型主数据,每个模型一行;`auto_discovered` 标记 API 自动晋升 |
| `prices` | 价格快照,追加写,保留全部历史 |
| `benchmark_scores` | 跑分快照,追加写 |
| `daily_snapshots` | 每日汇总 + 当日变化 JSON(含发现候选) |
| `discovery_candidates` | 发现层捞到、尚未收录的模型名(仅提案,按厂商分级) |
| `pending_changes` | 异常闸隔离的可疑值(同值持续 2 次自动确认应用) |
| `scrape_errors` | 爬虫错误日志(含漂移告警) |
| `models_overview` *(视图)* | 模型 + 当前价格 + Arena Elo 聚合,前端读取 |
| `recent_scrape_issues` *(视图)* | `scrape_errors` 脱敏投影(无 traceback/url),供 /health |
| `vendors` | Vendor master data (OpenAI / Anthropic / ...) |
| `models` | Model master data, one row per model; `auto_discovered` marks API auto-promotion |
| `prices` | Price snapshots, append-only, full history retained |
| `benchmark_scores` | Benchmark snapshots, append-only |
| `daily_snapshots` | Daily summary + that day's changes as JSON (incl. discovery candidates) |
| `discovery_candidates` | Model names surfaced by discovery but not yet registered (proposals only, tiered by vendor) |
| `pending_changes` | Suspicious values quarantined by the anomaly gate (auto-confirmed after 2 consecutive identical readings) |
| `scrape_errors` | Scraper error log (incl. drift alerts) |
| `models_overview` *(view)* | Models + current price + Arena Elo aggregate, read by the frontend |
| `recent_scrape_issues` *(view)* | Sanitized projection of `scrape_errors` (no traceback/url), for /health |

## Data sources & attribution

Expand Down
Loading
Loading