本文介绍 Timeline Studio 如何将 Hojo TTS Light 80M 集成到浏览器中,实现无需后端推理服务的中文及中英混合配音。内容涵盖 ONNX 模型切片、WebGPU 自回归推理、WASM 波形解码、ModelScope 与 Hugging Face 双镜像、长文本分句生成,以及字幕和音频时间线的同步设计。
在线体验:
https://video-editor.ai-creator.top
开源项目:
https://github.com/MartinDelophy/ai-video-editor
一、为什么要在浏览器里运行中文 TTS
大多数 AI 配音服务采用云端推理模式:
- 用户提交文本;
- 服务端加载语音模型;
- GPU 生成音频;
- 客户端下载结果。
这种方式部署简单,但也会带来一些问题:
- 用户输入的脚本需要上传;
- 参考声音可能涉及个人隐私;
- 服务端 GPU 成本会随着调用次数增长;
- 网络波动会直接影响生成;
- 生成后的音频还需要重新导入视频编辑器。
Timeline Studio 是一款本地优先的浏览器视频编辑器。为了让配音与字幕、素材和时间线直接衔接,我们希望 TTS 也能够在浏览器本地完成。
这意味着模型需要同时满足:
- 中文语音自然;
- 支持中英混合文本;
- 可以转换为 ONNX;
- 能在 WebGPU 或 WASM 中运行;
- 首次下载体积可以控制;
- 长文本生成足够稳定。
经过多轮测试,我们最终选择了 Hojo TTS Light 80M 作为新的中文配音模型。
二、为什么选择 Hojo TTS Light 80M
浏览器 TTS 不能只关注模型参数量,还需要综合考虑语音效果和工程成本。
Hojo TTS Light 80M 的几个特点比较符合我们的需求。
1. 中文自然度较好
相比此前使用的浏览器中文 TTS 模型,Hojo 在以下方面表现更加自然:
- 中文句尾语气;
- 句子之间的呼吸感;
- 中英文切换;
- 语气词的衔接;
- 较长句子的节奏稳定性。
对于短视频旁白、产品介绍和教程解说来说,这些细节对最终效果的影响非常明显。
2. 支持中文和英文
技术类视频经常包含产品名称、英文缩写和代码术语。如果中文和英文分别使用不同模型,容易在声线、音量和语速上产生明显差异。
Hojo 可以处理中文及中英混合内容,更适合类似下面的文本:
Timeline Studio 使用 WebGPU 在浏览器本地运行 AI 配音。
整句话可以在同一个语音上下文中生成,不需要把中英文拆到两个 TTS 引擎。
3. 支持参考声音
Hojo 可以利用参考声音生成对应音色。产品可以预置经过授权的参考声线,也可以为后续的合规声音定制预留空间。
目前我们保留了两位中文参考声线:
- 晴岚:温暖、自然,适合叙事和产品介绍;
- 若溪:清晰、轻快,适合教程和资讯解说。
三、浏览器端推理架构
Hojo TTS 的生成流程由多个模型阶段组成。浏览器版本的整体链路如下:
输入文本
↓
文本和参考声音编码
↓
自回归生成语音编码
↓
语音编码解码为波形
↓
响度处理与限幅
↓
生成 WAV 音频
↓
加入视频时间线
在运行时选择上,我们采用了 WebGPU 与 WASM 混合方案。
WebGPU:负责自回归生成
自回归模型是整个流程中计算量较大的部分。我们通过 ONNX Runtime Web 调用 WebGPU,并显式请求高性能 GPU 适配器。
这样在拥有独立显卡的设备上,浏览器能够优先使用高性能 GPU,而不是意外落到低功耗显卡。
WASM:负责波形解码
最初我们尝试让波形解码器也使用 WebGPU FP16,但在部分设备中出现了:
- 低频噪声;
- 波形失真;
- 局部爆音;
- 输出接近静音;
- 不同浏览器输出不一致。
最终我们选择让自回归阶段运行在 WebGPU,而波形解码阶段运行在 WASM。
自回归模型:WebGPU
波形解码器:WASM
这种混合架构没有追求理论上的最高速度,而是优先保证生成结果稳定。对于配音产品来说,音频质量比几秒钟的性能差异更加重要。
四、FP16 数据不能简单地统一读取
浏览器端处理 FP16 ONNX 输出时,有一个容易被忽略的问题:不同运行时版本返回的数据结构可能不同。
一种情况返回原始半精度二进制:
Uint16Array
另一种情况可能返回已经可以按数值访问的:
Float16Array
如果把 Float16Array 的数值错误地当成 Uint16Array 位模式再次转换,就会破坏输出波形,最终可能表现为:
- 完全静音;
- 声音带有噪声;
- 振幅异常;
- 波形出现无效数值。
因此,运行时需要根据实际数据类型决定处理方式:
function readFloat16Output(data) {
if (data instanceof Float16Array) {
return Float32Array.from(data);
}
if (data instanceof Uint16Array) {
return decodeFloat16Bits(data);
}
return Float32Array.from(data);
}
这类问题很难通过模型加载状态发现,因为推理本身可能已经成功,只是最终声音不正确。
五、将大模型拆分成多个文件
直接在浏览器中下载一个大型 ONNX 文件并不理想。
可能遇到的问题包括:
- 单请求时间过长;
- 网络中断后需要重新下载;
- CDN 对单文件大小有限制;
- 浏览器缓存失败;
- 无法判断下载内容是否完整。
我们将模型拆分成约 16 MiB 的分片:
Hojo-TTS-Light-llm.onnx
├── Hojo-TTS-Light-llm.onnx.part-000.bin
├── Hojo-TTS-Light-llm.onnx.part-001.bin
├── Hojo-TTS-Light-llm.onnx.part-002.bin
├── Hojo-TTS-Light-llm.onnx.part-003.bin
└── ...
同时生成一个清单文件,记录:
{
"file": "Hojo-TTS-Light-llm.onnx.part-000.bin",
"bytes": 16777216,
"sha256": "..."
}
浏览器端的加载流程为:
- 并行下载模型分片;
- 校验每个分片的大小;
- 计算并校验 SHA-256;
- 按照清单顺序重新组合;
- 创建 ONNX Runtime 推理会话。
这种设计可以降低大文件下载失败的影响,也更适合浏览器 Cache Storage。
六、使用 ModelScope 和 Hugging Face 双镜像
为了兼顾不同地区的访问质量,我们将模型同步到两个自有镜像:
- ModelScope:适合中国大陆网络环境;
- Hugging Face:作为海外访问与故障回退来源。
中文界面和国内会话优先请求 ModelScope,如果不可用则自动切换到 Hugging Face。
const providers = isChineseSession
? [modelScopeMirror, huggingFaceMirror]
: [huggingFaceMirror, modelScopeMirror];
两个来源使用同一个缓存身份。即使浏览器从不同平台下载,也会被识别为同一版本模型,避免重复占用存储空间。
生产环境中不直接引用不断变化的 main 分支,而是固定到不可变版本:
模型仓库 + 固定 revision + 文件路径
这样可以保证:
- 线上版本可复现;
- 两个镜像内容一致;
- 上游更新不会意外影响产品;
- 缓存校验值保持稳定。
模型镜像地址:
七、500 字长文本不能一次生成
模型能够接收长文本,不代表产品应该一次生成整篇内容。
如果直接输入数百字,可能出现:
- 后半段语音质量下降;
- 语速逐渐漂移;
- 句尾不完整;
- 内存与显存占用增加;
- 某一句出错后整段都要重新生成。
我们采用的方式是先拆分文本,再按顺序生成。
长文本
↓
按句号、问号、感叹号拆分
↓
按逗号整理呼吸组
↓
逐段独立推理
↓
分别生成音频文件
↓
按顺序加入时间线
例如:
今天我们发布了新的浏览器配音能力。
它可以直接在本地运行,不需要上传脚本。
中文和英文也可以在同一个工作流中完成。
这段文本会生成三个独立的音频资源,而不是先生成一段长音频再进行裁切。
这样做的优势是:
- 单句可以单独重试;
- 每段语气更加稳定;
- 音频可以独立移动;
- 字幕更容易精确对齐;
- 长文生成的内存压力更低。
八、分句不只是字符串切割
中文文本的分句不能简单使用:
text.split("。")
真实内容中可能包含:
- 中文和英文标点;
- 逗号、分号;
- 小数和版本号;
- URL;
- 英文缩写;
- 产品名称;
- 固定表达。
如果切分过于激进,可能产生没有实际含义的片段。
我们的默认规则是:
- 句号、问号和感叹号作为强边界;
- 逗号可以作为默认呼吸边界;
- 过短片段与相邻内容合并;
- 不拆分数字、小数、URL和专有名词;
- 中英混合固定短语尽量保持完整。
目标不是机械地缩短文本,而是构造接近真人呼吸节奏的生成单元。
九、为什么每句话都要生成真实音频资产
还有一种实现方式是先生成完整长音频,再按照时间范围切成多个时间线片段。
这种方式看起来简单,但存在一些问题:
- 所有片段依赖同一个原始文件;
- 单句不能重新生成;
- 删除或替换某句话比较麻烦;
- 字幕和音频的关系更复杂;
- 项目导出和迁移时容易产生隐式依赖。
因此,Timeline Studio 会把每个句子或呼吸组生成为独立的音频文件。
sentence-001.wav
sentence-002.wav
sentence-003.wav
相邻配音片段默认保留 0.4 秒间隔,桌面端和 H5 使用相同规则。
0.4 秒可以提供必要的呼吸空间,同时又不会让连续旁白显得过于松散。
十、采用音频优先的时间线设计
很多视频工具会先确定画面时长,再要求语音适配画面。这样容易导致:
- 配音被强制加速;
- 句尾被裁切;
- 停顿被压缩;
- 字幕与真实语音不同步。
我们采用相反的方式:
- 先生成并接受所有配音片段;
- 测量每个音频的真实时长;
- 按照 0.4 秒间隔排列;
- 建立最终语音骨架;
- 根据语音调整字幕、画面和转场。
也就是说,视频节奏来自最终生成的声音,而不是来自预设模板。
这种“音频优先”的方法尤其适合:
- 产品介绍;
- 教程视频;
- 新闻解说;
- 剧情旁白;
- 中英双语内容。
十一、与 OpenVoice 声音转换配合
Timeline Studio 已经集成了浏览器本地 OpenVoice V2,因此 Hojo 主要负责生成自然的基础语音,OpenVoice 负责转换为用户明确授权的目标音色。
整体流程如下:
文本
↓
Hojo 生成中文或英文基础语音
↓
OpenVoice 转换目标音色
↓
响度控制与限幅
↓
保存到“我的素材”
声音克隆不会被当作普通录音处理。用户必须确认拥有参考声音的使用权限,并先试听克隆测试结果。
生成后的音频也不会自动覆盖时间线内容。只有用户明确选择替换时,系统才会保留原片段的:
- 时间位置;
- 音量;
- 淡入淡出;
- 字幕关联;
- 可恢复的原始音频。
十二、最终实现效果
完成这次升级后,浏览器中文配音具备以下能力:
- Hojo TTS Light 80M FP16 推理;
- 中文和中英混合文本生成;
- 两位授权内置参考声线;
- WebGPU 自回归生成;
- WASM 稳定波形解码;
- ONNX 模型分片下载;
- 分片大小与 SHA-256 校验;
- ModelScope 优先、Hugging Face 回退;
- 跨镜像统一缓存;
- 长文本自动分句;
- 每个句子生成独立音频;
- 桌面端与 H5 统一 0.4 秒间隔;
- 与字幕、时间线和 OpenVoice 的完整衔接。
十三、总结
将中文 TTS 放进浏览器,难点不仅是让 ONNX 模型成功运行。
真正决定产品能否使用的,是整套工程链路:
- 模型是否足够自然;
- FP16 数据能否被正确解释;
- WebGPU 和 WASM 如何分工;
- 大文件能否稳定下载;
- 国内外镜像能否自动切换;
- 长文本能否稳定生成;
- 语音、字幕和时间线能否保持一致。
Hojo TTS Light 80M 在模型规模、中文效果、中英双语能力和浏览器可部署性之间取得了较好的平衡。
对本地优先的 AI 应用来说,模型参数量并不是唯一指标。稳定、可缓存、可恢复、可复现,并且能够真正进入用户工作流,才是浏览器 AI 工程化的核心。