Conversation
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并且给出了一些高层反馈:
- 在 build_locations.py 中你引入了
seen_names: set[str],这在 Python <3.9 上会出错;如果这个脚本需要在更旧版本上运行,请改用typing中的Set[str],或者添加from __future__ import annotations以保证兼容性。 - 在 Go 的
buildFeasibleWeaponSet中,你用Weapon.ChineseName作为可行性映射的键;如果武器中文名可能重复,或者会因为本地化发生变化,建议使用稳定的标识符(例如武器 ID)作为键,以避免可行性判断与其它地方使用的索引之间出现不一致。
给 AI Agent 的提示词
Please address the comments from this code review:
## Overall Comments
- In build_locations.py you introduced `seen_names: set[str]`, which will break on Python <3.9; if this script is meant to run on older versions, switch to `Set[str]` from `typing` or add `from __future__ import annotations` for compatibility.
- In the Go `buildFeasibleWeaponSet` you key feasibility by `Weapon.ChineseName`; if there can be duplicate or localized name changes, consider keying by a stable identifier (e.g. weapon ID) to avoid mismatches between feasibility and the indices used elsewhere.
## Individual Comments
### Comment 1
<location path="tools/essence_filter/build_locations.py" line_range="88-89" />
<code_context>
- pool2_by_id = {int(e["id"]): e for e in pool_slot2}
- pool3_by_id = {int(e["id"]): e for e in pool_slot3}
+ pool2_by_cn = {_norm_key(e.get("cn") or ""): e for e in pool_slot2}
+ pool3_by_cn = {_norm_key(e.get("cn") or ""): e for e in pool_slot3}
- locations_raw = wd.get("locations") or []
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Avoid using empty normalized keys in the CN → pool-entry maps to prevent accidental overwrites.
When `cn` is empty, `_norm_key` returns `""`, so all such entries share the same key and only the last one remains in `pool2_by_cn`/`pool3_by_cn`. Consider computing the normalized key first and only inserting when it’s non-empty to avoid collisions and silent overwrites.
```suggestion
pool2_by_cn: Dict[str, Any] = {}
for e in pool_slot2:
cn_key = _norm_key(e.get("cn") or "")
if not cn_key:
# Skip entries with empty/invalid CN to avoid collisions on the "" key
continue
pool2_by_cn[cn_key] = e
pool3_by_cn: Dict[str, Any] = {}
for e in pool_slot3:
cn_key = _norm_key(e.get("cn") or "")
if not cn_key:
# Skip entries with empty/invalid CN to avoid collisions on the "" key
continue
pool3_by_cn[cn_key] = e
```
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的 Review。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- In build_locations.py you introduced
seen_names: set[str], which will break on Python <3.9; if this script is meant to run on older versions, switch toSet[str]fromtypingor addfrom __future__ import annotationsfor compatibility. - In the Go
buildFeasibleWeaponSetyou key feasibility byWeapon.ChineseName; if there can be duplicate or localized name changes, consider keying by a stable identifier (e.g. weapon ID) to avoid mismatches between feasibility and the indices used elsewhere.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In build_locations.py you introduced `seen_names: set[str]`, which will break on Python <3.9; if this script is meant to run on older versions, switch to `Set[str]` from `typing` or add `from __future__ import annotations` for compatibility.
- In the Go `buildFeasibleWeaponSet` you key feasibility by `Weapon.ChineseName`; if there can be duplicate or localized name changes, consider keying by a stable identifier (e.g. weapon ID) to avoid mismatches between feasibility and the indices used elsewhere.
## Individual Comments
### Comment 1
<location path="tools/essence_filter/build_locations.py" line_range="88-89" />
<code_context>
- pool2_by_id = {int(e["id"]): e for e in pool_slot2}
- pool3_by_id = {int(e["id"]): e for e in pool_slot3}
+ pool2_by_cn = {_norm_key(e.get("cn") or ""): e for e in pool_slot2}
+ pool3_by_cn = {_norm_key(e.get("cn") or ""): e for e in pool_slot3}
- locations_raw = wd.get("locations") or []
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Avoid using empty normalized keys in the CN → pool-entry maps to prevent accidental overwrites.
When `cn` is empty, `_norm_key` returns `""`, so all such entries share the same key and only the last one remains in `pool2_by_cn`/`pool3_by_cn`. Consider computing the normalized key first and only inserting when it’s non-empty to avoid collisions and silent overwrites.
```suggestion
pool2_by_cn: Dict[str, Any] = {}
for e in pool_slot2:
cn_key = _norm_key(e.get("cn") or "")
if not cn_key:
# Skip entries with empty/invalid CN to avoid collisions on the "" key
continue
pool2_by_cn[cn_key] = e
pool3_by_cn: Dict[str, Any] = {}
for e in pool_slot3:
cn_key = _norm_key(e.get("cn") or "")
if not cn_key:
# Skip entries with empty/invalid CN to avoid collisions on the "" key
continue
pool3_by_cn[cn_key] = e
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| pool2_by_cn = {_norm_key(e.get("cn") or ""): e for e in pool_slot2} | ||
| pool3_by_cn = {_norm_key(e.get("cn") or ""): e for e in pool_slot3} |
There was a problem hiding this comment.
suggestion (bug_risk): 避免在 CN → pool-entry 映射中使用空的归一化键,以防止意外覆盖。
当 cn 为空时,_norm_key 会返回 "",因此所有这类条目会共享同一个键,最终只有最后一个会保留在 pool2_by_cn/pool3_by_cn 中。建议先计算归一化后的键,只在其非空时再插入,以避免键冲突和静默覆盖。
| pool2_by_cn = {_norm_key(e.get("cn") or ""): e for e in pool_slot2} | |
| pool3_by_cn = {_norm_key(e.get("cn") or ""): e for e in pool_slot3} | |
| pool2_by_cn: Dict[str, Any] = {} | |
| for e in pool_slot2: | |
| cn_key = _norm_key(e.get("cn") or "") | |
| if not cn_key: | |
| # Skip entries with empty/invalid CN to avoid collisions on the "" key | |
| continue | |
| pool2_by_cn[cn_key] = e | |
| pool3_by_cn: Dict[str, Any] = {} | |
| for e in pool_slot3: | |
| cn_key = _norm_key(e.get("cn") or "") | |
| if not cn_key: | |
| # Skip entries with empty/invalid CN to avoid collisions on the "" key | |
| continue | |
| pool3_by_cn[cn_key] = e |
Original comment in English
suggestion (bug_risk): Avoid using empty normalized keys in the CN → pool-entry maps to prevent accidental overwrites.
When cn is empty, _norm_key returns "", so all such entries share the same key and only the last one remains in pool2_by_cn/pool3_by_cn. Consider computing the normalized key first and only inserting when it’s non-empty to avoid collisions and silent overwrites.
| pool2_by_cn = {_norm_key(e.get("cn") or ""): e for e in pool_slot2} | |
| pool3_by_cn = {_norm_key(e.get("cn") or ""): e for e in pool_slot3} | |
| pool2_by_cn: Dict[str, Any] = {} | |
| for e in pool_slot2: | |
| cn_key = _norm_key(e.get("cn") or "") | |
| if not cn_key: | |
| # Skip entries with empty/invalid CN to avoid collisions on the "" key | |
| continue | |
| pool2_by_cn[cn_key] = e | |
| pool3_by_cn: Dict[str, Any] = {} | |
| for e in pool_slot3: | |
| cn_key = _norm_key(e.get("cn") or "") | |
| if not cn_key: | |
| # Skip entries with empty/invalid CN to avoid collisions on the "" key | |
| continue | |
| pool3_by_cn[cn_key] = e |
There was a problem hiding this comment.
Pull request overview
该 PR 针对 Issue #1682「推荐预刻写方案数据错误」修正地点词条来源与推荐逻辑,避免在“某地点不可刷的词条/武器”仍被纳入推荐方案的问题。
Changes:
- 改用
energy_point_gems.json作为地点词条来源,重新生成并更新locations.json。 - 更新
build_locations.py的解析/映射规则与文档说明。 - Go 端推荐逻辑按地点的 slot2/slot3 可用集合过滤,仅输出“该地点可行”的武器方案。
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/essence_filter/build_locations.py | 从 energy_point_gems.json 解析重度能量淤积点词条并映射到 skill_pools.json,生成 locations.json |
| tools/essence_filter/README.md | 补充 build_locations.py 用法与解析规则说明 |
| assets/data/EssenceFilter/locations.json | 更新地点词条数据(含部分 JP 文本补全) |
| assets/data/EssenceFilter/energy_point_gems.json | 新增能量淤积点原始数据,用于地点词条解析 |
| agent/go-service/essencefilter/ui.go | 推荐方案按地点可用 slot2/slot3 过滤,避免推荐不可行武器/方案 |
| locations := st.MatchEngine.Locations() | ||
| if len(locations) == 0 { | ||
| log.Info(). | ||
| Str("component", "EssenceFilter"). | ||
| Str("step", "PlanRecommend"). | ||
| Msg("skip recommend output: no locations loaded") | ||
| return | ||
| } |
There was a problem hiding this comment.
这里在 locations 为空时直接 return,导致用户界面不会输出任何“方案推荐/未毕业武器”信息;但 HTML 模板本身允许 Sections 为空(仍可显示未毕业武器列表)。建议不要直接跳过渲染:即使没有 locations,也至少渲染 plan_recommend(Sections 置空),并可在 UI 上提示“地点数据未加载/无法生成地点方案”。
| if len(sections) == 0 { | ||
| log.Info(). | ||
| Str("component", "EssenceFilter"). | ||
| Str("step", "PlanRecommend"). | ||
| Msg("skip recommend output: no feasible location plans") | ||
| return | ||
| } |
There was a problem hiding this comment.
这里在 sections 为空时直接 return,会让用户完全看不到“未毕业武器列表”等输出;而模板中 range .Sections 本来就可以为空(只是不会显示地点卡片)。建议仍然调用 plan_recommend 渲染(Sections 为空即可),并在必要时追加一条 UI 文案说明“当前没有可行地点方案”。
| if len(sections) == 0 { | |
| log.Info(). | |
| Str("component", "EssenceFilter"). | |
| Str("step", "PlanRecommend"). | |
| Msg("skip recommend output: no feasible location plans") | |
| return | |
| } |
fix #1682
Summary by Sourcery
解析
energy_point_gems数据以重新生成 EssenceFilter 的 location,并确保方案推荐只包含在各个 location 实际可行的武器。Bug Fixes(错误修复):
Enhancements(功能增强):
energy_point_gems.json而非weapons_data.json中推导 locations,并增加更严格的映射和基于当前skill_pools的校验。energy_point_gems.json生成locations.json的新build_locations工作流及解析规则编写文档。Documentation(文档):
build_locations.py添加 README 文档,包括用法、参数,以及基于energy_point_gems.json的解析规则。Original summary in English
Summary by Sourcery
Parse energy_point_gems data to regenerate EssenceFilter locations and ensure plan recommendations only include weapons feasible at each location.
Bug Fixes:
Enhancements:
Documentation: