(不)动手实现一个播客翻译 CLI

Make it work, make it right, make it fast.
— Kent Beck

之前有播客翻译的需求,手动跑通了一个流水线。后来想集成为方便复用的工具,一开始让 claude 直接根据文档生成了一个后端流水线 + Gradio 前端,看起来能用,但是在后续调整功能时陷入了依赖地狱,调试时经常需要等待镜像重建。遂准备尝试改为 uv + cli 的项目模式,从头让 codex plan mode 开始设计,claude review 并手动挑选修改。tts 的部分首先采用阿里百炼的云服务来降低配置依赖。

0. 开发工具

  • Antigracity + Codex + Claude Code ft. glm-5:正值各家都在大刀砍额度,利用 OpenAI 上市前的羊毛 GPT-5.4 多切号当主力勉强够用,而 Google AI Pro 的拼车可以薅 Claude Opus 4.5 做做 plan review 和一些其他操作,Claude Code 则用公司的 token 配阿里云的 glm-5,主打都是好猫。

  • mutagen:一个轻量的代码同步工具。一开始依赖的 PyCharm 的 rsync 功能,后来觉得开太多 ide 占内存,就找了这个轻量好用的工具做代码同步。通过 ssh 连接同步平时开发无感,远程调试前使用 mutagen sync list 确认下状态即可,同时支持排除一些编译配置路径等,具体命令让 AI 做语义转换即可。

1. It just work

Codex 和 Claude 左右互搏了两轮后,plan 看起来基本顺眼了,就沿用 WhisperX、首版跳过人声分离步骤等决策达成共识,后面就是 gpt-5.4 一把梭。

直接跑不出意外的遇到了一些接口参数和以来冲突的问题,不过都在几轮确认后修复。gpt-5.4 已经具备了成熟的文档搜索能力,基本都能快速定位到问题原因。

一开始直接在本地 32g 内存的笔记本跑,由于还跑着各种 ide 和 chrome 等内存大户,只测试了 medium 和 large-v2 的 int8 量化规格,虽然都能完成任务,但是试听下来多少有点问题,比如在之前的测试播客中的首句:

Reinforcement Learning is terriable.

低精度的处理下强化学习会被识别成雨林学习(Rainforest Learning)。不过之后在 3090 的机器上测试用 cuda 跑 float16 精度就可以正常识别。

2. Could be better

音色克隆

之前手动跑的时候依赖的 GPT-SoVITS 这个开源项目,效果还不错但是毕竟还得研究部署用起来没那么方便。所以还是选择先走阿里云的服务花小钱办大事。

阿里云官方的 qwen3-tts-vc-2026-01-22 价格是万字 / 0.8 元,跑个长播客一杯咖啡钱应该能兜住。

Qwen 年初开源了 Qwen3-TTS 全家桶,先使用 qwen3-tts-vc 作为默认模型试试。

音色克隆的特性需要克隆和 tts 使用同一模型,显要好处就是实际翻译后的语音也会变速,虽然难免有点歪果仁的感觉,但是可以将原计划中的语音变速功能往后推了。测试单抽效果如下:

似乎存在多音字念错的问题,偶尔还会莫名引入一些方言感,不过问题不大(这些问题在取样范围扩大后有所改善)。

而穿插翻译则是个人偏好的模式,直接作为默认模式内置了。主要逻辑是如果说话人变化,或者连续说话达到一定长度(默认 15s)后就跟上翻译。测试下来基本符合这个模式,可以部分避免人声转录或者翻译问题引入的歧义,同时保留 bgm 原声的播客感,还能锻炼一下听力。

任务隔离与缓存

简单测试的话单输入文件重跑也没啥问题,但是真正投入使用的话还得隔离下任务,并添加适当的缓存来减少任务失败损失 ,避免时间和金钱的非必要投入。

由于相同音频源也存在多轮配置调整的可能,所以方案的话是通过 artifacts/tasks/<task_id>/ 来隔离任务的中间产物,而 artifacts/cache/<stage>/<cache_key> 来建立任务之间的共享缓存。原理基本是对各个步骤的音频和对应配置做 hash 指纹,相同源则复用。带宽有限,具体缓存逻辑也没逐个确认,过了一遍计划反正 LGTM(后续 ai review 确实藏了点 bug)。

缓存做完后很多失败(暂时也没很多)重跑的心理负担就降低很多。

CLI 语义重构

设计之初没有太顾及 CLI 的语义,用起来时发现很丑陋(需要 uv run podtran run 来跑),觉得差不多是时候重构下了。

几轮对话后确认了一个相对精简的版本:

1
2
3
4
5
6
7
8
9
- podtran AUDIO
- podtran init
- podtran tasks
- podtran status [TASK]
- podtran transcribe TASK
- podtran translate TASK
- podtran synthesize TASK
- podtran compose TASK
- podtran cache clean ...

虽然有些念不出来的生词,不过基本都是为了调试流水线中间的验证步骤,保留这些步骤是为了开放一些可快速复现的中间步骤接口(好像也没必要,不过万一以后可以丢给龙虾用呢)。

测试下来很喜欢这个 status 命令,配合 watch 就可以轻松异步监控任务进度:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@gpu01 podtran]# uv run podtran status
task_id=20260403-065432-f1773c audio=YouTube_Skill-Issue-Andrej-Karpathy-on-Code-Agen_Media_1080p.mp4 status=running stage=synthesize
podtran status
┏━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━┓
┃ Stage ┃ Status ┃ Outputs ┃ Error ┃
┡━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━┩
│ transcribe │ completed │ yes │ - │
│ translate │ completed │ yes │ - │
│ synthesize │ running │ yes │ - │
│ compose │ pending │ no │ - │
└────────────┴───────────┴─────────┴───────┘
segments=435 translated=435 completed_tts=132 failed=0
voices=2 cloned=2 failed_voice_profiles=0

一些小优化

音频预览

由于烧的公司的 token 不心疼,第二次测试直接上一小时的播客也没问题,不过为了使用方便(验证 API 服务、音频效果等),最好还是加个截取 5min 快速验证的模式来减少后续沉没成本。

--preview 模式由此诞生,默认取前五分钟去跑完整流程,同时保留了一些片段缓存当蚊子肉了。不过 preview 模式的音色效果实际会差些,因为只能从前五分钟采样。

不过很快暴露了一个新问题:由于前五分钟往往带有 bgm,所以克隆的音色部分说话也会自带 bgm。虽然添加采样开始时间或者直接从中段截取可以相对解决,不过增加了一点复杂性。不如先保留这个 feature,后面如果用人声分离来解决的话应该更完美。

可视化进度条

用户友好的小优化,展示一下主流程和子流程进度:

1
2
3
4
5
6
7
8
9
PS D:\Projects\my-project\podtran> uv run podtran .\YouTube_An-AI-state-of-the-union-We-ve-passed-th_Media_wc8FBhQtdsA_009_128k.mp3 --preview
Created task: 20260410-055800-252e3c
transcribe skipped (cache hit)
translate skipped (cache hit)
synthesize done: 30/30 audio ready, 0 failed
compose done: YouTube_An-AI-state-of-the-union-We-ve-passed-th_Media_wc8FBhQtdsA_009_128k.preview.interleave.mp3
Pipeline Compose: Complete ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4/4 0:00:17
Task complete: 20260410-055800-252e3c
Output file: C:\Users\Rosin\.podtran\artifacts\tasks\20260410-055800-252e3c\final\YouTube_An-AI-state-of-the-union-We-ve-passed-th_Media_wc8FBhQtdsA_009_128k.preview.interleave.mp3

交互式配置

如今安装一些流行的开源项目(OpenClaw、Hermes)时基本都支持 CLI 交互式配置了,让 AI 实现一下也没啥成本,由于首版只支持阿里云,干脆重构了一下配置结构,只保留了一些必要配置:

1
2
3
4
5
PS D:\Projects\my-project\podtran> uv run podtran init --force
podtran init
Provider-managed auth. Translation and TTS default to DashScope; leave advanced endpoint overrides for later edits.
Before entering your Hugging Face token, accept the model terms at https://huggingface.co/pyannote/speaker-diarization-community-1 .
Hugging Face token:

这里的 HF_TOKEN 主要用来确认说话人识别模型的协议,加个链接方便跳转。

3. Done

毕竟花公司的钱不心疼,其实翻译想省钱的话可以白嫖谷歌 API,而 tts 的话后面也可以支持多渠道和本地部署,不过这些都等后面有需求和时间再改吧。

如今 AI Coding 的成本已经很低了,而想在开发过程中避免失控的同时增加一点参与感还是挺有挑战的一件事。利用 AI 创造算是对抗 AI 焦虑的一种魔法对轰的有效方式,这次做了个能让通勤时间更有价值,同时开拓一些视野,并尽可能降低使用成本的工具,过程和结果都还算满意。后面有空再看看能不能集成 Skill 丢到 Hermes 上去。

感谢 OpenAI,Google,Claude 对本工具开发的大力支持(排名分先后)。