换掉 TTS 引擎后才发现,API 调用只是开始
从 Kokoro 迁移到 Google Chirp 3 HD 后,真正的挑战不是调用 API,而是让生成的语音精确嵌入原视频的时间轴。本文记录 Katto 配音系统的完整技术实现。
2026年9月13日
Katto 的 AI 配音功能已经上线一段时间。创作者可以选择一个短视频片段,指定目标语言,系统返回翻译后的配音版本。最初的实现基于 Kokoro,支持 8 种语言。
最近我把主力语音引擎换成了 Google Cloud Text-to-Speech 的 Chirp 3 HD。目标看起来很明确:提升音质,增加语种。现在 Katto 编辑器里可以选择 19 种配音语言和 12 个精选音色。
我原本以为这主要是个 API 替换工作。
结果完全不是。
生成一句自然的语音很容易。让这句话精确地填进另一个说话人留下的时间槽,才是配音的真正难题。
如果原说话人用了 2.4 秒,翻译后的语音需要 3.2 秒,再好的 TTS 模型也救不了这个片段。要么语音挤到下一句,要么字幕飘移,要么只能加速到听起来很赶。
TTS 请求本身,反而是整个系统里最简单的部分。
最终的处理流水线
缓存的词级时间戳
|
v
固定时间槽的短语片段
|
v
长度感知的翻译
|
v
Google Chirp 3 HD 逐短语合成
|
v
基于 FFmpeg 的有界音频对齐
|
+----> 同源片段生成的翻译字幕
|
v
最终 MP4 封装每个阶段的存在,都是因为更简单的版本在某个地方失败了。
1. 把原始时间轴当作数据保留
Katto 的转录流程已经输出词级时间戳。我不会把整段文本一次性送去翻译和合成,而是先分组成短语。
短语的结束点出现在句子标点、超过 0.6 秒的停顿,或者长度即将超过 6 秒的时候。每个片段保留原始的起止时间。这些数字成为后续所有阶段的约束条件。
对全文一次性合成可能听起来更流畅,但会丢失把语音放回视频时间轴所需的锚点。短语级合成在保留自然语调的同时,也保留了有用的时间边界。
2. 翻译要考虑发音时长,不只是语义
书面翻译正确,不等于配音翻译可用。有些语言表达同样的意思需要更多音节。逐字翻译可能保留了所有细节,但因为塞不进时间槽而无法使用。
对每组短语,我让 Claude Haiku 生成口语化的翻译,要求更短的措辞和更少的音节。返回结果保留每个源片段的索引。
这个提示词是音频系统的一部分。它的任务不只是语言准确性,还要减少后续的时间拉伸量。
这仍然是启发式方法。LLM 无法保证时长,因为选定的音色也会影响节奏。音频层会实际测量生成的 WAV 文件。以目标语言和源片段为键的进程内缓存,让 worker 存活期间的重复渲染可以复用翻译结果。
3. 逐短语调用合成接口
每个翻译后的短语作为独立请求发送到 Google Cloud Text-to-Speech REST API,输出 24 kHz LINEAR16 格式音频。音色名称遵循 Google 文档规定的 locale-Chirp3-HD-speaker 格式。
Google 支持的 Chirp 3 HD 语种比 Katto 当前开放的更多。我刻意把产品限制在 19 种语言,这些语言走通了完整路径:UI、locale 映射、字体、字幕和降级逻辑。API 声称支持某个语言,不代表周边产品能正确处理它。
4. 在不破坏音质的前提下让语音适配时间槽
合成后,我会比较生成时长和原始槽位:
target_duration = segment["end"] - segment["start"] ratio = generated_duration / target_duration
如果语音稍长,用 FFmpeg 的 atempo 滤镜在保持音高的同时加速。加速上限设为 1.3 倍。
这个上限很重要。早期版本用 1.6 倍,更多短语能塞进去,但有些音色听起来不自然地仓促。完美对齐没有意义,如果结果让人不舒服。
每个调整后的短语放置在主轨道的原始偏移位置。短语音之间留下自然停顿。较长短语得到有界修正。这解决不了所有病态翻译,但执行了更有用的规则:保持可懂度优先于追求数学上的完美对齐。
5. 让语音和字幕共享同一个时钟
合成响应给我音频,但不给新语音的可靠词级时间戳。编造词级时间会让字幕看起来精确,实际上是错的。
因此配音片段使用短语级字幕,从用于语音的同一批翻译片段生成。它们的起止时间已经和音频放置位置匹配。
渲染器还会选择覆盖目标文字的字体。拉丁字体不够用于日语、中文、印地语或阿拉伯语。片头标题和 AI 钩子走相同的本地化路径,屏幕不会说一种语言显示另一种。
生产环境的常规问题也很重要
不是每个精选音色在我测试的每个 locale 都能用。如果选定音色不可用,Katto 用该性别的已知默认音色重试一次。编辑器的实时预览调用同一个 Google 引擎。用另一个模型的样本会让用户选择一个他们永远收不到的音色。
生产 API 密钥限制为 VPS 的 IPv4 地址,但 VPS 访问 Google 时优先用 IPv6。合法请求被拒绝,直到我强制 TTS 调用走 IPv4。API、密钥和代码都对,网络路径不对。
配音生成独立的视频变体。如果翻译、合成、字幕渲染或封装失败,原始片段保持完整。对于最初支持的 8 种语言,当 Google 路径被禁用或未配置时,Kokoro 仍可作为后备方案。
什么变了,什么没变
可见的结果是配音语言从 8 种扩展到 19 种,加上可选音色和实时预览。
更深层的改进是架构层面的。翻译、语音、字幕、叠加层和视频渲染现在共享一个时间单位:短语片段。
系统不克隆原说话人,不做唇形同步,不编造生成的词级时间戳。很长的翻译仍然可能超出理想槽位。这些限制好过声称流水线无法兑现的精度。
我以为自己在换语音引擎。结果是收紧了媒体流水线几乎每个阶段之间的契约。
API 调用是简单的部分。让结果属于原始时间轴,才是真正的工作。
Katto 把长视频切成短竖屏片段,现在可以把这些片段配音成 19 种语言。如果你在做多语言视频,我很想知道你如何在不让音色听起来很赶的前提下处理时间对齐。