视频二次配音系统
起因
刷短视频的时候经常能看到那种”二次配音”的搞笑视频——拿一段影视剧片段,配上完全不相干的沙雕文案,声音还挺像原角色的。这种视频制作门槛其实不低:要找素材、去字幕、克隆声音、合成语音、加字幕、剪辑……全手工做一条少说半小时。
我就想:这整个流程能不能全自动化?
上传原始视频,系统自动提取声纹;写好文案,一键合成成品视频,甚至自动发到视频号。整套东西全部跑在我的 MacBook Pro M2 上,不花一分钱 GPU 费用。
技术选型:在 M2 上跑 AI 的正确姿势
M2 的 16GB 统一内存意味着 CPU 和 GPU 共享内存,这是跑本地 AI 模型的天然优势。关键是选对框架——不是 PyTorch,而是 Apple 的 MLX。
最终的技术栈:
| 环节 | 方案 | 为什么选它 |
|---|---|---|
| 语音转文字 | mlx-whisper + whisper-large-v3-turbo | MLX 原生优化,M2 上转录速度是实时的 10 倍以上 |
| 声音克隆 | mlx-audio + Qwen3-TTS (8bit) | 目前开源方案中音质最好的,支持 zero-shot 声音克隆 |
| 人声分离 | demucs-mlx | 从有背景音乐的视频中提取纯净人声,大幅提升克隆质量 |
| 字幕去除 | video-subtitle-remover (STTN) | AI 画面修复,把字幕区域”抹掉” |
| 音视频处理 | FFmpeg | 没什么好说的,音视频处理的瑞士军刀 |
| 后端 | FastAPI + MySQL | 异步任务支持好,ORM 省事 |
| 前端 | React + TypeScript + Tailwind | 快速出活 |
| 自动发布 | Playwright | 操控微信视频号后台的 Shadow DOM |
| 视频元数据 | DeepSeek API | 根据文案自动生成标题、描述、话题标签 |
全部本地推理,除了 DeepSeek 的元数据生成需要网络,其他环节零 API 费用。
开发过程中踩的坑
坑 1:声纹被背景音乐污染
第一版做出来,声音克隆效果很差——合成出来的声音像机器人。排查后发现,原视频不仅有人声还有背景音乐,直接拿混合音频作为参考,声纹就被污染了。
解决方案:在创建角色时加了一步 demucs 人声分离。上传视频 → 提取音频 → demucs 分离出纯人声 → 用纯人声作为参考音频。效果立竿见影。

坑 2:字幕没去掉
video-subtitle-remover 的默认模式(全画面检测)效果很差,基本就是原封不动。翻了半天文档发现要用 sttn-det 模式,并且需要精确指定字幕区域坐标。
解决方案:前端做了一个视频播放器 + 可视化拖拽框,用户播放视频找到字幕位置后,拖拽圈定字幕区域,系统按这个区域做 AI 修复。
坑 3:FFmpeg 中文字幕变方块
烧录字幕时,所有中文变成了小方块。
解决方案:FFmpeg 的 ASS 字幕滤镜需要显式指定中文字体。macOS 自带 “Heiti SC”(黑体),加上 FontName=Heiti SC 就好了。另外还有一个隐蔽的坑——macOS 路径里的冒号(:)需要转义成 \:,否则 FFmpeg 的 subtitle filter 会解析失败。

坑 4:视频时长匹配
文案合成出来的音频可能 30 秒,但角色的视频素材有 3 分钟的、有 10 秒的。需要一套智能匹配算法:
- 如果有足够长的单段视频 → 裁剪
- 如果单段不够 → 多段拼接
- 如果所有素材加起来还不够 → 循环
实现起来不难,但边界情况很多,比如避免在同一个视频的同一位置反复裁剪。

坑 5:微信视频号后台是 Shadow DOM
视频号创作者后台用了 wujie-app 微前端框架,表单元素都在 Shadow DOM 里。Playwright 的标准选择器根本找不到。
解决方案:通过 evaluate() 注入 JS,先拿到 Shadow Root,再在里面查询元素。上传文件更麻烦——Shadow DOM 里的 <input type="file"> 无法直接操作,最后用了一个 hack:把 input 克隆到主 DOM 中,设置文件后再把 FileList 同步回原始 input。
坑 6:数据库迁移
没用 Alembic 这种专业迁移工具(因为项目初期,表结构变动太频繁)。每次加新字段,CREATE_ALL 不会给已有表加列,导致 500 错误。
解决方案:在 init_db() 里写了一个自动迁移函数,启动时用 inspect 检查每个表的现有列,对比 ORM 模型定义,自动执行 ALTER TABLE ADD COLUMN。简单粗暴但好用。

最终效果
完整的合成流程大约 40-60 秒(取决于文案长度),包含 9 个步骤:
- Qwen3-TTS 声音克隆合成语音
- 混入背景音乐(音量自动降低)
- 根据音频时长智能匹配视频片段
- 添加固定水印”二次配音 仅供娱乐”
- 烧录字幕到视频画面内
- 缩放到 1080x1920 竖屏 + 黑边填充
- 添加飘动水印
- 合并音频
- DeepSeek 生成短标题、描述、话题标签
一条命令自动发布到微信视频号:
cd publisher && .venv/bin/python main.py auto --collection "搞笑"
项目架构
React 前端 (Vite :3000)
│
│ API Proxy
▼
FastAPI 后端 (:8000)
├── 角色管理 (创建/上传视频/去字幕/BGM)
├── 文案库 (CRUD)
├── 合成中心 (异步任务)
└── 工具箱 (视频裁剪/音频裁剪)
│
├── mlx-whisper (语音转文字)
├── mlx-audio/Qwen3-TTS (声音克隆)
├── demucs-mlx (人声分离)
├── video-subtitle-remover (字幕去除)
├── FFmpeg (音视频处理)
└── DeepSeek API (元数据生成)
│
▼
MySQL (角色/文案/任务元数据)
本地文件系统 (视频/音频/字幕)
一些感悟
Apple Silicon 跑 AI 真的能打。MLX 框架让 M2 16GB 能同时跑 Whisper + TTS + Demucs,不用买 GPU 云服务器,电费都省了。
AI 编码助手改变了开发节奏。这个项目从 0 到完整可用,核心开发时间大约一周。很多重复性的代码(FFmpeg 命令封装、CRUD 接口、前端表单)都是 AI 辅助完成的,我主要在做架构决策和调试。
声音克隆的质量取决于参考音频的质量。最重要的不是模型多强,而是参考音频有多干净。加了 demucs 人声分离后,同一个模型的效果提升了一个档次。
短视频领域的工程化空间很大。从素材管理、内容生成、到自动发布,每个环节都有优化空间。这套系统目前是单用户本地运行的,但稍作改造就能变成一个 SaaS 产品。