Article

我把声音克隆搭了个网页界面,全程踩坑实录

trial

用 AI 配音,一直有个尴尬的中间地带。

TTS 太死板——念出来的东西没有语气起伏。

真人录又太麻烦——录一段 3 分钟的旁白,得找安静环境、调麦克风、控制语速,状态不好录七八遍。

但有时候,你已经有一段录音了(播客、访谈、随口录的 demo),只是想换成另一个声音来说——语速、语气、节奏都不变,只换音色。

我找到了一个能做的事:Seed-VC,声音转换模型。

给它两段音频——一段说内容,一段给音色——它输出的是「用目标声音说源内容」。

全程本地跑,不需要训练,不需要云端,一个参考音频就够了。

过程踩了不少坑,记下来。


什么是声音转换

先区分两个概念。

TTS(Text-to-Speech): 文字变语音。输入文字,输出声音。

VC(Voice Conversion): 语音变语音。输入一段说话音频和一段参考音色,输出的是「用参考音色说源音频内容」。

Seed-VC 做的就是后者。

它的工作流是:

  1. 语义编码:用 Whisper 提取源音频的「说了什么」——语音内容、语气、节奏
  2. 音色编码:用 CAMPPlus 从参考音频里提取「谁在说」——音色特征
  3. 融合生成:用 DiT 扩散模型把语义和音色融合,输出新的语音

整个过程不需要训练,不需要上传数据到云端,全部在本地完成。


模型文件,全部手动搬

Seed-VC 依赖 4 个模型,加起来约 2GB:

模型大小作用
DiT 主模型420MB核心扩散模型
Whisper-small922MB语音语义编码
CAMPPlus27MB说话人音色编码
BigVGAN v2449MB声码器(mel→音频)

HuggingFace 在我这里连不上。

所以代码里不能有一行自动下载——全部手动下载、放到 ~/my-sys/model/seed-vc/ 目录下,代码只从本地加载。

其中 BigVGAN 的模型文件跑了几次弯路。

💥 坑一:BigVGAN 的文件摆了我一道

第一次写代码时,我在 HuggingFace 镜像页面上看了一眼文件列表示,随口说了几个文件名和大小——用户实际下载时发现完全不对。

BigVGAN 需要两个文件:bigvgan_generator.pt(449MB)和 config.json。而模型库目录下还有一堆别的文件(git 仓库里的 pytorch_model.binmodel.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 必须跑通,没有备选方案。


现在的体验

以前要做一段声音转换:

  1. 打开 Audacity,裁剪音频到需要的段落
  2. 打开终端,拼命令行:--source xxx --target xxx --diffusion-steps 50 --cfg-rate 0.7
  3. 等处理完,打开文件听效果
  4. 不满意?改参数重新跑第 2 步
  5. 循环

现在:

  1. 浏览器打开 localhost:8080
  2. 拖拽上传源音频和目标音频
  3. 拖动滑块调参数,实时看到说明
  4. 点转换,等几十秒
  5. 在线播放、下载

还不是”一步到位”

说点真心话。

声音转换的输出质量,上限取决于源音频的干净程度

背景噪音、混响、BGM——这些 Whisper 提取语义特征时都会干扰。降噪可以缓解,但不能完全消除。

最理想的使用场景是:录一段干净的干声,换成另一个干净的声音。

播客、访谈录音、课程讲解——这种场景下效果最好。

如果你想要的是「从电影片段里提取对话,换成另一个人的声音说」——目前的输出还达不到商用质量。

但作为本地可跑的声音克隆方案,它已经是目前开源里效果最好的之一。


在 pi 里的用法

我把它包装成了一个简单的命令:

启动/停止 Seed-VC 网页界面

在 pi 对话里说这句话,AI 自动拉起 Flask 服务、打开浏览器。用完说「关掉」,服务就停了。

配合之前写过的 dub_narration(配音+字幕视频工具),工作流是这样的:

  1. 写文稿 → pi 生成 TTS 初稿
  2. 不满意?用 Seed-VC 换一个更合适的音色
  3. 导出音频 → 用 dub_narration 合成字幕视频

三个工具串起来,文字到成品视频的链路就通了。


全部代码和模型在本地,不经过云端。所有模型已下载到 ~/my-sys/model/seed-vc/,断网也能跑。

评论区告诉我你最想接进来的下一个工具。