旁白配音
npm run tts 将 src/timeline.ts 中的每一行旁白输出到 public/audio/<语言>/<键>.wav,
并附带 Cartesia 的词语时间戳(<键>.words.json),同时将实际行时长写回 src/audio.generated.ts。
各行按引擎、语音、模型、语速和文本内容缓存:仅新行或已编辑的行会重新配音。
npm run tts -- en 或 -- es 可限制只处理一种语言。
Cartesia 配置
- 设置位于
video.config.mjs(tts部分):模型sonic-3.6-2026-08-27,语速1。 - 英文语音:
5568a7df-e5ab-4442-9fae-2e9ba1b15ad8(en-GB)。 CARTESIA_API_KEY按以下顺序查找:- 环境变量;
- 视频文件夹中的
.env文件(已加入 gitignore;可复制.env.example); ~/Documents/repos/.env。
- 切勿输出、回显或提交密钥。检查密钥是否存在但不显示,例如
test -n "$CARTESIA_API_KEY" && echo set。
引擎与 Kokoro 回退
video.config.mjs 中的 tts.engine:
auto(默认):当找到密钥且服务响应时使用 Cartesia;否则整个语言改用 Kokoro(本地,免费)并输出警告。一个语言绝不会混合两种语音:如果 Cartesia 中途失效,整个语言会使用 Kokoro 重新生成,下次运行时若 Cartesia 恢复则再次重做。cartesia:失败时直接报错,不回退。kokoro:保持离线模式。语音:af_bella(英文)、ef_dora(西班牙文)。Kokoro 不提供词语时间戳,因此字幕将按比例分配时间。
输出中出现关于 Kokoro 的警告意味着该视频没有 Cartesia 语音:在交付视频时应说明这一点。
西班牙语语音
voices.es 默认为 null,直到制作了西班牙语版本。从 Cartesia 语音库中选择一个西班牙语语音,试听脚本中的示例行,将其 ID 记录到 video.config.mjs 中(es: { id: '<语音-id>', language: 'es' }),并将 'es' 添加到 SETTINGS.voices(如果需要西班牙语字幕,也添加到 SETTINGS.subtitles)。
发音
TTS 朗读旁白文本;字幕显示书面文本。当 TTS 读错数字或符号时,为行提供口语化版本作为 say 的第四个参数,并保持文章书面形式作为字幕:
say(0.3, '它完成了 14/20 项任务。', 'Resolvió 14/20 tareas.', {
en: 'It solved fourteen out of twenty tasks.',
es: 'Resolvió catorce de veinte tareas.',
})
- TTS 朗读口语化版本(缓存会在该行改变时重新配音);行时长也基于口语化版本。
- 字幕显示书面文本,按比例分布到整行(词语时间戳属于口语词,因此不会用于该行)。
- 正常情况使用书面文本(如“14/20”、“83 %”、“p = 0.0018”),仅在试听后 TTS 读错时添加口语化版本。
- 斜杠、版本字符串(如“gpt-5.6”)、文件名和缩写通常是常见问题。对每行包含此类内容的语句进行试听。
音频质量检测
npm run audio-qa(生成 out/audio-qa.md):
- 将每行标准化至相同响度(每个文件版本执行一次);
- 当音频源峰值达到 -0.1 dBFS 时标记为削波;
- 当行时长超过文本长度预估的 1.6 倍时标记为过长:这是音频内容混乱或重复的迹象。试听每个被标记的行,如确有错误则重新配音(略微修改文本,或删除其 wav 文件);
- 在
npm run render之后,测量out/中每个混音相对 -16 LUFS 集成响度,±1 LU(真峰值 -1.5 dBTP),若某混音不达标则退出并返回错误码 1。
配音完成后,再次运行 npm run lint:实际时长会替换预估时长,可能使视频偏离目标时长或使字幕超过 17 字符/秒。
背景音乐
背景音乐由本地生成(npm run music,缺失时 npm run render 会自动生成;需要 Python3 及 numpy,或 uv)。在有旁白播放时,音乐音量会被压缩至原音量的 30%。将 SETTINGS.music 设为 null 可关闭音乐。