Article
我把声音克隆搭了个网页界面,全程踩坑实录
用 AI 配音,一直有个尴尬的中间地带。
TTS 太死板——念出来的东西没有语气起伏。
真人录又太麻烦——录一段 3 分钟的旁白,得找安静环境、调麦克风、控制语速,状态不好录七八遍。
但有时候,你已经有一段录音了(播客、访谈、随口录的 demo),只是想换成另一个声音来说——语速、语气、节奏都不变,只换音色。
我找到了一个能做的事:Seed-VC,声音转换模型。
给它两段音频——一段说内容,一段给音色——它输出的是「用目标声音说源内容」。
全程本地跑,不需要训练,不需要云端,一个参考音频就够了。
过程踩了不少坑,记下来。
什么是声音转换
先区分两个概念。
TTS(Text-to-Speech): 文字变语音。输入文字,输出声音。
VC(Voice Conversion): 语音变语音。输入一段说话音频和一段参考音色,输出的是「用参考音色说源音频内容」。
Seed-VC 做的就是后者。
它的工作流是:
- 语义编码:用 Whisper 提取源音频的「说了什么」——语音内容、语气、节奏
- 音色编码:用 CAMPPlus 从参考音频里提取「谁在说」——音色特征
- 融合生成:用 DiT 扩散模型把语义和音色融合,输出新的语音
整个过程不需要训练,不需要上传数据到云端,全部在本地完成。
模型文件,全部手动搬
Seed-VC 依赖 4 个模型,加起来约 2GB:
| 模型 | 大小 | 作用 |
|---|---|---|
| DiT 主模型 | 420MB | 核心扩散模型 |
| Whisper-small | 922MB | 语音语义编码 |
| CAMPPlus | 27MB | 说话人音色编码 |
| BigVGAN v2 | 449MB | 声码器(mel→音频) |
HuggingFace 在我这里连不上。
所以代码里不能有一行自动下载——全部手动下载、放到 ~/my-sys/model/seed-vc/ 目录下,代码只从本地加载。
其中 BigVGAN 的模型文件跑了几次弯路。
💥 坑一:BigVGAN 的文件摆了我一道
第一次写代码时,我在 HuggingFace 镜像页面上看了一眼文件列表示,随口说了几个文件名和大小——用户实际下载时发现完全不对。
BigVGAN 需要两个文件:bigvgan_generator.pt(449MB)和 config.json。而模型库目录下还有一堆别的文件(git 仓库里的 pytorch_model.bin、model.safetensors 等),很容易弄混。
最后正确的做法是把整个仓库 git clone 到本地,或者手动下载 bigvgan_generator.pt + config.json 放进一个目录,然后用 HuggingFace 的 from_pretrained(local_path) 加载。只放一个 .pt 文件不够,from_pretrained 会找不到配置。
用 Flask 搭了个 Web 界面
纯命令行调 Seed-VC 没问题,但参数多(扩散步数、时长调整、引导权重),每次改参数都得拼命令行,体验不好。
我写了个 Flask Web 页面,主要做几件事:
▎上传音频
两个拖拽上传框——源音频(要转换的内容)和目标音频(参考音色)。
上传后立刻显示波形,可以看到录音的节奏和音量分布。
▎时间区间裁剪
源音频往往比需要的部分长。我在波形下方加了分/秒输入框,指定起止时间,只处理中间那一段。
省去先用工具切割音频的步骤。
▎参数实时调节
三个滑块:
- 扩散步数(10-100):步数越高音质越好,但越慢。默认 50,预览用 20 就够了
- 时长调整(0.5-2.0):调整语速。1.0 保持原速
- 引导权重(0.0-1.0):调高更像目标音色,调低更保真原声。0.7 是平衡点
每个滑块移动时下方的说明会跟着变化,不用记参数含义。
▎处理计时
点转换后显示实时计时,处理完显示总耗时。50 步大约 60 秒处理 1 分钟音频。
▎降噪开关(可选)
源音频有背景音乐或噪音时,可以勾选「降噪」——用 demucs 自动分离人声。
默认不勾选,避免每次多等半分钟。
长音频的坑
第一个项目跑通后,我拿了一段 2 分钟的播客试——结果输出完全错乱,像机器人在胡言乱语。
查了半天发现原因:Whisper 编码器有 30 秒窗口限制。
超长音频喂进去,后面的内容 Whisper 根本「看不懂」。语义特征错了,后续扩散出来的就是乱码。
修复方法:把长音频切成 30 秒一段,每段重叠 5 秒,分别提取语义特征再拼接。
这个逻辑 local_inference.py(Seed-VC 自带的推理脚本)里已经写好了,但我当初图省事直接抄了个简化版——少了一段重叠切片。加上之后,2 分钟音频转换正常。
声码器的选择
Seed-VC 默认搭配 BigVGAN v2 作为声码器(把 mel 频谱转回音频)。
如果 BigVGAN 加载失败,代码会回退到 HiFi-GAN。两个都能出声,但效果天差地别:
- BigVGAN:干净、清晰,语音自然
- HiFi-GAN 回退:有金属感,像旧手机通话
Seed-VC 主模型是用 BigVGAN 的输出训练的。用 HiFi-GAN 解码相当于「用一个模型不熟悉的格式还原」,效果打折是必然的。
所以 BigVGAN 必须跑通,没有备选方案。
现在的体验
以前要做一段声音转换:
- 打开 Audacity,裁剪音频到需要的段落
- 打开终端,拼命令行:
--source xxx --target xxx --diffusion-steps 50 --cfg-rate 0.7 - 等处理完,打开文件听效果
- 不满意?改参数重新跑第 2 步
- 循环
现在:
- 浏览器打开
localhost:8080 - 拖拽上传源音频和目标音频
- 拖动滑块调参数,实时看到说明
- 点转换,等几十秒
- 在线播放、下载
还不是”一步到位”
说点真心话。
声音转换的输出质量,上限取决于源音频的干净程度。
背景噪音、混响、BGM——这些 Whisper 提取语义特征时都会干扰。降噪可以缓解,但不能完全消除。
最理想的使用场景是:录一段干净的干声,换成另一个干净的声音。
播客、访谈录音、课程讲解——这种场景下效果最好。
如果你想要的是「从电影片段里提取对话,换成另一个人的声音说」——目前的输出还达不到商用质量。
但作为本地可跑的声音克隆方案,它已经是目前开源里效果最好的之一。
在 pi 里的用法
我把它包装成了一个简单的命令:
启动/停止 Seed-VC 网页界面
在 pi 对话里说这句话,AI 自动拉起 Flask 服务、打开浏览器。用完说「关掉」,服务就停了。
配合之前写过的 dub_narration(配音+字幕视频工具),工作流是这样的:
- 写文稿 → pi 生成 TTS 初稿
- 不满意?用 Seed-VC 换一个更合适的音色
- 导出音频 → 用
dub_narration合成字幕视频
三个工具串起来,文字到成品视频的链路就通了。
全部代码和模型在本地,不经过云端。所有模型已下载到
~/my-sys/model/seed-vc/,断网也能跑。评论区告诉我你最想接进来的下一个工具。