#2100·read-frog

[BUG] AI 分句产出的 cue 没有长度上限,而 optimizer 只能合并不能切分

Author: T0MYYYCreated Aug 18, 2026Updated Sep 19, 2026
LabelsbugStale

Before you report

  • I have searched existing issues to avoid duplicates
  • I have tried with the latest available version (or can reproduce on latest)

Current vs. Expected behavior

开启 AI 分句后会出现单条超长字幕。截图里单条占据 5~7 行、覆盖半个画面;在页面上读取 read-frog 注入的 shadow DOM 实测,单条 cue 长度为 375 字符,对比 MAX_CHARS_CJK = 30

根因是一个隐含假设被打破了。optimizeSubtitles 的设计输入是词级碎片,碎片天然比目标短, 所以它只需要"往上凑",不需要"往下切" —— 代码里因此只有合并操作,没有任何 split。这在原 路径上是成立的。

AI 分句把这个前提颠倒了:它输出的是完整句子,可能天生就超过上限,而下游没有任何手段处理。

具体证据:

  • DEFAULT_SUBTITLES_SEGMENTATION_SYSTEM_PROMPT 的 rule 1("Complete sentences only")和 rule 2("Never split at incomplete clauses ... MUST be merged")全是合并压力,没有任何 一条设置长度上限。一个长复合句就能产出 200+ 字符的 cue。
  • optimizeSubtitlesprocessSubtitles 里的 wouldExceedLimit 只触发 flushBuffer(), 即"在追加下一个输入片段之前要不要先收尾"。如果单个输入片段本身已经超长,它照样被无条件 push 进空 buffer,下一轮原样吐出。
  • rebalanceToTargetRange 同理,只有 mergeSegmentPair,且只在 currentLength < min 时 触发。
  • isQualityPoor(>20% cue 超 250 字符时启用 pause detection)这层兜底对此无效:pause detection 同样只改变输入片段之间的 flush 边界,对单条超长片段是 no-op —— 恰好在它本该 生效的场景失效。

结果是 MAX_WORDS = 15 / MAX_CHARS_CJK = 30 在开启 AI 分句时退化成只参与合并判断、但从 不被强制执行的装饰性常量。

预期行为: 无论上游产出什么长度,进入渲染的 cue 都应受 MAX_WORDS / MAX_CHARS_CJK 约束。

与 #2099 / #2101 的关系: 这条路径上不存在任何长度约束,所以降低 temperature(#2099)只能减 轻、不能消除该问题。截图里「上下两段都是中文」则由 #2101 解释(AI 分句阶段模型翻译了原文), 与本 issue 的超长问题是彼此独立的根因。三者修法各不相同。

Image

To Reproduce

  1. 配置任意 LLM provider,开启 AI 分句。
  2. 播放一个带 word-level 自动字幕(scrolling-asr 格式)、且语速较快长句较多的视频(讲座、 播客类最容易触发,口语 vlog 反而不明显)。
  3. 观察到单条字幕占据三行以上。

触发前提是送进模型的输入为词级。开启 AI 分句时 utils/subtitles/fetchers/youtube/index.ts:425 会直接 return parseStandardSubtitles(...), 绕过 parseScrollingAsrSubtitles。实测同一视频同一份 timedtext:开启时 6468 条 fragment (平均 4.4 字符),关闭时 375 条(平均 79.9 字符)。人工上传字幕的视频输入是句级的, 不容易触发。

Which area(s) are affected? (Select all that apply)

Other

Extension version (if applicable)

  • Extension channel/version: Chrome Web Store 1.46.0

Provide environment information

bash
- Extension channel/version: Chrome Web Store 1.46.0

Additional context

修复方向有两层。

短期:在分句 prompt 里补一条长度上限规则。改动小,但 prompt 层的长度约束模型遵守率有限, 只能算缓解。

根治:给 optimizer 加一个 split pass。难点在于切分需要发明一个原数据里不存在的时间点 —— 这也正是当初没写 split 的原因。两种做法:

  1. 按字符数比例在 cue 内部线性插值切分。实现简单,但对语速不均的段落会偏。
  2. 把词级时间戳一路保留到 optimizer(目前分句之后就丢了),切分时回查真实边界。准确,但 需要改数据流。

方案 2 和 #2099 里提的"让模型只返回句子边界索引、时间戳由代码回查"是同一个方 向 —— 都指向"词级时间戳不该在管线中途被丢弃"。如果决定往那边走,两个 issue 可以合并成一 次重构。

需要的话我可以提 PR。