Reorganize repository into pc web shared monorepo
Separate the local recognition, web publishing, and shared data paths while preserving direct script execution and existing site content. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -21,53 +21,56 @@ Dota 2 **天梯选将识别**:从选人 / 决策时间截图中识别双方 10
|
||||
## 安装
|
||||
|
||||
```powershell
|
||||
pip install -r requirements.txt
|
||||
python fetch_cdn_templates.py # 一次性:data/heroes.json(含基础属性/血蓝)+ templates/cdn/
|
||||
pip install -r pc/requirements.txt
|
||||
python pc/fetch_cdn_templates.py # 一次性:shared/data/heroes.json(含基础属性/血蓝)+ pc/templates/cdn/
|
||||
# 可选:从选将笔记 xlsx 导入定性克制/搭档
|
||||
# python import_relations_xlsx.py path\to\dota2.xlsx
|
||||
# python shared/import_relations_xlsx.py path\to\dota2.xlsx
|
||||
```
|
||||
|
||||
仓库为 monorepo:`pc/`(局内选将识别)、`web/`(上分帝 Web)、`shared/`(共享包)。脚本一律在仓库根执行,如 `python pc/gsi_watch.py`、`python web/serve_relations.py`。
|
||||
|
||||
## 上分帝 Web(游戏外)
|
||||
|
||||
上分帝 Web 是独立子项目(`web/relations/`):英雄克制/搭档、排行、主播、物品、版本等内容站点,与局内选将识别解耦。
|
||||
上分帝 Web 是独立子项目(`web/`):英雄克制/搭档、排行、主播、物品、版本等内容站点,与局内选将识别解耦。
|
||||
|
||||
```powershell
|
||||
python fetch_hero_portraits.py # 官网竖版头像 → assets/hero_portraits/
|
||||
python fetch_hero_items.py # OpenDota 热度 + Valve 中文名 + Steam 图标 → data/hero_items.json
|
||||
python fetch_hero_stats.py # OpenDota 各段位胜率/场次 → data/hero_stats.json(Web 走势兜底)
|
||||
python fetch_stratz_meta.py # STRATZ 周胜率/分路/对位 Top → stratz_hero_meta.json(需 token;见 .env.example)
|
||||
python fetch_hero_matches.py # 同英雄近期比赛出装/加点(含购买时间)→ data/hero_matches.json
|
||||
# 既有行补时间:python fetch_hero_matches.py --enrich-item-times [--heroes juggernaut]
|
||||
python fetch_item_shop.py # 官网商店 11 列目录 → data/item_shop.json
|
||||
python fetch_items_meta.py # 装备描述 + 机制标签 → data/items_meta.json
|
||||
python fetch_hero_abilities.py # 英雄技能 / 驱散汇总 → data/hero_abilities.json
|
||||
python fetch_ability_videos.py # 官网技能演示 webm(限速)→ assets/ability_videos/
|
||||
python fetch_item_counter_stats.py # OpenDota 对阵购买率/胜率相对全局基线 → 可再生成缓存
|
||||
python item_fears.py # 规则推导「怕的装备」→ data/hero_item_fears.json
|
||||
python fetch_patches.py # 近一年版本日志 + 详情 → data/patches.json(版本页)
|
||||
python fetch_leaderboards.py # Valve Immortal 四区 Top100 → data/leaderboards.json(排行页)
|
||||
python fetch_streamers.py # 抖音主播主页补全 → data/streamers.json(主播页;手工名单)
|
||||
python serve_relations.py # 本地开发服务 http://127.0.0.1:8765(改 JSON 后刷新)
|
||||
python web/fetch_hero_portraits.py # 官网竖版头像 → web/assets/hero_portraits/
|
||||
python web/fetch_hero_items.py # OpenDota 热度 + Valve 中文名 + Steam 图标 → web/data/hero_items.json
|
||||
python web/fetch_hero_stats.py # OpenDota 各段位胜率/场次 → web/data/hero_stats.json(Web 走势兜底)
|
||||
python web/fetch_stratz_meta.py # STRATZ 周胜率/分路/对位 Top → stratz_hero_meta.json(需 token;见 .env.example)
|
||||
python web/fetch_hero_matches.py # 同英雄近期比赛出装/加点(含购买时间)→ web/data/hero_matches.json
|
||||
# 既有行补时间:python web/fetch_hero_matches.py --enrich-item-times [--heroes juggernaut]
|
||||
python web/fetch_item_shop.py # 官网商店 11 列目录 → web/data/item_shop.json
|
||||
python web/fetch_items_meta.py # 装备描述 + 机制标签 → web/data/items_meta.json
|
||||
python web/fetch_hero_abilities.py # 英雄技能 / 驱散汇总 → web/data/hero_abilities.json
|
||||
python web/fetch_ability_videos.py # 官网技能演示 webm(限速)→ web/assets/ability_videos/
|
||||
python web/fetch_item_counter_stats.py # OpenDota 对阵购买率/胜率相对全局基线 → 可再生成缓存
|
||||
python web/item_fears.py # 规则推导「怕的装备」→ web/data/hero_item_fears.json
|
||||
python web/fetch_patches.py # 近一年版本日志 + 详情 → web/data/patches.json(版本页)
|
||||
python web/fetch_leaderboards.py # Valve Immortal 四区 Top100 → web/data/leaderboards.json(排行页)
|
||||
python web/fetch_streamers.py # 抖音主播主页补全 → web/data/streamers.json(主播页;手工名单)
|
||||
python web/fetch_streamer_live.py # 探测真实在播状态 → is_live/live_probed_at(主播页角标;--dry-run 只打印)
|
||||
python web/serve_relations.py # 本地开发服务 http://127.0.0.1:8765(改 JSON 后刷新)
|
||||
```
|
||||
|
||||
Web 站点带 **Hash 路由**:`#/heroes/axe/core`、`#/heroes/axe/trends`、`#/heroes/axe/matchups`、`#/heroes/axe/matches`、`#/trends/legend`、`#/rankings`、`#/items/black_king_bar`、`#/patches/7.41`(`#/patches` = 最新,`#/rankings` = 中国区);英雄页的定位标签筛选与搜索框也进 URL(`?tags=核心&q=axe`)。刷新保状态、可分享 / 深度链接、浏览器前进后退还原。`python export_relations_site.py` 导出的静态站点同样支持深度链接(可部署 GitHub Pages 或 Cloudflare Pages)。
|
||||
Web 站点带 **Hash 路由**:`#/heroes/axe/core`、`#/heroes/axe/trends`、`#/heroes/axe/matchups`、`#/heroes/axe/matches`、`#/trends/legend`、`#/rankings`、`#/items/black_king_bar`、`#/patches/7.41`(`#/patches` = 最新,`#/rankings` = 中国区);英雄页的定位标签筛选与搜索框也进 URL(`?tags=核心&q=axe`)。刷新保状态、可分享 / 深度链接、浏览器前进后退还原。`python web/export_relations_site.py` 导出的静态站点同样支持深度链接(可部署 GitHub Pages 或 Cloudflare Pages)。
|
||||
|
||||
### 部署到 Cloudflare Pages
|
||||
|
||||
```powershell
|
||||
python deploy_relations.py
|
||||
python web/deploy_relations.py
|
||||
# 串联:导出 → 资产完整性预检 → wrangler 直传 → 绑定自定义域名
|
||||
# 凭据经 keyzoo 注入(refining/cloudflare 的 Global API Key);
|
||||
# 或手动设 $env:CLOUDFLARE_EMAIL / $env:CLOUDFLARE_API_KEY 后运行
|
||||
# 默认项目 climperor-relations、域名 dota2.refining.dev(可用 --project-name / --domain 覆盖)
|
||||
# 技能演示视频与静态图标默认走阿里云 OSS 桶 climperor(Pages 只部署 ~2MB HTML/JS/data)
|
||||
python _oss_static_assets.py upload # patch/新英雄后同步图标到 OSS
|
||||
python _cf_status.py # 部署后只读核对(项目 / 部署 / 域名状态)
|
||||
python web/_oss_static_assets.py upload # patch/新英雄后同步图标到 OSS
|
||||
python web/_cf_status.py # 部署后只读核对(项目 / 部署 / 域名状态)
|
||||
```
|
||||
|
||||
### 定时刷新(Gitea Actions)
|
||||
|
||||
仓库 [`.gitea/workflows/`](.gitea/workflows/) 在 **self-hosted** runner(与 `site-traffic-notify` 同一 Mac mini)上分层拉数;`refresh_web.py` 比对 JSON/图标摘要,**有变更才** `_oss_static_assets.py upload` + `deploy_relations.py`。数据-only 刷新**不** bump `SITE_VERSION`(`data.json` / `index.html` 已不缓存)。
|
||||
仓库 [`.gitea/workflows/`](.gitea/workflows/) 在 **self-hosted** runner(与 `site-traffic-notify` 同一 Mac mini)上分层拉数;`web/refresh_web.py` 比对 JSON/图标摘要,**有变更才** `_oss_static_assets.py upload` + `deploy_relations.py`。数据-only 刷新**不** bump `SITE_VERSION`(`data.json` / `index.html` 已不缓存)。
|
||||
|
||||
| Workflow | 时间(CST) | 档位 | 拉取内容 |
|
||||
|----------|-------------|------|----------|
|
||||
@@ -75,17 +78,17 @@ python _cf_status.py # 部署后只读核对(项目 / 部署 / 域名状态
|
||||
| `web-weekly` | 周二 07:00 | `weekly` | `stratz_meta`、`hero_items`、`items_meta`、OpenDota 对阵装备证据、`item_fears` |
|
||||
| `web-patch` | 每 6 小时 | `patch` | `fetch_patches.py --check`;仅 `has_new` 时拉详情 + abilities/商店/items_meta/fears |
|
||||
|
||||
**版本检测:** `--check` 只请求 Valve 版本列表,与本地 `data/patches.json` 的 `details` 比对,stdout 一行 JSON(`has_new` / `new_versions` / `latest`)。无新版本则跳过详情与部署。
|
||||
**版本检测:** `--check` 只请求 Valve 版本列表,与本地 `web/data/patches.json` 的 `details` 比对,stdout 一行 JSON(`has_new` / `new_versions` / `latest`)。无新版本则跳过详情与部署。
|
||||
|
||||
**本机试跑:**
|
||||
|
||||
```powershell
|
||||
pip install -r requirements.txt -r requirements-web.txt
|
||||
python fetch_patches.py --check
|
||||
python refresh_web.py --tier patch --dry-run
|
||||
python refresh_web.py --tier patch --skip-deploy --skip-oss
|
||||
pip install -r web/requirements.txt
|
||||
python web/fetch_patches.py --check
|
||||
python web/refresh_web.py --tier patch --dry-run
|
||||
python web/refresh_web.py --tier patch --skip-deploy --skip-oss
|
||||
# 真实拉数+部署(需 CF / OSS env 或 keyzoo):
|
||||
# python refresh_web.py --tier daily
|
||||
# python web/refresh_web.py --tier daily
|
||||
```
|
||||
|
||||
**Runner 要求:** `python3`(或 `python`)、`node`/`npx`(wrangler)、出网访问 OpenDota / STRATZ / Valve / Cloudflare / 阿里云 OSS。
|
||||
@@ -94,32 +97,32 @@ python refresh_web.py --tier patch --skip-deploy --skip-oss
|
||||
|
||||
| Secret | 用途 |
|
||||
|--------|------|
|
||||
| `CLOUDFLARE_EMAIL` / `CLOUDFLARE_API_KEY` | 部署 Pages(与 `site-traffic-notify` 共用;可用 `_gitea_actions_secrets.py` 写入) |
|
||||
| `CLOUDFLARE_EMAIL` / `CLOUDFLARE_API_KEY` | 部署 Pages(与 `site-traffic-notify` 共用;可用 `web/_gitea_actions_secrets.py` 写入) |
|
||||
| `STRATZ_API_TOKEN` | `web-weekly`(及 daily 内若触发连带时不需要) |
|
||||
| `OSS_ACCESS_KEY_ID` / `OSS_ACCESS_KEY_SECRET` | 图标变更时上传 OSS |
|
||||
|
||||
手工数据(`relations.json`、overrides)与技能视频(GB 级)**不**进定时;新英雄仍需本机 `fetch_cdn_templates.py` + `fetch_hero_portraits.py`。冒烟:Gitea Actions 对 `web-patch` 点 **Run workflow**。
|
||||
手工数据(`shared/data/relations.json`、overrides)与技能视频(GB 级)**不**进定时;新英雄仍需本机 `pc/fetch_cdn_templates.py` + `web/fetch_hero_portraits.py`。冒烟:Gitea Actions 对 `web-patch` 点 **Run workflow**。
|
||||
|
||||
仿局内选将四列网格(图标来自 [dota2.com/heroes](https://www.dota2.com/heroes) 竖版裁切):点英雄高亮克制 / 被克制 / 搭档,下方显示定位,并以标签页切换 **技能**(可点选魔晶/神杖升级与天赋树)、**核心装备**、**被克装备**、**走势**(STRATZ 优先:勋章条 + 最近 1 周三卡 + 分路 + 近 8 周列表;OpenDota 兜底)、**对位**(STRATZ 克制/被克/搭档 Top)、**近期比赛**(终局出装/加点)、**主播**(常玩该英雄的收录主播)、**版本变更**(该英雄近一年各版本改动)。
|
||||
英雄页上方网格固定高度;点选技能 / 核心装备 / 被克装备后,详情显示在下方(装备含合成,非弹窗)。
|
||||
|
||||
顶部另有 **排行** 页:Valve Immortal 四区榜各 Top 100(中国 / 欧洲 / 美洲 / 东南亚);数据来自 `data/leaderboards.json`(`python fetch_leaderboards.py`)。
|
||||
顶部另有 **主播** 页:手工收录直播间/主页(首版仅抖音),抖音式卡片展示昵称、签名、关注/粉丝/获赞、常用英雄与可选精选高光视频(滚入视口中部自动播放;有 `live_url` 时点头像进直播间并显示直播动效;**角标不代表真实在播**,待接入 `is_live`);数据来自 `data/streamers.json`(`python fetch_streamers.py` 补全;亦由 `refresh_web --tier daily` 每日软失败刷新)。视频文件放 `assets/streamer_videos/`(gitignore),本地开发经 `/streamer-video/` 提供,部署前用 `_oss_static_assets.py upload` 同步至 OSS `streamer-video/`。
|
||||
顶部另有 **排行** 页:Valve Immortal 四区榜各 Top 100(中国 / 欧洲 / 美洲 / 东南亚);数据来自 `web/data/leaderboards.json`(`python web/fetch_leaderboards.py`)。
|
||||
顶部另有 **主播** 页:手工收录直播间/主页(首版仅抖音),抖音式卡片展示昵称、签名、关注/粉丝/获赞、常用英雄与可选精选高光视频(滚入视口中部自动播放;有 `live_url` 时点头像进直播间;「直播」角标与动效只在真实探测在播时显示(线上由访客触发的 `/api/live-status` 边缘函数实时刷新,边缘缓存 5 分钟合并请求;`data.json` 内 `fetch_streamer_live.py` daily 探测值兜底);数据来自 `web/data/streamers.json`(`python web/fetch_streamers.py` 补全;亦由 `web/refresh_web --tier daily` 每日软失败刷新)。视频文件放 `web/assets/streamer_videos/`(gitignore),本地开发经 `/streamer-video/` 提供,部署前用 `web/_oss_static_assets.py upload` 同步至 OSS `streamer-video/`。
|
||||
顶部另有 **走势** 页:近 8 周各段位高胜率 / 上场率榜(`#/trends[/bracket]`;STRATZ 周胜率数据)。
|
||||
顶部另有 **物品** 页:对齐 [官网商店物品](https://www.dota2.com.cn/items/index.htm) 的 **11 列竖排**(基础分类 5 列 + 合成分类 6 列),点选后详情显示在右侧(含合成组件)。目录来自 `data/item_shop.json`(`python fetch_item_shop.py`)。
|
||||
顶部另有 **版本** 页:默认展示最新版本完整改动(综合 / 物品 / 中立物品 / 英雄),下拉切换近一年其它版本;数据来自 `data/patches.json`(`python fetch_patches.py`,近一年窗口可用 `--days` / `--since` 调)。
|
||||
数据在 `data/relations.json`(英雄关系,不用胜率);选将全网格「克/搭/补」推荐读同一份文件,并用 `draft_archetypes.py` 规则识别推进/全球流与敌我缺口(不接 AI)。热门装备来自 OpenDota 统计。**走势**优先 STRATZ(`data/stratz_hero_meta.json`,按勋章近 8 周 + 最近 1 周分路;`python fetch_stratz_meta.py`,需 token),OpenDota 各段位胜率/上场率/场次在 `data/hero_stats.json`(近约 7 天兜底;不进推荐)。**对位**数值 Top 在 `data/stratz_matchup_tops.json`(与网格定性克/搭分开展示)。被克装备以描述标签 + 规则为主;`fetch_item_counter_stats.py` 另算敌方终局装备相对同装备全局基线的购买率提升/胜率差,对全部英雄的已有候选小幅调序;装备卡有数据时显示对阵该英雄的敌方队伍终局装备出现率。统计显著的新组合仍须确认机制成立后写入 `hero_fear_overrides.json`,避免“高相关但不克制”的误报。可改 `data/item_tag_overrides.json` 后重跑 `fetch_items_meta.py` 与 `item_fears.py`。**尚无对局内出装推荐**。
|
||||
顶部另有 **物品** 页:对齐 [官网商店物品](https://www.dota2.com.cn/items/index.htm) 的 **11 列竖排**(基础分类 5 列 + 合成分类 6 列),点选后详情显示在右侧(含合成组件)。目录来自 `web/data/item_shop.json`(`python web/fetch_item_shop.py`)。
|
||||
顶部另有 **版本** 页:默认展示最新版本完整改动(综合 / 物品 / 中立物品 / 英雄),下拉切换近一年其它版本;数据来自 `web/data/patches.json`(`python web/fetch_patches.py`,近一年窗口可用 `--days` / `--since` 调)。
|
||||
数据在 `shared/data/relations.json`(英雄关系,不用胜率);选将全网格「克/搭/补」推荐读同一份文件,并用 `pc/draft_archetypes.py` 规则识别推进/全球流与敌我缺口(不接 AI)。热门装备来自 OpenDota 统计。**走势**优先 STRATZ(`web/data/stratz_hero_meta.json`,按勋章近 8 周 + 最近 1 周分路;`python web/fetch_stratz_meta.py`,需 token),OpenDota 各段位胜率/上场率/场次在 `web/data/hero_stats.json`(近约 7 天兜底;不进推荐)。**对位**数值 Top 在 `web/data/stratz_matchup_tops.json`(与网格定性克/搭分开展示)。被克装备以描述标签 + 规则为主;`web/fetch_item_counter_stats.py` 另算敌方终局装备相对同装备全局基线的购买率提升/胜率差,对全部英雄的已有候选小幅调序;装备卡有数据时显示对阵该英雄的敌方队伍终局装备出现率。统计显著的新组合仍须确认机制成立后写入 `web/data/hero_fear_overrides.json`,避免“高相关但不克制”的误报。可改 `web/data/item_tag_overrides.json` 后重跑 `web/fetch_items_meta.py` 与 `web/item_fears.py`。**尚无对局内出装推荐**。
|
||||
|
||||
## 快速开始(GSI 自动跟踪)
|
||||
|
||||
```powershell
|
||||
python gsi_setup.py # 写入 Dota GSI 配置
|
||||
python pc/gsi_setup.py # 写入 Dota GSI 配置
|
||||
# Steam → Dota 2 → 属性 → 启动项加上 -gamestateintegration,重启游戏
|
||||
python gsi_watch.py
|
||||
python pc/gsi_watch.py
|
||||
```
|
||||
|
||||
进入英雄选择后自动跟踪;敌方锁 ≥1 人后按关系与阵容画像在英雄网格标出 **克 / 搭 / 补**,并显示一句阵容分析(需 `data/relations.json`;定位局按分路过滤)。凑齐 10 人或超时后写出 `results/draft_<时间戳>.json`(该目录已 gitignore)。
|
||||
会话截图按对局落在 `samples/raw/<matchid>/`;默认同时把每包 GSI JSON 追加到同目录 `gsi.jsonl`(`--no-dump-gsi` 可关)。
|
||||
进入英雄选择后自动跟踪;敌方锁 ≥1 人后按关系与阵容画像在英雄网格标出 **克 / 搭 / 补**,并显示一句阵容分析(需 `shared/data/relations.json`;定位局按分路过滤)。凑齐 10 人或超时后写出 `pc/results/draft_<时间戳>.json`(该目录已 gitignore)。
|
||||
会话截图按对局落在 `pc/samples/raw/<matchid>/`;默认同时把每包 GSI JSON 追加到同目录 `gsi.jsonl`(`--no-dump-gsi` 可关)。
|
||||
|
||||
> 主菜单收不到 GSI 是正常的:客户端**第一次载入对局后**才开始推送。看到 `[gsi] connected` 才算链路通。
|
||||
|
||||
@@ -128,30 +131,30 @@ python gsi_watch.py
|
||||
### 截图
|
||||
|
||||
```powershell
|
||||
python capture.py # 单张 → samples/raw/
|
||||
python capture.py --loop 300 3 # 每 3 秒一张,持续 300 秒
|
||||
python pc/capture.py # 单张 → pc/samples/raw/
|
||||
python pc/capture.py --loop 300 3 # 每 3 秒一张,持续 300 秒
|
||||
```
|
||||
|
||||
GSI 跟踪时自动写入 `samples/raw/<matchid>/draft_*.png`(含 milestone / best)。
|
||||
GSI 跟踪时自动写入 `pc/samples/raw/<matchid>/draft_*.png`(含 milestone / best)。
|
||||
需无边框窗口或窗口模式(独占全屏可能黑帧)。
|
||||
|
||||
### 标定 ROI(一次性)
|
||||
|
||||
```powershell
|
||||
python autocalibrate.py samples/raw/<matchid>/<某帧>.png
|
||||
# 失败时退路:python calibrate.py samples/raw/<matchid>/<某帧>.png
|
||||
python pc/autocalibrate.py pc/samples/raw/<matchid>/<某帧>.png
|
||||
# 失败时退路:python pc/calibrate.py pc/samples/raw/<matchid>/<某帧>.png
|
||||
```
|
||||
|
||||
### 识别 / 评测
|
||||
|
||||
```powershell
|
||||
python recognize.py samples/raw/<matchid>/<帧>.png
|
||||
python recognize.py samples/raw/<matchid>/<帧>.png --sheet
|
||||
python recognize.py samples/raw/<matchid>/<帧>.png --truth hero1,...,hero10
|
||||
python evaluate.py # 按 samples/labels.json 批量评测
|
||||
python pc/recognize.py pc/samples/raw/<matchid>/<帧>.png
|
||||
python pc/recognize.py pc/samples/raw/<matchid>/<帧>.png --sheet
|
||||
python pc/recognize.py pc/samples/raw/<matchid>/<帧>.png --truth hero1,...,hero10
|
||||
python pc/evaluate.py # 按 pc/samples/labels.json 批量评测
|
||||
```
|
||||
|
||||
辅助脚本:`roles.py`(位置字)、`grid.py`(禁用名单)、`modes.py`(模式字)。
|
||||
辅助脚本:`pc/roles.py`(位置字)、`shared/grid.py`(禁用名单)、`pc/modes.py`(模式字)。
|
||||
|
||||
## 截图要求
|
||||
|
||||
|
||||
Reference in New Issue
Block a user