Files
climperor/AGENTS.md
T
vosonandCursor 9f484166d4 Add daily Feishu digest for dota2.refining.dev traffic.
Gitea Actions runs notify_site_traffic.py at 09:00 CST using Cloudflare GraphQL and a Feishu webhook (secrets from keyzoo).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-28 15:26:07 +08:00

179 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 协作说明(面向 AI 与贡献者)
本文件描述 **上分帝(Climperor** 的职责边界、代码布局与修改注意点。
## 项目是什么
Windows 上的 Dota 2 **天梯选将识别**工具:用 GSI 感知选将阶段,截屏后对顶栏 10 格做 OpenCV 模板匹配,输出双方阵容与选将时间线。
- 中文名:上分帝
- 英文名 / 仓库目录:Climperor / `climperor`
- 模板来源:**仅** Steam CDN 官方头像(`templates/cdn/`
- **已放弃** real 实拍模板库补充;不要再引入 `templates/real/` 或入库流水线
**上分帝 Web**`web/relations/`)是独立子项目:英雄克制/搭档、排行、物品、版本等内容站点,与局内选将识别解耦。文档与注释统称「上分帝 Web」,勿再称「关系预览」;历史路径/脚本名(如 `serve_relations.py``dist/relations/`)暂保留。
## 目录与模块
| 路径 | 职责 |
|------|------|
| `common.py` | 配置 IO、槽位几何、裁切、NCC 匹配、天梯遮罩、CDN 模板加载 |
| `recognize.py` | 单帧识别;`recognize_image()` 供会话复用 |
| `draft_session.py` | 整局选将跟踪、改判、皮肤规避策略 |
| `gsi_watch.py` / `gsi_setup.py` | GSI 监听与 cfg 安装 |
| `http_utils.py` | 所有 fetch 脚本共用的 HTTP 请求、图标下载、Valve datafeed 加载(统一 UA / 超时) |
| `fetch_patches.py` | 拉取近一年(默认 365 天,`--days`/`--since`)版本列表 + 逐版本 `patchnotes` 详情 → `data/patches.json`;构建 id→名称/图标的 `lookup` 并下载引用到的物品/技能图标(`--no-icons` 跳过;`--force` 重抓全量) |
| `fetch_cdn_templates.py` | 拉取 CDN 头像 + 生成 `data/heroes.json`(含基础属性/血蓝;保留已有 `aliases` |
| `relations.py` | 定性克制/搭档边读写与名称解析 |
| `import_relations_xlsx.py` | 从选将笔记 xlsx 种子导入 `data/relations.json` |
| `fetch_stratz.py` | 拉取 STRATZ 对位优势 / 搭档协同 → `data/stratz_matchups.json` / `data/synergies.json`(需 token`--mode matchups\|synergies`;供 `audit_relations.py` |
| `fetch_stratz_meta.py` | 拉取 STRATZ 各段位周胜率/上场率 + 分路统计 + 对位 Top → `data/stratz_hero_meta.json` / `data/stratz_matchup_tops.json`(需 token**仅上分帝 Web**;勿进 recommend / relations |
| `fetch_matchups.py` | 拉取 OpenDota 对位优势 → `data/matchups.json`(供 `audit_relations.py` 交叉审计) |
| `audit_relations.py` | OpenDota+STRATZ 交叉审计 `relations.json`,列出缺失英雄 |
| `recommend.py` | 定位局分路过滤;克/搭/补全网格标记;调用 `draft_archetypes` 做推进/全球流/缺口画像与短文案 |
| `draft_archetypes.py` | 规则阵容画像(推进/全球流/敌我缺口)+ `analysis` / `reasons` 文案(不接 AI |
| `serve_relations.py` | 上分帝 Web 本地开发服务(`web/relations/`;改 `data/*.json` 后刷新) |
| `export_relations_site.py` | 导出上分帝 Web 为纯静态站点 → `dist/relations/`data.json 快照 + 前端 + 图片;`SITE_VERSION` 常量与 `web/relations/config.js` 同步;`--ability-video-base` / `--static-asset-base``config.js` 指向 OSS;设 `--static-asset-base` 时不拷贝图标进 dist`--with-videos` 可选本地拷贝视频,生产部署勿用) |
| `deploy_relations.py` | 一键部署上分帝 Web 静态站点到 Cloudflare Pages(导出 + 资产预检 + `wrangler` 直传 + 绑域名;默认 OSS base 指向 `climperor` 桶的视频与静态图;凭据经 keyzoo 注入或 env |
| `notify_site_traffic.py` | 上分帝 Web 日活摘要 → 飞书 webhookCloudflare GraphQL;按已知浏览器 UA + `/` 估真实访问;`--dry-run` 只打印卡片) |
| `.gitea/workflows/site-traffic-notify.yml` | 每日 09:00 CST 在 self-hosted runner 跑 `notify_site_traffic.py`Secrets`CLOUDFLARE_EMAIL` / `CLOUDFLARE_API_KEY` / `FEISHU_WEBHOOK_URL`(自 keyzoo `refining/cloudflare` + `refining/feishu_webhook` |
| `_cf_status.py` | 只读查询 Cloudflare Pages 项目 / 部署 / 自定义域名状态(凭据经 keyzoo 注入) |
| `_oss_ability_videos.py` | 阿里云 OSS 桶 `climperor` 建桶 / CORS / 同步 `assets/ability_videos/``ability-video/`(凭据经 keyzoo `digitevents/voson-RAM` 注入);`_oss_static_assets.py` 同步图标等静态图;`_oss_fix_public.py` / `_oss_launch_upload.py` 为配套辅助 |
| `fetch_hero_portraits.py` | 拉取官网横版头像 → `assets/hero_portraits/`(上分帝 Web |
| `fetch_hero_items.py` | 拉取 OpenDota 热门装备 → `data/hero_items.json` + `assets/item_icons/` |
| `fetch_hero_stats.py` | 拉取 OpenDota 各段位场次/胜场 → `data/hero_stats.json`(**仅上分帝 Web**;勿写入 relations/heroes,勿进 recommend |
| `fetch_hero_matches.py` | 拉取同英雄近期比赛 + 终局出装/加点 → `data/hero_matches.json``--source league\|public\|both`;合并后保留最近 N 场胜局,默认 10;天梯需传奇及以上;公开列表过滤 bot/Turbo、仅 ranked lobby`--public-region china` 优先国服;`--enrich-item-times` 补购买时间;**仅上分帝 Web**;勿进 recommend |
| `fetch_leaderboards.py` | 拉取 Valve Immortal 四区榜 Top100 → `data/leaderboards.json`(**仅上分帝 Web「排行」**;无 MMR/account_id;勿进 recommend |
| `fetch_item_shop.py` | 官网商店 11 列目录(dota2.com.cn/itemscategory+ 合成图 → `data/item_shop.json` + 图标 |
| `fetch_items_meta.py` | Valve/OpenDota 装备描述 → 机制标签 → `data/items_meta.json``%token%` 用 special_values 填数) |
| `loc_format.py` | Valve 文案共用:去 HTML、填充 `%token%` / `{s:token}` |
| `fetch_hero_abilities.py` | Valve herodata 技能/魔晶/神杖/天赋 + 驱散汇总 → `data/hero_abilities.json``has_scepter`/`has_shard` 只信 Valve 显式 flagValve 移除升级后残留的 `scepter_loc`/`shard_loc` 文案会被清空;逐级相同的 `cast_points`/`channel_times` 合并为单值(施法前摇/吟唱时间);可选 `--icons` / `--icons-only` 缓存 Steam CDN 技能图标 → `assets/ability_icons/`(先天用共用 `innate.png`,不拉 CDN |
| `fetch_ability_videos.py` | 官网技能演示 webm/mp4Steam CDN;限速)→ `assets/ability_videos/`A 杖/魔晶赋予技能(`granted_by_scepter`/`granted_by_shard`CDN 名用 `<hero>_aghanims_scepter`/`<hero>_aghanims_shard`,本地文件名仍用 ability key |
| `item_fears.py` | 规则推导「英雄怕的装备」→ `data/hero_item_fears.json` |
| `autocalibrate.py` / `calibrate.py` | ROI 自动 / 手动标定 |
| `capture.py` | 屏幕捕获 |
| `overlay.py` | 顶栏角色标签 + 网格「克/搭/补」方标 + 阵容分析横条(点击穿透) |
| `evaluate.py` | 按 `samples/labels.json` 批量评测 |
| `roles.py` / `grid.py` / `modes.py` | 位置字、禁用网格、模式字 |
| `config.json` | 相对坐标、阈值、GSI、recommend 参数 |
| `data/heroes.json` | 英雄表(id/key/attr/roles/aliases/abbr/tags + 基础属性/初始血蓝等;由 `fetch_cdn_templates.py` 生成) |
| `data/patches.json` | 近一年版本列表 + 逐版本详情(`patches`/`lookup`/`details`;由 `fetch_patches.py` 生成,Web 版本页只读) |
| `data/relations.json` | 定性克制边 + 搭档边(可提交;手改 JSON,Web 站点只读) |
| `data/hero_grid_order.json` | Web 站点四列网格顺序 |
| `data/hero_items.json` | 核心成品装备缓存(Web 站点只读;由 `fetch_hero_items.py` 生成) |
| `data/hero_stats.json` | 英雄各段位 pick/win + `totals` + `window_*`OpenDota **近约 7 天**;Web「走势」Tab:胜率/上场率/场次;冠绝与超凡样本合并展示;由 `fetch_hero_stats.py` 生成;**不**参与局内推荐) |
| `data/hero_matches.json` | 同英雄近期比赛列表 + 终局出装/加点 + 可选购买时间(OpenDota;`--source league\|public\|both`Web「近期比赛」Tab;由 `fetch_hero_matches.py` 生成;**不**参与局内推荐) |
| `data/leaderboards.json` | Valve Immortal 四区 Top100`china`/`europe`/`americas`/`se_asia`;仅排名+昵称等;由 `fetch_leaderboards.py` 生成;Web「排行」选手榜只读;**不**参与局内推荐) |
| `data/stratz_hero_meta.json` | STRATZ 各勋章段位近 N 周 pick/win + **同段位最近 1 周分路** + `meta_board`(由 `fetch_stratz_meta.py` 生成;Web 英雄详情「走势」优先 + 顶层「走势」近 N 周高胜率榜 +「排行 → 英雄 Meta」;**不**参与局内推荐) |
| `data/stratz_matchup_tops.json` | STRATZ 对位/协同 Topcounters/countered/synergies;由 `fetch_stratz_meta.py` 生成;Web「对位」Tab;与定性 `relations.json` 分开展示;**不**参与局内推荐) |
| `data/item_shop.json` | 商店 11 列目录(官网 basic/upgrade;由 `fetch_item_shop.py` 生成;物品页只读) |
| `data/items_meta.json` | 成品装备描述与机制标签(由 `fetch_items_meta.py` 生成) |
| `data/item_tag_overrides.json` | 装备标签手工加减(合并进 items_meta |
| `data/hero_fear_overrides.json` | 英雄→害怕装备手工加减(合并进 item_fears |
| `data/hero_abilities.json` | 英雄技能与机制汇总(由 `fetch_hero_abilities.py` 生成) |
| `data/hero_item_fears.json` | 英雄怕的装备(规则推导;Web「怕」行) |
| `web/relations/` | 上分帝 Web 前端静态资源(`index.html` / `config.js` / `app.js` / `style.css` / `router.js`);`config.js``SITE_VERSION``ABILITY_VIDEO_BASE``STATIC_ASSET_BASE`;版本页底部显示 `v{SITE_VERSION}` |
| `web/relations/router.js` | Hash 路由:`parseHash` / `serializeHash` / `installRouter` / `syncStateToUrl`;状态↔URL 双向同步(顶层标签 `heroes\|rankings\|trends\|items\|patches` / 英雄 + 子标签 `skills\|core\|fears\|trends\|matchups\|matches\|patches` / Immortal 地区或 Meta 段位 `#/rankings/meta[/bracket]` / 近 8 周走势榜 `#/trends[/bracket]` / 物品 / 版本 / 标签筛选 / 搜索;旧 `stats` 别名兼容) |
| `templates/cdn/` | 全英雄 CDN 模板(需提交或由脚本生成) |
| `templates/roles/` / `templates/modes/` | 位置 / 模式辅助模板 |
| `assets/role_icons/` | Valve 选人筛选角色图标(`filter_*`,品红 chroma 去黑边) |
| `assets/hero_portraits/` | 官网横版头像(上分帝 Web;默认 wide 面部构图,非匹配模板) |
| `assets/attr_icons/` | 官网主属性图标(力量/敏捷/智力/全才,上分帝 Web 用) |
| `assets/rank_icons/` | 天梯勋章图标(OpenDota `rank_icon_1..8` 先锋→冠绝;走势段位选择器) |
| `assets/item_icons/` | Steam CDN 装备图标(上分帝 Web常用装备) |
| `assets/item_cat_icons/` | 官网商店分类图标(`itemcat_*.png`,物品页列头) |
| `assets/ability_icons/` | Steam CDN 技能图标(上分帝 Web;按需缓存);`innate.png` 先天共用图标;`talent_tree.png` 天赋树触发图标 |
| `assets/ui_icons/` | dota2.com.cn 通用 UI 图标(`cooldown.png` 等,技能详情底栏冷却图标) |
| `assets/ability_videos/` | 官网技能演示视频(webm/mp4;勿提交,由脚本拉取;线上由阿里云 OSS `climperor``ability-video/` 前缀托管) |
运行时产物(**勿提交**,见 `.gitignore`):
- `samples/raw/<matchid>/` — GSI 会话截图与 `gsi.jsonl`;手动 `capture.py` 可写在 `raw/` 根下
- `preview/` — 标定 / sheet 预览
- `dist/` — 静态站点导出(`export_relations_site.py`
- `results/` — 每局 JSON
- `failures/``--truth` 调试用错识裁切
- `data/matchups.json` / `synergies.json` / `stratz_matchups.json` / `relations_audit.json` 等 — 可再生成缓存与报告
- `assets/ability_videos/` — 官网技能演示(体积大,可再拉取)
## 数据流
```
Dota 2 GSI → gsi_watch.py (:3223)
→ 全量 payload → samples/raw/<matchid>/gsi.jsonl(可关)
→ DraftSession 轮询截屏 → samples/raw/<matchid>/
→ recognize_image (CDN 模板 + 可选天梯遮罩)
→ roles(分路字)/ grid(禁用 + 单元格)/ modes
→ recommend 克/搭/补(relations + draft_archetypes 规则画像,本人槽位只信 GSI)
→ overlay 角色标签 + 网格克/搭/补 + 阵容分析条(可选)
→ results/draft_*.json + 终端时间线
```
## 技术约束(修改前必读)
- **合规**:仅 GSI + 屏幕截图;**禁止**读进程内存、注入、绕过 VAC。
- **GSI 范围**:普通玩家视角拿不到双方 pick;GSI 只作阶段触发、`team_slot`、本人 `hero`、本机 `accountid`/`steamid`。本人顶栏槽位**只信** GSI,不用截屏名字亮度猜测。
- **克制 / 搭档数据**:机制克制/搭档只用定性边存 `data/relations.json`(克制有向 + 搭档无向 + 理由),**不要**用胜率/场次表达机制克制,也**不要**写入 `data/heroes.json`。Web 英雄页三视图:克制 / 被克制 / 搭档。OpenDota 段位胜率/场次单独存 `data/hero_stats.json`(近约 7 天窗;上场率 = 出场/(Σ出场/10);冠绝样本过小时与超凡合并),**仅**上分帝 Web 英雄详情「走势」兜底展示。STRATZ 周胜率/分路/`meta_board``data/stratz_hero_meta.json`,对位 Top 存 `data/stratz_matchup_tops.json`(英雄详情「走势」与顶层「走势」榜 `#/trends` 优先用 STRATZ;「对位」Tab 与「排行 → 英雄 Meta」只读),**禁止**合并进 relations/heroes,禁止 `recommend.py` 读取。同英雄近期比赛出装/加点单独存 `data/hero_matches.json`**仅** Web「近期比赛」Tab,禁止进 recommend。Valve Immortal 四区榜单独存 `data/leaderboards.json`,**仅** Web「排行」页选手榜,禁止进 recommend。
- **装备机制 / 怕的装备**:标签与技能汇总来自 Valve/OpenDota 自动抽取 + `item_tag_overrides.json``item_fears.py` 规则映射到英雄弱点。大段技能文案只进 `data/hero_abilities.json` / `items_meta.json`**不要**塞进 `heroes.json`。本阶段仅上分帝 Web 展示,**不对局内出装推荐**。核心装「使用率」为 `hero_items` 列表内相对热度归一化,非绝对出场率、无段位维度。
- **模板策略**:只维护 CDN 层。皮肤问题用会话策略(选人可改判、决策 `allow_revise=False`、best 帧偏 HERO_SELECTION),不要为皮肤加模板库,也不要复活 real 双层库。
- **顶栏时机**:皮肤在**全员选完后**才上顶栏;本机进决策时别人可能还在选——须保持 `strategy_tail` 视觉,禁止「一进 STRATEGY 就永久停读」。
- **坐标**:一律相对坐标(相对屏幕高 / 相对中心),勿写死像素分辨率。
- **宁可不认,不可乱认**`min_score` + `min_margin` 双门控;不确定就 `null`
- **平台**:面向 Windows;截屏依赖无边框/窗口模式。
## 开发命令
```powershell
pip install -r requirements.txt
python fetch_cdn_templates.py
python import_relations_xlsx.py # 可选:从选将笔记 xlsx 导入关系
python fetch_hero_portraits.py # 官网横版头像(上分帝 Web
python fetch_hero_items.py # OpenDota 热门装备缓存(上分帝 Web)
python fetch_hero_stats.py # OpenDota 各段位胜率/场次(上分帝 Web 走势兜底)
python fetch_stratz_meta.py # STRATZ 周胜率/分路/对位 Top(走势/对位/Meta;需 token
python fetch_hero_matches.py # 同英雄近期比赛出装/加点/购买时间(上分帝 Web;可 --heroes antimage--enrich-item-times
python fetch_leaderboards.py # Valve Immortal 四区 Top100(排行页)
python fetch_item_shop.py # 商店分类目录(物品页)
python fetch_items_meta.py # 装备描述 + 机制标签
python fetch_hero_abilities.py # 英雄技能 / 驱散汇总
python fetch_hero_abilities.py --icons-only # 缓存技能图标到 assets/ability_icons/
python fetch_ability_videos.py # 官网技能演示(限速;默认 webm)
python item_fears.py # 英雄怕的装备
python fetch_patches.py # 近一年版本日志 + 详情(版本页)
python serve_relations.py # 上分帝 Web 本地开发服务(英雄 / 排行 / 物品 / 版本)
python export_relations_site.py # 导出静态站点到 dist/relations/(可部署 Pages
python export_relations_site.py --ability-video-base https://climperor.oss-cn-shanghai.aliyuncs.com --static-asset-base https://climperor.oss-cn-shanghai.aliyuncs.com
python deploy_relations.py # 部署 dist/relations 到 Cloudflare Pages(凭据经 keyzoo 注入或 env;默认 dota2.refining.dev;视频与图标走 OSS
python notify_site_traffic.py --dry-run # 上分帝 Web 日活摘要(飞书;需 CF + webhook env / keyzoo
python _oss_static_assets.py upload # 图标/portrait 变更后同步 OSSkeyzoo voson-RAM
python _cf_status.py # 只读查 CF Pages 部署 / 自定义域名状态
python gsi_setup.py --check
python gsi_watch.py --once
python recognize.py samples/raw/<>.png --sheet
python evaluate.py
```
## 修改原则
- 只改任务所需逻辑,避免无关重构与大范围格式化。
- 代码标识符、日志、错误信息、注释用**英文**;用户可见摘要可用中文。
- 改匹配阈值或裁切时,用 `evaluate.py` / 标注帧验证,并更新 `CHANGELOG.md` 与必要时的 `DESIGN.md`
- 改 GSI cfg 时同步核对 `gsi_setup.py` 与 Dota `gamestate_integration` 目录。
- 改 Web 路由形态(URL 段 / query 参数 / 默认值)时同步 `web/relations/router.js``parseHash` / `serializeHash`)与 `app.js``applyPatch` 校验;新增可路由状态维度时在两处都加,并在 `syncStateToUrl` 调用点(含搜索 debounce)接好。Hash 路由不命中后端,`serve_relations.py` 无需改;`export_relations_site.py` 的导出文件列表须含 `router.js`
-`data/heroes.json` 结构时同步 `grid.py`(依赖 `attr` / `name_loc`);`roles``overlay.py` 使用;`aliases` 为中文口语/俗称(勿与 `name_loc` 重复),重跑 `fetch_cdn_templates.py` 会按 `key` 合并保留;`tags` 为中文定位(核心/辅助/…/幻象,由 `roles`+幻想系推导),上分帝 Web 筛选 + 局内 `draft_archetypes` 缺口/推进画像共用;基础属性/血蓝等数值字段供上分帝 Web 详情条,勿塞机制文案。
- 发版上分帝 Web 时同步 bump `export_relations_site.py``SITE_VERSION``web/relations/config.js` 的同名变量,以及 `index.html``style.css`/`config.js`/`router.js`/`app.js``?v=` 缓存戳;并写 `CHANGELOG.md`
- 不要重新引入 real 模板双层库、`cdn_penalty``build_library.py`
## 文档分工
| 文件 | 内容 |
|------|------|
| `README.md` | 安装与操作手册 |
| `DESIGN.md` | 背景、选型、关键实测与决策记录 |
| `AGENTS.md` | 本文件:给协作者 / AI 的约束 |
| `CHANGELOG.md` | 面向用户的版本变更 |
## 与 dota2-hex
本仓库独立演进。并入或旁路对接时,仍须遵守 [dota2-hex/AGENTS.md](../dota2-hex/AGENTS.md) 的合规边界。