Skip to content

Feat/ai tag suggestion#55

Merged
wnzzer merged 22 commits into
mainfrom
feat/ai-tag-suggestion
May 3, 2026
Merged

Feat/ai tag suggestion#55
wnzzer merged 22 commits into
mainfrom
feat/ai-tag-suggestion

Conversation

@wnzzer
Copy link
Copy Markdown
Owner

@wnzzer wnzzer commented May 2, 2026

No description provided.

wnzzer added 12 commits May 2, 2026 22:12
Plan 2,覆盖 spec §特性 2。9 个 TDD 任务:TS 类型 → validator → 特征
提取 → prompt → 编排 → AISuggestModal → 测试 → Tags.vue 集成 → ship。
全前端,无 Rust 改动(schema 已存在)。
- stripJsonFences 改用 regex,容忍 AI 输出前后的散文 / 单行 fence
- parseAndValidate 在 root 不是对象(如 null)时给出明确报错
- 补 3 个 MatchRefresh 变体测试(average 缺 metric / streak 大小写)
- 补 3 个递归 TagCondition 测试(and 嵌套合法 / and 嵌入非法 / not 包装错值)
orchestrator 串联 get_my_summoner → get_match_history_by_puuid → featureExtract
→ requestAIContent → parseAndValidate → sessionStorage 缓存;
markAdopted 供 AISuggestModal 采用后标灰态;
7 单元测试覆盖 ok / insufficient / aiError / parseError / 缓存命中 / forceRefresh。
Copilot AI review requested due to automatic review settings May 2, 2026 15:51
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an “AI 推荐” workflow to the Tags settings page: it fetches the current user’s recent matches, builds an AI prompt to generate tag rules, validates the AI JSON strictly, shows suggestions in a modal, and allows one-click adoption into persisted TagConfigs.

Changes:

  • Integrate an AI 推荐 button + AISuggestModal into Tags.vue, refreshing tag list after adoption.
  • Introduce tagSuggest service (feature extraction → prompt → AI request → validation → sessionStorage cache + adopted marker).
  • Add comprehensive Vitest coverage for validator/prompt/extraction/orchestrator + modal component behavior.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
lol-record-analysis-tauri/src/views/settings/Tags.vue Adds AI button + mounts AISuggestModal, reloads tags after adopt
lol-record-analysis-tauri/src/components/tags/AISuggestModal.vue Modal UI for loading/empty/error/ok states and “adopt” flow
lol-record-analysis-tauri/src/types/tagSuggest.ts TS schema mirror for TagCondition/TagConfig + AI result types
lol-record-analysis-tauri/src/services/ai/tagSuggest/index.ts Orchestrates fetching matches, calling AI, validating, caching
lol-record-analysis-tauri/src/services/ai/tagSuggest/validator.ts Strict schema validator + JSON fence stripping
lol-record-analysis-tauri/src/services/ai/tagSuggest/prompt.ts System + user prompt construction
lol-record-analysis-tauri/src/services/ai/tagSuggest/featureExtract.ts Extracts compact per-game features for AI input
lol-record-analysis-tauri/src/services/ai/tagSuggest/tests/*.spec.ts Unit tests for tagSuggest pipeline modules
lol-record-analysis-tauri/src/components/tags/tests/AISuggestModal.spec.ts Component tests for modal rendering and actions
docs/superpowers/plans/2026-05-02-ai-tag-suggestion.md Implementation plan/design notes for the feature

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +87 to +90
it('generates id (uuid) and sets isDefault=false / enabled=true', () => {
const raw = JSON.stringify({ good: [suggestion()], bad: [] })
const r = parseAndValidate(raw)
expect(r.good[0].id).toMatch(/[a-f0-9-]+/)
import { invoke } from '@tauri-apps/api/core'
import TagConditionNode from './TagConditionNode.vue'
import AISuggestModal from '@renderer/components/tags/AISuggestModal.vue'
import { championOption } from '../../components/type'
wnzzer added 10 commits May 3, 2026 00:00
- 编排器把 puuid 暴露在 ok outcome 里 + 模块级缓存,消除 adopt() 里的
  第二次 get_my_summoner 调用以及缓存命中时的多余 IPC
- rawCacheKey 清理移到 finally,AI throw 时也不留 sessionStorage 垃圾
- 好/坏标签卡片渲染用 v-for sections 去重 ~46 行模板
- validator 测试 stub crypto.randomUUID,断言用确定值代替 lenient 正则
- Tags.vue championOption 改用 canonical 路径 + import type
实测 AI 会输出 filter "gold>=12000" + refresh "average gold>=12000" 这种永远
成立的套套逻辑,且没样本量门槛。

- SYSTEM_PROMPT 加 3 类常见错误示例 + 2 条良好 few-shot 规则(中路稳健 / 暮气沉沉)
- validator 增加 hasFilterRefreshTautology,filter.Stat 和 refresh.Average/Sum/Max/Min
  同 metric + 同 op 时拒绝(误杀风险低,因为没有合理用例)
…拒绝模式不一致

实测 AI 把娱乐模式数据贴上"排位..."标签,desc 和 filter.queue 完全脱节。

- GameFeature 加 queueName 字段(小队列 id 表覆盖排位+常见娱乐模式),AI 输入直接看到中文模式名
- SYSTEM_PROMPT 加"模式严格分开" + "desc 必须与 filter 一致"两条硬约束 + 反例 + 大乱斗 few-shot
- validator 增加 descMatchesQueueScope:含娱乐 queueId 时 desc 不能含"排位",反之亦然
- validator: NAME_MAX 5→7(让 name 能塞下"模式前缀+主题+调侃")
- validator: 新增 hasNonSrLaneWord,filter 全是娱乐模式时 name/desc
  不能含 上路/中路/下路/打野/辅助/ADC 等 SR 路位词
- prompt: 鼓励"儒雅+调侃"语气,强制非 SR 模式去路位
- few-shot 改成更有梗的"排位刺客 / 乱斗咆哮王 / 暮气连败王"
- QUEUE_NAMES 扩展到 ~20 个常见模式(含 海克斯乱斗、飞升、雪球、AI 等)
- 未知 queueId 默认 '娱乐模式'(绝大多数情况下成立),不再返回信息量为 0 的'其他模式'
- 新增分类 fallback:未知但属于 ranked/matchmaking 范围的归为对应类别
编排器调用 get_game_modes 拿到 Rust 维护的中文映射并注入 gameToFeature;
featureExtract 只保留分类兜底(排位/匹配/娱乐模式)。新模式以后只在
Rust 那边加一行就能流到 AI 输入,不需要改 TS。

- featureExtract: 移除 QUEUE_NAMES 硬编码 map,新增 QueueNameMap 注入参数
- index: 模块级缓存 get_game_modes 结果,requestTagSuggestions 一次性拉取
- prompt: 简化模式参考块(AI 直接用 queueName)
实测 AI 输出:
- "海克斯混子" 配高伤害规则归到好标签 → 命名负面 vs 分类褒义 互相打脸
- "乱斗高光" 配 desc "海克斯乱斗" → 不同队列 (450 vs 2400) 用了模糊词

- validator: 好标签 name 含 混子/翻车/水货/咸鱼/废物/掉分/演员/弱鸡/荣鸡/坑货/送人头 → 拒绝
- prompt: 加"好/坏命名情绪一致" + "name 和 desc 模式名必须一致"两条硬约束 + 海克斯乱斗 few-shot
@wnzzer wnzzer merged commit 447cbc6 into main May 3, 2026
3 checks passed
wnzzer added a commit that referenced this pull request May 3, 2026
- validator 测试 stub crypto.randomUUID,断言用确定值代替 lenient 正则
- Tags.vue championOption 改用 canonical 路径 + import type
@wnzzer wnzzer deleted the feat/ai-tag-suggestion branch May 3, 2026 00:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants