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>
19 KiB
19 KiB
协作说明(面向 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 日活摘要 → 飞书 webhook(Cloudflare 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 显式 flag,Valve 移除升级后残留的 scepter_loc/shard_loc 文案会被清空;逐级相同的 cast_points/channel_times 合并为单值(施法前摇/吟唱时间);可选 --icons / --icons-only 缓存 Steam CDN 技能图标 → assets/ability_icons/(先天用共用 innate.png,不拉 CDN) |
fetch_ability_videos.py |
官网技能演示 webm/mp4(Steam 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 对位/协同 Top(counters/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/— 每局 JSONfailures/—--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;截屏依赖无边框/窗口模式。
开发命令
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 变更后同步 OSS(keyzoo 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与 Dotagamestate_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 的合规边界。