Skip to content

feat(tts): IndexTTS-2.5 专业用法沉淀:上游能力接通、读法修复与循证文档 - #1109

Merged
ThreeFish-AI merged 10 commits into
feature/1.x.xfrom
ThreeFish-AI/indextts-2.5-usage-doc
Aug 21, 2026
Merged

feat(tts): IndexTTS-2.5 专业用法沉淀:上游能力接通、读法修复与循证文档#1109
ThreeFish-AI merged 10 commits into
feature/1.x.xfrom
ThreeFish-AI/indextts-2.5-usage-doc

Conversation

@ThreeFish-AI

Copy link
Copy Markdown
Owner

背景

  • 本次变更要解决的问题:科普视频配音只用到了 IndexTTS-2.5 上游能力的一小部分(服务端仅透传 6 个推理参数、文本预处理仅 2 行替换),且既有文档存在多条被源码核验证伪的结论。
  • 关联上下文/Issue/文档:INDEXTTS-2.5-ADVANCED.md(新增循证篇)、ISSUE-164(年份读法陷阱)、VOICE-CLONING.md

核心变更

  • 读法修复与成门:已上线三集共 8 句「2025 年」被读成「两千零二十五年」(wetext 的 date 规则被空格击穿),修稿并新增 READING_TRAPS 内容门(每条规则附实测错读证据与正反例单测)。
  • 发音标注接通<行|HANG2> 拼音通道经 ASR 回转写证实生效(标注档与汉字对照组转写完全相同);build_narration.py 派生 text(字幕/字数)与 ttsText(送合成),存量 604 句缓存零失效。
  • 上游参数透传:采样参数族 + text_normalization + interval_silence + --seed(实测带种子字节一致,A/B 可信的前提)接通,/health 增能力位,旧服务硬失败防假验证。
  • 测量基建:新增 tts_bench.py(环境体检 + 成对 A/B + ASR 判据),漂移定因为热节流(换页/分配器/泄漏均排除),75s 冷却下极差比 1.016–1.047×。
  • 参数 A/B 定论(两项均维持上游默认)length_penalty 实测惰性(11 对含 ±2 极值,尾覆盖改善 0/11 句);repetition_penalty 的 3.5–10 是稳定平台,两端更差——上游无据可查的 10.0 事后成立。
  • 预设与工具:非生产三档名义向量归一到 Σvec=1.0(alpha 跨档可比,有效注入不变);新增 sunny-pure/sunny-clear 候选档(不动生产档);prospect_ref.py 增保真度门与 --accept 验收模式。
  • 文档校准:修正 10+ 处既有结论(df 方向写反、Σvec×alpha≤0.8 实为本仓自创口径、参考音频 15s 硬截断、束宽在 MPS 上非线性等),每处附实测或源码坐标。

风险与回滚

  • 主要风险:低——所有新能力默认关闭(采样参数不传即上游默认),存量缓存经 604 句逐句比对零失效;三集台词改动仅 8 处年份空格,音频未重合成。
  • 回滚方式:git revert 对应提交即可;narration 改动可由 build_narration.py 重新生成。

验证证据

  • 单元测试:media/pipeline/tests/ 46 → 110 项全过(新增 digest 采样不变量、发音标注三失效模式、读法陷阱正反例、tts_bench 判据、保真度门)。
  • 集成测试:ttsText 全链路验证(build → tts 合成出不同音频 → captions 零标注泄漏);三集内容门 FAIL 0 / WARN 0;check_series 五规则全绿。
  • E2E/Workflow:发音标注 ASR 回转写 A/B(拼音 6 档、CMU 6 档);参数 A/B 22 对配对样本;同口径 RTF 对齐实验。
  • 覆盖率/关键截图:tts.py --list-styles 9 档预设表;tts_bench.py A/A 判定输出。

影响范围

  • 前端:无。
  • 后端:media/pipeline/scripts/(tts.py / tts_server.py / tts_sample.py / build_narration.py / check_script.py / prepare_ref.py / prospect_ref.py + 新增 pron_marks.py / tts_bench.py)。
  • GitHub Actions / 文档:新增 INDEXTTS-2.5-ADVANCED.md(715 行)与 PRON-GLOSSARY.md;更新 VOICE-CLONING.md、README、skills/03、skills/07、knowledge-map、issue.md。

Next Best Action

🤖 Generated with Claude Code

循证核验上游源码(~/tools/index-tts HEAD 4f8792f)后,把三类此前隐式继承或完全
未使用的能力接通到配音管线,并全程保住存量缓存零失效。

采样参数族(temperature/top_p/top_k/length_penalty/repetition_penalty/
max_mel_tokens/interval_silence/text_normalization)此前全部隐式取上游默认,
任何调优都得改服务源码。现经 SynthesizeRequest 显式化并对齐 webui 取值域校验;
/health 增加 supports_sampling_params / supports_seed / supports_text_normalization
三个能力位,客户端在旧服务上请求非默认值时硬失败——否则 Pydantic 会静默忽略未声明
字段,而摘要已按新参数变了,会得出「改了参数没效果」的假验证。不暴露 do_sample:
上游 infer_v2_5.py:780 用字面量 True 覆盖了弹出值,webui 的复选框是装饰性控件。

随机种子:上游 do_sample 恒 True 且全链路无种子,同句每次合成都是不同的 take。
实测同文本带 --seed 777 两次字节完全一致、不带则不同——这是所有参数 A/B 可信的
前提,故一并接通并提供 --seed-offset 作「换一条 take」的逃生口。

发音标注 <原文|读音>:上游有完整实现却零使用。用「故意互换多音字读音」的对照实验
证实拼音通道生效(MFCC-DTW 距离 0.133 对「汉字写法」组 vs 0.320 对基线,分离度
2.4×);CMU 音素通道判定随分析窗口翻转,记为未验证。新增 pron_marks.py 承载语法与
校验:正文孤立 < 会被上游正则粘连并吞掉正文、标注错必然读错(原字被丢弃)、
pinyin.vocab 在运行时从未被读取故非法拼音静默通过——三个失效模式全部前移为 ERROR。
build_narration.py 据此派生 text(剥离标注,供字幕与字数预算)与 ttsText(带标注,
供合成),标注自带原字故一处书写零副本。

缓存兼容:摘要沿用「未使用即省略」规则,全部参数取默认时逐字节不变。已对三集
604 句逐句比对新旧摘要——0 句变化;改任一采样参数则正确失效。

测试 46 → 74 项(+8 摘要不变量与区间校验、+20 标注解析与三个失效模式)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
已上线三集共 8 句年份被念错:`2025 年` 读成「两千零二十五年」而非「二零二五年」。
根因是「排版约定 × 归一化规则」的隐式耦合——逐字稿有「数字与汉字间加空格」的排版
习惯,而 macOS 上实际的归一化引擎 wetext 的 date 规则要求数字与「年」字面相邻,
插入空格即回落到基数读法。实测空格敏感性矩阵里**只有 4 位年份这一条被击穿**:
`6 月`/`88 页`/`47.6%`/`第 3 章`/`1.2 节` 加不加空格都正确。

修复面:三集 narration.md(唯一维护处)共 8 句去掉该空格并重跑 build,命中句为
EP1 p0-01/p0-11、EP2 p0-01/p0-12/p5-15/p5-22、EP3 p0-16/p2-06。归一化是幂等的,
故此类修复可逐句增量做,不需要关 text_normalization(关掉反而丢失 %/小数/量词
这些本来就正确的能力)。

check_script.py 新增 READING_TRAPS 内容门,把**实测确认会读错**的 7 类写法固化:
4 位年份带空格、三段版本号 2.5.1→「二.五点一」、连字符区间 3-5 倍→「三减五倍」、
±3%→「百分之正负三」、10x→「十x」、整句无汉字→被 use_chinese 逐句嗅探路由到英文
归一化(IndexTTS 2.5→two point five)、1080P→「一千零八十P」(WARN)。每条 message
都带实测输出。反例组同等重要:调研初稿曾把 `0.5~1.0 秒` 与 `9:30` 也列为缺陷,实测
证明它们其实正确(零点五到一点零秒 / 九点三十分),凭直觉扩大清单会造成误伤。

prepare_ref.py 的 --duration 上限从 30 收到 15 并硬失败:上游 _load_and_cut_audio
对参考音频只取前 15 秒、静默丢弃尾部且 verbose 关闭时无日志,故 16–30 秒的样本会有
一半以上内容永不进模型。默认值同步 15→12(推荐区间 10–14,文献侧 speaker similarity
在 ~10 秒后饱和)。顺带更正两处归因:「保留原采样率」对模型无影响(上游无条件重采样
到 22.05 kHz),-3 dB 峰值归一的作用不是防止小音量削弱相似度(CAMPPlus 与 w2v-BERT
两条相似度主路径都有 CMVN、对全局增益免疫),真正伤相似度的是削波。

测试 74 → 88 项(+14 读法陷阱正反例)。三集内容门复跑 FAIL 0 / WARN 0。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
新增 media/pipeline/INDEXTTS-2.5-ADVANCED.md(九章)作为 VOICE-CLONING.md 的正交
补充:后者是「怎么用现有能力做完一集」的单一参考,本文回答「上游到底有什么能力、
机制为何、还能怎么更好」。全文不复制任何本仓参数值,只写上游事实(file:line 锚定
HEAD 4f8792f)与二者的映射;含两张 Mermaid(文本前端链路、情感融合)、16 项 ROI
排序路线图、迁移地雷表、9 条 IEEE 参考文献。

调研推翻的既有结论(逐条校准,均附实测或源码坐标):

- Σvec×alpha≤0.8 是**本仓自创口径**而非上游行为——上游 infer() 从不归一化,
  normalize_emo_vec 全仓唯一调用点是 webui.py:665 的自定义向量分支,且那条的 0.8
  作用在已乘 emo_bias 的和上、且在 alpha 之前。emo_bias 8 维严重不等权
  (calm 仅 0.5625、surprised 0.6875)⇒ 从社区/WebUI 抄来的参数在本仓实际强
  16–33%,跨来源迁移不可靠。另:alpha 等于「替换本人语调的百分比」仅当名义向量和
  为 1.0,lively/confident/positive 不满足,其 alpha 跨预设不可比。
- 「alpha ≤0.8 推荐(官方建议)」把向量总和上限与 alpha 上限混为一谈——alpha 本身
  只被 clamp 到 [0,1];实操该盯的是残差保留率 1−Σ(w·α)。
- 「df 0.97 护密集技术句清晰度」方向写反:df<1 = 更快 = 咬字更紧更糊,护清晰度应
  df>1。duration_factor 的真实作用面是 S2M 时间轴重采样(常数 1.72 = 梅尔帧率
  86.13 ÷ 语义帧率 50),不产生音高偏移、不消耗 token 预算。
- 「数字句贵在 token 数暴涨」归因错误:该句 token 仅 17→23,且文本 token 只进一次
  prefill 不参与 AR 循环;真实原因是「短句 × 3 束」。
- 「束宽线性放大整集墙钟」在 MPS 上不成立:分段 profile 实测 s2mel 占 45–73%、
  T2S 仅 18–46%,整集 1→3 束仅 +4%。正确口径是 CUDA 近线性、MPS 近乎免费。
- 本机跑的是 U-DiT 而非论文的 Zipformer 变体(config dit_type="DiT",全仓 grep
  zipformer 零命中)⇒ 论文 Table 4 的 S2M 0.017 与头条「RTF 提升 2.28×」不适用于
  本机,别引用。IndexTTS2.5-RL 权重亦未公开发布(已核 GitHub/HF/ModelScope)。
- 参考音频「5–15 秒(上限 30s)」与「保留原采样率」两处均已更正(见前一提交);
  长样本代价不在条件提取(按样本缓存只算一次)而在 ref_mel 作为 CFM 前缀每句都进
  25 步扩散——交错 3 组实测 12s→6s 使 s2mel 中位降 54%,但音色语速随之变,不可为
  提速缩短参考。
- tts_server 对「向量 + 情感音频」互斥的理由更正:上游并非静默丢弃音频,真实问题
  是 emo_alpha 被消费两次。
- 方案对比表的 mlx 行更新:index-tts-2.5-mlx 0.1.1 已支持 2.5,但砍掉全部情感控制
  与束搜索,不可直接替换。

配套:新增 PRON-GLOSSARY.md 易错字台账(含 9 个科普高频多音字候选清单,明确「确认
读错才标注、不预防性标注」);skills/03 补读法纪律表与标注规约;skills/07 决策树补
束宽口径与「A/B 前先固定 seed」一闸;docs/.agents/issue.md 记 ISSUE-164(年份空格
陷阱的表因/根因/处理/防范);knowledge-map 登记新文档。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
路线图 #4(此前标为优先级最高的诊断)已完成。按社区 MLX 移植 README 的确切口径
(RTF = synth ÷ 音频时长,load 与 clone 均排除;warm、3 次均值;该移植主动砍掉全部
情感控制)直调 infer() 重测本机,剥离 HTTP/mp3/情感向量/长跑降频等本仓口径差异:

  对齐档 RTF = 4.37(音频 3.34s / synth 14.60s;gpt 2.75 / cfm 10.10 / vocoder 1.41)

缺口分解:管线开销 2.1×(整集 9.0 → 4.37)× 硬件 2–3×(M4 base 120GB/s·10 核 vs
M5 Pro 273+GB/s·~20 核),残差仅 1.3–1.9×。旁证是分段占比:本机 cfm 占 70.8%
(3.02× 实时),对方 int8 的 cfm 只占 35%(0.15× 实时)——而 cfm 成本正比于
「参考帧 + 目标帧」,我们用 12s 参考(1034 梅尔帧)而对方 benchmark 的参考长度未披露,
这是残差最合理的落点。**结论:换栈不被 RTF 数字支持**(且 MLX 要付出砍掉全部情感控制
的代价),真正的杠杆仍是 cfm 前缀长度——那是管线侧的事,但 §5 已论证不可为提速缩短参考。

同时沉淀一条比上述任何数字都重要的发现(新增 §6.4):**本机当前无法支撑性能 A/B**。
同一份 neutral 工作量在 6 次连续调用内从 14.49s 漂到 48.74s(3.4×);交错设计的逐对
比值摆动 0.75×/1.60×/0.75×,把 1.0 夹在中间,真实效应被漂移淹没。漂移有可识别的指纹
——「不该变的段变了」:num_beams 不作用于 S2M 却让 cfm 从 10.10s 涨到 19.01s,6s 参考
的归一化 cfm 反而高于 12s。唯一可信的是冷起第一块(两次独立冷起测同一工作量得
14.60s 与 14.49s,差 0.8%)。测量期间交换区仅剩 0.8–1.5GB。

据此写入性能测量协议(先查 swap 余量、每次只测一个冷起块、绝不用顺序阶梯做参数归因、
交错前先过 A/A 复现性、判据优先用分段计时器),并把它作为路线图新 #6,成为
length_penalty 与 repetition_penalty 两项 A/B 的前置——二者此前标为「待验证」,现明确
标注受阻于测量环境而非缺乏方案。路线图编号相应顺延至 17 项。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
路线图 #6#7/#8 的前置)完成。此前记录「本机同一工作量 6 次连续调用漂 3.4×,任何
耗时 A/B 都不可信」,但未定因。新增 media/pipeline/scripts/tts_bench.py 逐条排除后,
三个候选只剩一个:

  内存/换页      逐次换页增量最大 31 MB(8 连跑,可用内存 9.7 GB)  → 排除
  MPS 分配器累积  driver_allocated_memory 恒定 7.62/10.00 GB,+0.00 GB → 排除
  进程泄漏       RSS 反而下降 1834 → 1130 MB                        → 排除
  **热节流**     单调爬升 15.36→36.46s(2.37×,全部由 cfm 承担
                 10.61→27.14s),冷却后恢复                          → 成因

**加 75 s 冷却间隔即合格**:无冷却 8 连跑极差 2.37×;75 s 冷却后稳定窗口极差
1.016×(CV 0.007)与 1.047×(CV 0.018)。稳态值 ≈15.2 s ⇒ RTF 4.5,与 §6.3 冷态
对齐档 4.37 相差 3%,反证那个数字可信。重要推论:**加内存或清 MPS 缓存都不会有帮助**
(二者已被证伪),冷却是唯一有效手段,占空比约 5:1。

判据设计被实测纠正三次,均已写进代码注释与测试文档,以免重犯:

1. 最初用「随运行序的秩相关」当门 —— 秩相关**无标度**,稳态尾部 15.19/15.31/15.42
   (极差仅 1.016×)会被判成「完美单调上升 +1.00」。改为量级判据(极差比/CV/相对漂移)。
2. 接着用「弃头部、判尾部」 —— 只能从头裁,遇到末次突然**变快**(15.15 → 13.35,
   风扇起转)就永远裁不掉,把明显合格的环境判成不合格。改为**最长连续稳定窗口**。
3. 静态内存门被逐条否决:「可用内存 ≥10 GB」硬门误杀了换页仅 31 MB 的可用环境;
   用命令行扫描找「其它实例」连续两次把调用方的包装 shell 误判成实例(其 argv 里含
   python 与脚本名)。故静态指标全部降级为提示,实例检测改用精确的端口占用;判据只用
   直接测量量(换页增量 + 稳定窗口复现性)。

工具能力:--check-only 前置体检;A/A 复现性判定(含逐次分段计时、RSS、MPS 分配器占用、
换页增量);--cooldown 冷却节奏;--empty-cache 用于验证分配器假说;--json 落盘读数。
判据由 tests/test_tts_bench.py 用本轮三组真实读数钉死(7 项,含三次纠正各自的回归用例)。

路线图相应更新:#6 标记完成,#7(length_penalty)与 #8(repetition_penalty)从
「受阻于 #6」改为「已可做」,并在 §6.5 写明必须遵守的六条测量协议。测试 88 → 95 项。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
## #9 预设名义向量归一到 Σvec=1.0(已做)

只有 Σvec=1.0 时 emo_alpha 才等于「替换掉本人语调的百分比」,否则被稀释成 α·Σvec、
跨预设不可比。把 lively/confident/positive 的名义向量归一,alpha 反向缩放
(α_new = α_old × Σvec_old)。`--list-styles` 的「有效注入」列现在恒等于 alpha。

精确说法:有效注入 w=vec×alpha 在数学上不变,但上游把 w 截断到 4 位小数
(infer_v2_5.py:608 用 int() 截断而非四舍五入),而 0.33/0.455 恰在截断边界上,
故 21 个分量里有 3 个差 1e-4(相对 0.03%)。**不写成「逐项完全一致」——那是过度断言。**
这三档未被任何已上线剧集使用(三集用 sunny-steady / passionate),缓存零影响;
生产档逐字不变由 test_production_presets_untouched 钉死。

## #13 prospect_ref 保真度门(已做)

原评分 5 项全是风格指标、0 项保真度,而保真度损伤事后无法弥补(WildSpoof
arXiv:2602.05770 Table 2:事后增强提升 UTMOS 却让 SECS 0.35→0.28)。新增只否决不加权
的一组:削波、底噪绝对电平、动态范围(SNR 代理)、DC 偏置、有效带宽(识别低码率转码)。
同时修掉两个自相加强的旧缺陷:静音占比从相对阈改绝对阈(相对阈在有底噪的录音上会
系统性低估静音、扣分项失效);谱质心从全带改 300–5000 Hz 限带(全带会把「嗓音明亮」
与「有嘶声」记成同一信号,与上一条叠加使「脏但亮」的段落双重虚高)。

验收:成片在用的 me-1@180s 段**被放行** ✅,且正确标出更脏的窗口(底噪 −46 dB /
动态 29 dB);超 15s 与 5 kHz 带限的反例均被拦。

开发中被测试抓出并修掉的两个自造 bug:
- `bandwidth_khz` 用 np.convolve(..., "same") 平滑对数谱,**两端少算抽头且不归一化**,
  把空频段的 −240 dB 抬到接近 0 dB,使带宽恒报 Nyquist(5 kHz 带限信号被测成 16 kHz)。
  改为按实际抽头数归一化。
- 底噪指标的隐含前提没写明:它是「帧 RMS 第 10 百分位」,窗口内**没有停顿**时测到的是
  轻声段而非底噪(恒幅正弦上给出 −13.6 dBFS 的假警报)。改为先检查是否有足够安静帧,
  不足 5% 时记 None 并旗标「底噪不可估」——宁可说测不了,不给错的数。

## #10 / #11 候选档就位(新增而非改动生产档 ⇒ 缓存零影响)

`sunny-pure`(happy 单载,砍掉有效强度仅 0.5625/0.6875 的 calm/surprised 配料)与
`sunny-clear`(= sunny-steady 但 df 1.05,护术语密集句清晰度——df 方向勘误见 §3.4)。
新增 §7.1 写清定档动作,并明确「放弃也是合法结论」:若 A/B 差异落在噪声内,标注
「实测无差异、维持现档」比强行改预设(整集重录 2 小时)更划算。

## #12 工具就绪(录音须本人操作)

`prospect_ref.py --accept`:整段评估候选样本,对**保真度**下硬结论、风格指标只作参考
(风格的真正判据是纯克隆小样而非样本本身),并给出合格线与下一步命令。

## #14 / #15 关闭为「不做」

#14 进程级分片并行:#6 已定因为热节流而非吞吐受限,两个进程只会更快撞上同一个热墙。
#15 降 diffusion_steps / 关 CFG:二者是 infer() **函数体内的局部字面量**(:829-830),
既非参数也非模块常量 ⇒ 无法传入、无法 monkeypatch,只能改上游源码——那是 glossary.yaml
被否决的同一模式(不受本仓版本控制、换机即静默失效)。已记入迁移地雷表。

## ASR 回转写判据(并据此更正一条结论)

tts_bench 新增成对 A/B 模式(逐句交替先后顺序以抵消热漂移)与 whisper 回转写判据
(CER + **尾部覆盖率**,后者是 #7「吞尾」的直接判据且不受热漂移影响)。注意
whisper.transcribe(路径) 会 shell 调 ffmpeg 而本机 PATH 上没有,须先 librosa.load
到 16 kHz 再喂 numpy 数组。

**据此更正**:CMU 音素通道此前记为「不可判定」,实为**生效**——ASR 转写显示基线念
「Cloud」而标注 `<Claude|K AE1 T>` 档念成「看」(kàn≈kæt)。根因是 MFCC-DTW 在「差异只
集中在首词、句尾大段共享」时分辨力不足(只差 2%、判定随分析窗口翻转)。同时拼音通道
拿到了文本级铁证:标注档与「汉字对照」档转写**完全相同**、都不同于基线。
教训写进文档:验证发音类改动优先用回转写,声学距离只作辅助。

测试 95 → 110 项(+11 保真度门与带宽判据、+4 预设不变量)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
按 §6.5 的测量协议(固定 seed、冷却节奏、逐句交替先后顺序以抵消热漂移)跑完两项参数
A/B,判据用 whisper 回转写的**尾部覆盖率**与 CER 而非墙钟——后者会被热漂移淹没,
而 ASR 判据不受热影响。

## #7 length_penalty:机制成立,但在本工作负载上**实际惰性**

| 对比 | n | Δ尾覆盖中位 | 尾覆盖改善句数 |
|---|---|---|---|
| 0.0 vs 0.8(35–49 字长句) | 8 对 | +0.0000 | **0/8** |
| −2.0 vs +2.0(全区间极值) | 3 对 | +0.0000 | **0/3** |

8 对里 7 对输出**逐项完全相同**(时长到 0.01s、CER 到 3 位、尾覆盖);即使拉到区间两端,
可测效应也只有秒/字 +0.4%。代码路径已核实确实到达 BeamSearchScorer
(transformers_generation_utils.py:2232),**不是**像 do_sample 那样被静默忽略。

机制解释:length_penalty 只在比较**长度不同**的已完成假设时起作用;3 条束在同一长度收束
时除数 len^lp 是公共因子、排序不变。本仓旁白 35–49 字,束间长度差异不足以让它咬合。

**同时作废上一版的记载**:此前记「某长句 lp=0 的 GPT 段 180.5s vs lp=0.8 的 19.3s(4.9×)」
并据此推测有大收益。那是热漂移伪影(同批数据里 s2mel 在同等音频长度下从 18.3 跳到
33.1s,而 lp 根本不作用于 S2M)。本轮在合格环境下用 11 对样本得到零效应,可以定论。

## #8 repetition_penalty:10.0 落在稳定平台区,上游选择事后成立

| 对比 | n | CER 中位 | 尾覆盖中位 | 逐对差异 |
|---|---|---|---|---|
| 10.0 vs 3.5(8 句混合长度) | 8 对 | 0.060 / 0.060 | 0.929 / 0.929 | **8/8 逐项相同** |
| 1.0 vs 20.0(全区间极值) | 3 对 | 0.095 / 0.057 | 0.889 / 1.000 | Δ尾覆盖 +0.111 |

**极值证伪是这一项的关键**:只做 10 vs 3.5 会得到「零效应」,却无法区分「真惰性」与
「参数没到达模型」。拉到 1.0(关惩罚)vs 20.0(上限)后差异立刻显现 ⇒ 参数确实生效,
3.5–10 只是一段平台。两端都不如 10.0:rp=1 中位更差;rp=20 中位虽好但方差极大——
同批第 1 句崩到 CER 0.395 / 尾覆盖 0.56(惩罚过强会压掉韵尾所需的稳态码)。

结论「维持 10.0」同时给上游那个无据可查的默认值补上了事后依据:它处在既避开「无惩罚
导致拖音/漏字」又避开「过强压掉韵尾」的中间带。极值组 n=3,只支撑定性结论;且该结论
与音色绑定(惩罚强度依赖 logit 绝对尺度),换参考样本需重测。

两项都不改预设——改档即整集重录,而实测收益为零。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
@ThreeFish-AI
ThreeFish-AI merged commit a025a06 into feature/1.x.x Aug 21, 2026
1 check passed
ThreeFish-AI added a commit that referenced this pull request Aug 21, 2026
…tools-video

合并 #1109(IndexTTS-2.5 专业用法:发音标注、tts_bench、读法修复)。两处冲突均为
「双方同位新增」,处置:

- pipeline/README.md 脚本表:双侧行都保留(source_ledger / pron_marks / tts_bench)。
- issue.md:编号撞车——基线的 ISSUE-164(年份空格读错,2026-08-20)日期早于本分支
  的同名条目,保留基线 164,本分支三条顺延为 ISSUE-165/166/167;全仓核查无旧编号
  残留引用(knowledge-map 的 ISSUE-164 指向正是基线条目,语义正确)。

合并后验证:管线测试 130 项全绿(含 #1109 新增 66 项,注意其 test_prospect_ref 需
--with soundfile);check_series 2 系列 / 4 集 FAIL 0。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
ThreeFish-AI added a commit that referenced this pull request Aug 21, 2026
- qa_frames.py:SUBTITLE_BOX_H_PX 注释算术修正(框顶 137.4 / 墨水顶 ≈118,
  132 是其间灵敏度选择,非「≈125 留余量」);侵入块宽度改闭区间 b-a+1,
  对齐「≥24px」宣称
- P0Hook.tsx:时点锚改用 at(),不再冒充分镜 beat 窗口——check --check-scenes
  由常驻 WARN 2 清零(WARN 通道信噪比,ISSUE-167 原则)
- motifs.tsx:删两处恒等三元(DispatchTable value 列 / CodeCard 行色)
- knowledge-map + CHANGELOG:测试数 63 → 130(合并 #1109 后实际口径)
- skills/08:语速单位笔误「300 字/秒÷60」→「300 字/分 ÷ 60 = 5 字/秒」

验证:pytest 130 passed;check --check-scenes FAIL 0 WARN 0;tsc 通过;
ruff lint/format 全绿;check_series FAIL 0。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
ThreeFish-AI added a commit that referenced this pull request Aug 21, 2026
* feat(video): 新系列「Claude Code 通俗全解」首集,管线多系列化与 B 型信源取证基建;

新增《拆开 Claude Code:让 AI 动手的四层机制》——开源课程 Learn Claude Code 的
工具与执行四章(Agent Loop / Tool Use / Permission / Hooks)成片工程:170 句 /
4048 字 / 7 幕 / 39 镜,陶土橙内核 + 石青外挂机制 + 警示红拒绝闸门三色契约
(对底色实测 6.06 / 9.19 / 6.00 : 1),配音 sunny-steady + me-bright.wav。

为承载「独立新系列」与「非论文信源」,同步做三件基建:

1. series.json 多系列化:顶层单 series 对象改为 seriesList[],check_series.py
   相应分层——反串线规则跨系列全局生效(两系列口播互不引用),顺序类规则按系列内
   判定(episode 的 1..N 连续性只在系列内成立,slug 仍全局唯一);
   test_check_series.py 增 6 例多系列语义用例。

2. Stage ① 泛化为两类信源:skills/01 更名 01-source-extraction.md,A 型论文正文
   原样保留,新增 B 型(文档/代码/课程站点)大节——双轨取证(仓库固定 commit +
   站点正文)、证据三级(三级「他人对闭源产品源码的分析」必须带归属句)、数字口径
   须可复算、二次信源分歧清单必备。新增 source_ledger.py(fetch/list/verify,
   repo 类固定提交 raw 指纹漂移即 FAIL,site 类只比归一正文、漂移报 WARN)
   + 11 例单测;管线测试 46 → 63 项全绿。

3. 两条实测口径沉淀:skills/02 写明 chars_per_min=280 是含停顿的等效口径
   (实测纯语速 301 字/分 + 停顿开销抵消,全片时长估算误差约 1%),推论「字数是
   硬约束、句数不是」;skills/06 新增可复用视觉母题库,并显式化 A 档冻结清单的
   同步义务限于同系列内。

内容侧两处校准:课程标注的章节行数在固定提交上任何口径都复算不出,改为口播只说
趋势、画面给实测值与取数日期;课程「循环里只改了一行」经逐章 diff 实测只在第二章
成立,改用「骨架四章一字未改,变的只有执行那一步怎么写」(总行 141→255 增 81%,
而循环函数恒在 20–28 行)。另实测确认 pnpm 11 的 ERR_PNPM_IGNORED_BUILDS 对本
工程无害,刻意不改 A 档冻结文件去消音。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(issue): 记录 ISSUE-164 站点规模数字与固定提交复算不一致、ISSUE-165 pnpm 忽略构建脚本实为无害噪声;

ISSUE-164:与 ISSUE-162(取数姿势错,读了未水合 DOM)是**不同失效模式**——本例站点
为 SSG 预渲染、取数姿势正确,但站点标注的四章行数(102/135/180/232)相对其自身代码
已陈旧,在固定提交上任何口径都复算不出(s04 声称 232 而实测非空仅 213)。处置:口播只
说趋势、画面给实测值+口径+取数日期,并新增 source_ledger.py 把「信源陈旧可发现」变成
机器门。防范:凡引用他方标注的规模数字,必须在固定版本上自己复算并写明口径;同一信源
的散文与代码新鲜度要分别评估。

ISSUE-165:ERR_PNPM_IGNORED_BUILDS 只表示 postinstall 被跳过,不等于依赖不可用。
esbuild 的平台二进制走 optionalDependencies、不依赖 postinstall,端到端验证(transform
调用 + remotion bundle 跑到 100%)确认旧写法完全可用,故撤销全部「修复」以保四集 .npmrc
逐字节一致。防范:报错不等于故障,先做端到端验证再动手——为消掉一条无害提示而改动跨集
冻结文件,比那条提示本身更贵。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(video): P1 两处可读性缺陷——斜叉压亮字互相干扰、抽屉标签压到章号;

以已合成的 67 句真实音频时长重算 beat 帧位后抽帧复检发现(合成音频前用等长外推
时看不出来,因关键帧落点不同):

1-D 停止标记打叉:斜叉直接压在亮色 tool_use 文字上,两者互相干扰致都难辨认。
改为叉线加底色描边(两层线)+ 打叉后标记文字压暗,让「被否定」的语义清晰。

1-E 十个抽屉:最长标签「工具与权限上下文」与固定在右下角的章号重叠。标签加
右侧让位内边距。

顺带验证:39 个 beat 窗口在真实时长下最短 7.8 秒,无动画被截断风险;全片外推
14:10,落在预算窗内。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(video): 2-G 分批动画改由句边界驱动,去掉硬编码帧数;

P2 全幕音频合成完毕后按真实时长复检发现:2-G 三组 batch 的落位写死为 12/34/52
帧,与口播推进脱钩——配音时长一变就会出现「三组都排完了,旁白才刚说到第一组」。
改为由 beat 内句边界传入(p2-25 讲划第一组、p2-26 讲夹在中间的单独一组),说明
文字同样跟随。复检确认:batch 1 恰在「连着能并行的划成一组」时出现,batch 2/3
落在「中间夹着不能并行的就单独一组」。

同类风险已全仓扫过:P0/P4 各余一处硬编码 delay,均为 beat 开头即出现的常驻角标,
不与后续句子绑定,保留。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(video): P3 三处缺陷,含一处画面与旁白语义相反;

P3 全幕音频合成后按真实时长逐镜复检,抓出三处:

1. 3-F 优先级堆叠方向反了(实质错误):stack 数组按优先级升序声明,却正序渲染并
   高亮首项——画面等于宣称「你的全局配置最大」,而旁白说「公司策略压过本地配置」。
   改为倒序渲染(最高优先级在顶)+ 亮度阶梯按优先级递增 + 箭头自下向上,并把
   「压过」改成跨第 1 行到第 3 行的括号连线,明确是口播点名的那一对;收束时只留
   这两级亮着。反枚举原则下用亮度而非色相编码层级。

2. 3-C 审批卡盖住三道闸门:卡片弹出时闸门整体上移让位,「停在第三道闸门前等待」
   这层语义才看得见。

3. 3-G「命中即出」三条标签随各级漏斗宽度参差:改为每级占满容器、卡片内部居中,
   标签统一挂在最宽一级的右边界,读作同一个侧向出口。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(video): 4-D 插槽压环重叠,SlotRing 改四角布局并写明定位契约;

P4 前四镜按真实音频时长复检发现 4-D 严重错位:四个插槽卡片压在环上并互相重叠,
「工具执行之后」被完全遮住,右侧还有溢出碎片。根因是 SlotRing 的绝对定位偏移
(size*0.24 / 0.68 一类的经验值)与调用方给的容器尺寸不匹配。

改法不是继续调偏移,而是把契约显式化:SlotRing 导出 SLOT_W / SLOT_GAP,四个
插槽固定排在四角,并在 docstring 写明「容器至少 size+2*(SLOT_W+SLOT_GAP) 宽、
size+220 高,环须居中」;调用方按该公式推导容器与环位,不再各自试参数。

顺带把闸门迁移轨迹的终点对准右上插槽左缘(此前偏低、离目标远,读不出「搬进这个
插口」),回流箭头起点也改为按容器尺寸推导。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(video): 4-G 对撞由一次性瞬间改为持续抵抗,补足安全主题收口的四秒;

P4 全幕音频齐后复检 4-G(全片安全主题的收口镜):旁白「配置里的禁止和询问仍然
要再走一遍」有四秒多,而冲击波在 16 帧内就衰减完毕,此后画面静止——观众在这句
的大部分时间里看不到「顶住」这个动作,语义落空。

改为:弹回后保持小幅慢周期的抵抗抖动,冲击波每 34 帧复发一次,读作「持续施压 →
持续被顶回」,与「仍然要再走一遍」的持续性对应。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(video): 配音完成后的交付记录,并沉淀「分幕音画复检」方法论;

配音 170/170 完成(sunny-steady + me-bright,纯语音 13.20 分钟,实测语速 307 字/分,
墙钟 2.1 h)。时长双口径门通过:估算 14.5 / 实测含时距 14.2 分钟,均在预算窗
13.0–14.6 内;字幕 srt+vtt 各 170 cue;主题对比度 FAIL 0;尾幕渐黑窗口贴合末 beat
(末帧灰度 0.0118,无提前收尾的长黑屏)。

同时把本轮最有复用价值的一条做法写进 skills/08:**分幕音画复检**——配音是全流程最
慢的一环(2 小时量级),而动画与旁白的错配只在真实时长下才暴露,故不要干等成片,
每合成完一幕就用该幕真实时长重算 beat 帧位、逐镜抽帧目检(remotion still 首帧含
打包约 100 秒、之后缓存仅 4–5 秒,39 镜可负担)。本集据此修了 9 处缺陷,其中 3 处
在等长外推下全部漏检,规格里列出了三种漏检模式与各自症状。

并固化一条纪律:beat 内动画时点一律由句边界推导,不得写死帧数(配音时长一变即脱钩),
例外只有 beat 开头即出现的常驻角标。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(pipeline): 字幕侵入判据改用几何法,消除半透明字幕底导致的整片假报;

草渲 QA 首跑刷出 500+ 条「角标侵入字幕安全区」WARN,逐帧目检画面完全干净——是判据
错了,不是视频错了。

根因:Subtitle.tsx 的底是半透明 rgba(6,8,12,0.68) 压在 #0E1116 上,实测灰度仅
≈0.10–0.14,而文字笔画 0.45+。旧判据「亮列连通段 + 最宽段=字幕框」用文字阈值找框,
于是把每个汉字当成一个独立亮段(14 字字幕 → 14 段、最宽段仅 20px),字幕自己刷出
十几条「侵入」。试过降阈值找框同样不稳:抗锯齿把框切碎,放宽到能连成片时又与页面
底色(0.045)分不开。

改用几何法:字幕框高度是**已知量**(marginBottom 54 + padding 12×2 + 行高 44×1.35
≈ 125,取 132),故只检查框**上方**那条窄带(y∈[H-160,H-132))内有无宽度 ≥24px 的
亮块——这正是「角标是否压进字幕安全区」的原始问题,且与 skills/06「角标 bottom ≥ 150」
同一口径。无阈值自由度,不受底色透明度影响。

测试:修正 test_intrusion_warns 的合成帧几何(旧 fixture 把侵入物画在框占位区内,
本身就不符合真实形态),新增 test_translucent_subtitle_does_not_self_report 锁死本次
假报。64 项全绿。

复跑:全片 7 幕 FAIL 0,WARN 由 500+ 降到 2 条,且两条均为刻意设计(p0-02/03 的
「画面凝住」、p6-06/07 的信源卡停留)——16×16 均值哈希看不出光标闪烁与字幕换行。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(issue): 记录 ISSUE-166 视觉判据与渲染实现不匹配致整片假报;

草渲 QA 首跑 500+ 条「角标侵入」WARN 而画面实际干净。根因是判据模型与渲染实现不
匹配:判据假设字幕框是实心亮矩形,而 Subtitle.tsx 的底是半透明 rgba(6,8,12,0.68)
(实测灰度 0.10–0.14 << 文字阈值 0.45),于是每个汉字各成一段、字幕把自己每个字都
举报成侵入物。

记下三条防范:① 视觉判据必须与渲染实现对账,写前先看目标元素的 CSS/几何;② 优先
用几何量(尺寸/边距/行高,来自代码常量、零自由度)而非亮度阈值(经验值,随配色与
抗锯齿漂移);③ 假报成本不低于漏报——500 条 WARN 会让「FAIL 0 · WARN N」失去信噪
比,等于关掉检查,故新判据须先在一帧已知干净的画面上验证零报警。

另记一条误修过程:先试「两级阈值」仍不稳(0.09 时抗锯齿切碎框、放宽又与页面底色
分不开)——「参数怎么调都不对」这个症状本身就说明模型错了,应立即回头质疑模型。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* feat(video): 《拆开 Claude Code》终渲交付(14:14,1080p30),并补渲染耗时实测口径;

终渲产物:out/final.mp4 —— 14:14.73 · 1920×1080 @30fps · h264 yuv420p 196 kb/s ·
aac 189 kb/s · 42.1 MB;配套 captions.srt/vtt 各 170 cue + cover.png(标题卡帧)。

终渲全分辨率抽帧复检 FAIL 0,仅 1 条 WARN(p0-02/03 的「画面凝住」为刻意设计——
模型吐出命令后光标停闪,16×16 均值哈希看不出光标闪烁);尾幕末 6 句 FAIL 0 WARN 0,
渐黑窗口贴合末 beat(末帧灰度 0.0118),未复现第三集「渐黑提前收尾致长黑屏」。
交付前复验:无死链、系列一致性 FAIL 0、12 条信源指纹全部未变。

顺带把实测耗时口径写进 skills/09:草渲 0.5x 6.0 分钟、终渲 1080p 8.2 分钟(25642 帧)。
即整片渲染是分钟级,远快于同集配音的 2.1 小时——排期上「渲染慢」是错觉,真正的长尾
在 TTS;改一处场景重渲全片只要 8 分钟,可放心多轮迭代。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(review): 评审六条意见修复——判据注释对账、时点锚去 w() 化与口径刷新;

- qa_frames.py:SUBTITLE_BOX_H_PX 注释算术修正(框顶 137.4 / 墨水顶 ≈118,
  132 是其间灵敏度选择,非「≈125 留余量」);侵入块宽度改闭区间 b-a+1,
  对齐「≥24px」宣称
- P0Hook.tsx:时点锚改用 at(),不再冒充分镜 beat 窗口——check --check-scenes
  由常驻 WARN 2 清零(WARN 通道信噪比,ISSUE-167 原则)
- motifs.tsx:删两处恒等三元(DispatchTable value 列 / CodeCard 行色)
- knowledge-map + CHANGELOG:测试数 63 → 130(合并 #1109 后实际口径)
- skills/08:语速单位笔误「300 字/秒÷60」→「300 字/分 ÷ 60 = 5 字/秒」

验证:pytest 130 passed;check --check-scenes FAIL 0 WARN 0;tsc 通过;
ruff lint/format 全绿;check_series FAIL 0。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(review): 评审三条意见修复——CLI 示例形态纠错、几何算式补全与对比度口径对齐;

三处均为文档/注释层缺陷,不改判据行为与已交付成片:

1. source_ledger.py 模块 docstring 的三条用法示例把 `--project` 写在子命令
   之后,而该参数定义在顶层 parser——照抄即报 `unrecognized arguments`
   (实测复现)。改为参数在前,与 README / skills/01 的既有写法统一;三个
   子命令(list / verify / fetch)按新形态实跑通过。

2. issue.md ISSUE-167 的字幕框算式漏算第二个 padding(上下各 12 共 24),
   得 125 而非 137.4,致其与 qa_frames.py 注释对「检查线 132 在框顶之上
   还是之下」的说法相反。补全算式并写明 132 的落位依据(框顶 137.4 之下、
   墨水顶 118 之上)。常数本身取对,仅中间数更正。

3. mech 对比度四处口径对齐 9.19 → 9.18:`--check-theme` 实测与精确 WCAG
   计算均为 9.1847(两位舍入 9.18),此前 theme.ts / planning.md /
   CHANGELOG 写 9.19、仅 README 写 9.18。视觉契约 SSOT 的自述数字须与验证
   工具输出一致,故统一为 9.18。

验证:管线测试 119 项全绿;check_series FAIL 0;内容门 --check-scenes
FAIL 0 WARN 0;source_ledger verify 12 条信源 FAIL 0;--check-theme
FAIL 0;tsc --noEmit 通过;ruff 0.14.14 lint/format 全过。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
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.

1 participant