Skip to content

feat: 翻译任务支持按任务选词库并通读摘要 - #436

Open
MaurUppi wants to merge 12 commits into
buxuku:mainfrom
MaurUppi:feat/summary_glossary_enhancement
Open

feat: 翻译任务支持按任务选词库并通读摘要#436
MaurUppi wants to merge 12 commits into
buxuku:mainfrom
MaurUppi:feat/summary_glossary_enhancement

Conversation

@MaurUppi

Copy link
Copy Markdown
Contributor

摘要

启动台「翻译已有字幕」(及共用配置条的其它翻译路径)增加:

  1. 按任务选用词库glossaryIds 三态:未选 = 全部已启用,[] = 不用,显式 id = 含已停用库)
  2. 可选通读摘要:独立 AI 调用,失败降级不阻断翻译;仅 AI 翻译服务会把摘要注入 system
  3. 摘要 / 翻译共用本任务词库:摘要对整份源文命中一次(上限 100 条);翻译按批命中注入

不含 dist/.next/app/ 等编译产物。

行为要点

  • 生成摘要默认关;summaryProvider 缺省跟随翻译服务(须为已配置 AI)
  • 出厂摘要稿在「翻译」页独立编辑;专名保持源字幕写法,中文译名交给各批词库(避免摘要改写成表内译名后和英文源文对不齐)
  • 平凡文件自动跳过摘要(cue < 20 或预计不足 2 批)
  • 校对 sidecar meta 写入 glossaryIds + episodeSummary,不 bump 版本;独立校对回落全局已启用
  • zh / en 文案成对;yarn check:i18n 通过

内部文档(本 PR 一并带上)

  • docs/docs/summary_glossary_enhancement/summary_glossary_enhance_plan.md
  • docs/docs/summary_glossary_enhancement/evidence.md
  • docs/docs/summary_glossary_enhancement/summary_glossary_test.log(S01E06 手测归档,API Key 已脱敏)

用户文档:docs/docs/advanced/glossary.mdcustom-prompts.mdfeatures/subtitle-translation.md

测试

  • yarn test:glossary
  • yarn test:summary(35)
  • yarn test:proofread-data
  • yarn check:i18n
  • 手测:mac-arm64 打包应用翻译 A.French.Village.S01E06.eng.srt(647 条 / 13 批),摘要注入首批 system,sidecar 落盘 676 字

手测建议

  1. 翻译页确认「摘要提示词」面板与恢复出厂
  2. 启动台 → 翻译已有字幕:打开生成摘要、选用词库
  3. 英 → 中、AI 翻译服务;看日志「通读摘要 / 已注入 / 任务词库 N 个」
  4. 设置切 English,核对配置条 / 快照条 / 阶段标签

任务可显式选用参与匹配的词库,不再只能跟随全局 enabled 开关。

- core: 新增 resolveTaskGlossaryEntries(glossaries, ids)。筛选发生在
  normalizeGlossaries 之后、enabled 过滤之前:给了 ids 就按 ids 取(忽略
  enabled,关掉的库仍可被显式勾上),没给就按 enabled。两条路径都保持全局
  order 排序与「同原文首个胜出」语义,冲突判定不随勾选顺序变化。
- core: 新增纯函数 describeGlossarySource() 生成来源标注,
  logGlossaryConflicts / logGlossaryMatches 的 context 追加「任务词库 N 个」
  或「全局已启用」,便于排查未命中原因。
- glossaryManager: 新增 getTaskGlossaryResolution(ids);
  resolveEnabledGlossaryEntries / getActiveGlossaryResolution 保留为等价包装,
  校对链路调用点不受影响。
- translateWithProvider: 已有 10 个位置参数,扩参走尾部 options 对象
  ({ glossaryIds }),避免错位;未传 options 的调用点日志字节级不变。
- types: IFormData.glossaryIds?: string[]。undefined = 回落全部已启用(旧配方
  与历史快照的语义),[] = 明确不用词库,两者全链路不得互相塌缩;非数组的畸形
  输入按 undefined 走旧行为。
- renderer: 新增 GlossarySelectControl 配置条多选,未建库时显示「去词库」链接
  且不挡开始;停用库标注「已停用」仍可勾选;提供「恢复默认」写回 undefined。
- test: scripts/test-glossary.ts 扩 testTaskGlossarySelection,覆盖 undefined /
  [] / 指定 id / 勾中 disabled 库 / order 不随勾选顺序变 / 未知与重复 id /
  畸形输入 / 入参不被改写。63 → 87 passed。
任务选用的词库随 sidecar 落盘,校对台的单条优化 / 批量优化 / 重翻失败
三条链路都按任务词库工作,而不再固定读全局已启用。

- types/proofreadData: ProofreadDataMeta 增加 glossaryIds?: string[];meta 归一化
  抽出 normalizeProofreadMeta + 纯函数 normalizeMetaGlossaryIds 做边界校验。
  非数组 → undefined(旧 sidecar 回落全局已启用),数组只保留字符串成员,
  [] 保持 [](明确不用词库)。旧 sidecar 归一化后不写出显式 undefined 键。
  PROOFREAD_DATA_VERSION 保持 2:meta 是展开合并、未知字段原样保留,无需 bump。
- proofreadData: writeProofreadDataFromFiles 增加 glossaryIds 参数,条件展开写入
  meta;fileProcessor 调用点传 formData?.glossaryIds。
- subtitleCorrectionService: CorrectionParams 增加 glossaryIds?,
  getActiveGlossaryResolution() 改为 getTaskGlossaryResolution(params.glossaryIds);
  不传时语义与此前完全一致。correctionRunner 从 formData 透传。
- ipcProofreadHandlers: 三个 handler 的 payload 增加 proofreadDataFile?,
  经 readSidecarGlossaryIds 读取 meta.glossaryIds。无路径或读取失败 → 记 warning
  并回落 undefined,独立校对模式(直接拖字幕进校对台)行为不变。
- renderer: ProofreadEditor 把 file.proofreadDataFile 透传给 SubtitleEditToolbar、
  BatchAiOptimizeDialog 与 useRetranslateFailed,三处 invoke 带上该路径。
- test: 新增 scripts/test-proofread-data.ts 与 yarn test:proofread-data,覆盖
  保留显式 id / 保留 [] / 旧 v1 与 v2 sidecar 无该键 / 五种畸形输入 / 非字符串
  成员剔除 / 未知 meta 字段前后兼容。32 passed。
Product-level defaultSummaryPrompt plus settings.summaryPrompt with a
restore-to-factory control. Translation page is now providers + summary
panel. Empty stored drafts fall back to the factory template.
…nslation

Add the test:summary seam and the runtime stage: optional per-file
read-through before translate, independent AI provider, trivial-file skip,
degrade-without-fail, and one-pass system prompt injection. Task UI can
toggle the stage; non-AI translation keeps the summary for reference only.
Document task-level glossary selection, the translation-page summary
prompt, ${summary} as an optional placeholder, and the generate-summary
flow on the subtitle translation guide.
… size

Plain-text summary calls now set structuredOutput=disabled so json_schema
providers do not force the src/tr protocol. Trivial-skip and cost logs use
the translation provider's capped batch size, not the summary provider's.
Add summaryFollowLabel, document ${summary} in systemPromptTips, and show
task glossary state plus follow-hint on the snapshot bar. zh/en keys stay
paired; check:i18n passes.
The factory draft no longer asks the summary model to rewrite names into
glossary Chinese. Recap stays in the target language; names stay as in the
source so later translation batches can align. Glossary appendix is for
not inventing extra names. Tests and the enhancement plan follow.
The S01E06 hand-test facts stay. Retract the claim that source names in
the summary prove the glossary table was sent. Record whole-episode
matching versus per-batch injection, and that keeping source names is now
the factory spec (b533bef).
Keep the archived task log with the plan and evidence chain. Drop the
step-2 implement handoff; it is process-only and not needed upstream.

@buxuku buxuku left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

主要 Findings

  • [P1] 关闭摘要后重跑,旧摘要仍会注入 AI 翻译。
    main/helpers/fileProcessor.ts:280-310 清理阶段状态时没有清理 episodeSummary;main/translate/index.ts:197-200 又无条件传入它,最终由 main/translate/services/ai.ts:171-
    177 注入 system prompt。用户第一次开启摘要、之后关闭并重跑时,旧摘要仍会影响译文并产生额外 token 成本。应在关闭摘要时清空,或仅在 generateSummary === true 时传递。

  • [P1] resume 快路径会把“未生成摘要”直接标成 done。
    main/helpers/fileProcessor.ts:402-440 在已有翻译产物的 pipeline 任务中跳过字幕段,428-432 只要开关开启就发送 summarizeEpisode: 'done',不会调用 runEpisodeSummaryStage。
    因此摘要首次失败、或翻译完成后才开启摘要时,重试会显示完成但永远没有摘要。

  • [P1] “不超过 400 字”没有运行时约束。
    types/summaryPrompt.ts:15 明确要求 400 字;但 main/helpers/episodeSummaryCore.ts:83-90 接受任意非空响应,main/helpers/episodeSummary.ts:291-315 直接持久化并重复注入。PR
    自带日志 summary_glossary_test.log:34 已记录 676 字摘要。应在剥离思考内容后限制、截断或降级,并校验 resume 时复用的旧摘要。

  • [P1] 摘要调用没有使用任务实际的扩展服务商配置。
    main/helpers/taskProcessor.ts:191-203,557-579 为正式翻译加载 customParameters;但摘要阶段在 main/helpers/episodeSummary.ts:79-102,270-277 重新从 store 取原始 provider。
    自定义 headers/body 参数因此不会传入摘要请求,某些已配置服务商会只在摘要阶段失败并被静默降级。应传入 extendedProvider,或对摘要 provider 也加载 configurationManager 配
    置。

  • [P2] 主进程只检查 isAi,没有检查服务商是否已配置。
    main/helpers/episodeSummary.ts:79-102 不检查 API key、URL、model 等必填字段。UI 的 TaskControls/TaskWizard 有校验,但 resume 或其他非 UI 路径仍可能发起一个必然失败的摘
    要调用。应复用主进程侧的配置校验。

  • [P2] 摘要用量统计丢失 input tokens。
    main/helpers/episodeSummary.ts:269-286 明确写入 input_tokens: undefined,只保存 completion tokens。规格要求把 usage 记录到 file.summaryUsage,目前无法排查摘要输入成本。

  • [P1] PR 提交了完整真实字幕、译文和运行环境信息。
    docs/docs/summary_glossary_enhancement/summary_glossary_test.log:1-3512 包含整集源字幕/译文、用户本机路径、API endpoint、模型配置以及首批完整 system prompt。即使 API
    key 部分遮罩,这仍是版权内容与环境信息泄露风险,不应作为仓库测试证据提交。应改成合成样本或脱敏摘要,并清理历史。

Standards

  • renderer/components/tasks/GlossarySelectControl.tsx:20-23、SummaryGenerateControl.tsx:18-28,44,50、renderer/components/TaskControls.tsx:160-168 新增大量 any/as any,违
    反 docs/docs/development.md:87-88 的“TypeScript 类型完整”要求。

  • 摘要服务商校验在 TaskControls.tsx、TaskWizard.tsx、SummaryGenerateControl.tsx 重复,属于可能的 duplicated code / shotgun surgery。

  • scripts/test-summary.ts:25 直接导入 renderer helper,跨越 scripts 与 renderer 边界,后续构建环境变化时容易失效。

Spec

  • 规格要求摘要 provider 必须是“已配置的 AI 服务商”,实现只保证 isAi。
  • 规格要求 resume 时已有摘要才跳过;当前实现会在无摘要时直接标记完成。
  • 规格要求保存摘要 usage;实现丢弃 input token。

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