引言
这两个星期,在 大白菜 大佬和 Kid 大佬的提点下,完成了 Audio8 和 MOSS-TTS-Nano 两个轻量级 TTS 引擎的集成工作,也让一直定位于轻量级语音合成的 OddTTS 的引擎矩阵越来越丰富。与此同时刚才这两个引擎都支持音色克隆(zero-shot voice cloning),昨天晚上想起来这摊子事后,就决定把 OddTTS 的音色克隆功能给搞一下,并将这个能力给暴露出来。
今天搞了一天,还算是比较顺利的把音色克隆功能完整实现了,并作为 v2.0 的核心特性发布。
现在,你只需要上传一段 3-10 秒的参考音频,就能在 OddTTS 中注册一个自定义音色,像内置音色一样随时调用——无论是通过 Web 界面还是 OpenAI 兼容 API。
在这个周末,俺终于可以说 OddTTS 完成了从 v1.x 到 v2.0 的跨越。
音色克隆功能首批支持 MOSS-TTS-Nano、Audio8 0.1B ONNX INT8、Audio8 0.6B ONNX INT4 三个引擎。
后面如果有更多轻量级的 TTS 引擎和模型,我也会持续的将一些适合的引擎一个个的加进 OddTTSk 中,以支持更多引擎。
快速开始使用 OddTTS
OddTTS 是一个功能强大的多引擎语音合成服务,提供统一的 API 接口和友好的 Web 界面,一套接口搞定多种主流 TTS 引擎,包括 EdgeTTS、Kokoro-82M-v1.1-zh、Audio8、MOSS-TTS-Nano、ChatTTS、Bert-VITS2、GptSovits v2 等,同时也支持 OpenAI TTS API 的调用。
- 仓库:
https://github.com/oddmeta/oddtts - 版本:
v2.0.13 - 安装:
pip install oddtts - 运行:
oddtts - 演示:
http://localhost:9001
Python 测试
import openai
client = openai.OpenAI(base_url="http://localhost:9001/v1", api_key="dummy")
response = client.audio.speech.create(input="你好,欢迎使用OddTTS小奥语音合成服务。")
curl 测试
curl http://127.0.0.1:9001/v1/audio/speech -H "Content-Type: application/json" -d "{\"input\": \"你好,欢迎使用OddTTS小奥语音合成服务。\"}" --output speech.mp3
一、音色克隆是什么?
1.1 Zero-shot Voice Cloning
音色克隆(Voice Cloning)是指通过一段参考音频,让 TTS 模型学会模仿该音频中说话人的音色、语调、韵律等特征,然后用这个”克隆”出来的音色去合成新的文本,简单理解就是,可以用你自己的音频来clone一个音色,然后使用这个音色去合成新的文本。
本次 OddTTS 集成的三个引擎(MOSS-TTS-Nano、Audio8 0.1B、Audio8 0.6B)的 ONNX Runtime 都原生支持 prompt_audio_path 参数——你只需要传入一段参考音频的路径,模型就能自动克隆该音色进行合成。
1.2 为什么需要音色克隆?
在实际应用中,内置音色往往无法满足所有需求。比如:
- 个人品牌:用自己的声音做配音
- 角色扮演:为游戏角色、动画角色定制声音
- 多语言场景:同一个人说不同语言,保持音色一致性
- 隐私保护:用克隆音色替代真人录音
音色克隆让 TTS 从”用别人的音色”变成了”用我自己的音色”。

二、整体架构设计
2.1 设计思路
核心思路是音色库管理:一次上传 → 注册为自定义音色 → 像内置音色一样选择使用。
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────────┐
│ 前端 UI │────▶│ API 层 │────▶│ VoiceCloneManager │
│ (上传/管理) │ │ (上传/列表/删除) │ │ (文件存储+元数据) │
└─────────────────┘ └──────────────────┘ └─────────────────────┘
│
┌────────────────────────┘
▼
┌─────────────────┐
│ tts_moss_nano │
│ get_voices() │◀── 合并内置+自定义音色
│ _synthesize() │◀── 根据voice名找prompt_audio_path
└─────────────────┘
2.2 文件结构变化
本次更新新增和修改了以下文件:
oddtts/
├── voice_clone/ # 新增:音色克隆管理模块
│ ├── __init__.py
│ └── manager.py # VoiceCloneManager(287行)
├── models/
│ ├── tts_moss_nano.py # 修改:支持prompt_audio_path克隆
│ ├── tts_audio8_0_1b_onnx_int8.py # 修改:支持音色克隆
│ └── tts_audio8_0_6b_onnx_int4.py # 修改:支持音色克隆
├── oddtts_params.py # 修改:TTSParams新增prompt_audio_path
├── oddtts_config.py # 修改:新增voices_base_dir配置
├── router/
│ └── api.py # 修改:新增4个克隆API接口
├── templates/
│ └── index.html # 修改:新增音色克隆标签页
└── tests/
├── test_voice_clone.py # 新增:单元测试
├── test_voice_clone_api.py # 新增:API集成测试
└── test_voice_clone_check.py # 新增:功能验证测试
2.3 音色存储目录结构
克隆音色按引擎隔离存储,运行时自动创建:
voices/
moss_nano/
xiaoming/
reference.wav # 原始参考音频(统一转为WAV格式)
meta.json # {"name":"xiaoming","display_name":"小明",...}
audio8_0_1b/
my_voice/
reference.wav
meta.json
三、技术实现细节
3.1 VoiceCloneManager 核心管理器
VoiceCloneManager 是音色克隆的核心模块,职责包括:
- 文件存储:保存上传的参考音频到
voices/<engine>/<voice_id>/ - 元数据维护:每个克隆音色对应一个
meta.json文件 - 引擎隔离:不同引擎的克隆音色空间互相隔离,避免命名冲突
- 音频转码:自动将上传的 mp3/flac 等格式转为 WAV(48kHz)
# oddtts/voice_clone/manager.py 核心逻辑
_TARGET_SAMPLE_RATE = 48000
def _sanitize_voice_id(name: str) -> str:
"""将用户输入的名称转换为安全的 voice_id"""
sid = re.sub(r"[^a-zA-Z0-9_\-]", "_", name.strip())
sid = re.sub(r"_+", "_", sid)
sid = sid.strip("_")
if not sid:
sid = "voice_" + uuid.uuid4().hex[:8]
return sid[:64]
def _ensure_wav(audio_path, output_path) -> Path:
"""确保音频为WAV格式,如需要则转码"""
# 优先用soundfile,fallback到pydub
...
关键设计决策:
| 决策 | 理由 |
|---|---|
| 按引擎隔离目录 | 不同引擎的音色格式要求不同,隔离避免冲突 |
| 统一转为WAV | ONNX Runtime 只接受 WAV 输入 |
| voice_id 白名单校验 | 防止路径穿越等安全问题 |
| meta.json 存储元数据 | 方便前端展示和管理 |
3.2 TTSParams 扩展
为支持音色克隆,TTSParams 新增了可选字段:
class TTSParams:
def __init__(self, ..., prompt_audio_path: str | None = None):
self.prompt_audio_path = prompt_audio_path
这个字段支持两种使用模式:
- 音色库模式(推荐):通过
voice参数传入克隆音色名称,后端自动查找对应的reference.wav - 即时上传模式:直接通过
prompt_audio_path传入参考音频路径,无需注册
3.3 引擎改造:MOSS-TTS-Nano
MOSS-TTS-Nano 的 ONNX Runtime 原生支持 prompt_audio_path 参数,改造相对直接:
# get_voices() 合并内置 + 自定义音色
async def get_voices(self) -> list[dict[str, str]]:
builtin = list(MossNano_voices.values())
cloned = get_voice_clone_manager().list_voices("moss_nano")
return builtin + cloned
# _resolve_voice_and_prompt() 核心解析逻辑
def _resolve_voice_and_prompt(self, tts_params):
voice = tts_params.voice
prompt_path = None
if voice not in MossNano_voices:
# 克隆音色:从voice_clone库查找reference.wav
prompt_path = get_voice_clone_manager().get_audio_path("moss_nano", voice)
return (voice, prompt_path)
# synthesize() 调用时传入prompt_audio_path
result = self.runtime.synthesize(
text=text,
voice=voice,
prompt_audio_path=prompt_path, # 克隆音色时传入reference.wav路径
...
)
3.4 引擎改造:Audio8
Audio8 的两个模型(0.1B 和 0.6B)也支持参考音频克隆,但实现方式略有不同:
- 0.1B 模型:自动将
reference_codes.npy复制到voices/default_voice/codes.npy作为默认音色 - 0.6B 模型:仅创建
meta.json文件,不包含参考音色代码
改造后,Audio8 引擎同样支持通过 voice 参数传入克隆音色名称,后端自动查找对应的参考音频。
3.5 API 层新增接口
本次更新新增了 4 个音色克隆相关的 API 接口:
| 接口 | 方法 | 说明 |
|---|---|---|
/api/voice/clone | POST | 上传参考音频并注册音色(multipart/form-data) |
/api/voice/clone/list | GET | 列出自定义音色 |
/api/voice/clone/<engine>/<voice_id> | DELETE | 删除克隆音色 |
/api/voice/clone/audio/<engine>/<voice_id> | GET | 试听参考音频 |
上传接口示例:
curl -X POST http://localhost:9001/api/voice/clone \
-F "audio_file=@reference.wav" \
-F "name=xiaoming" \
-F "display_name=小明" \
-F "engine=moss_nano"
使用克隆音色合成:
# 通过 OpenAI 兼容 API 使用克隆音色
curl -X POST http://localhost:9001/v1/audio/speech \
-H "Content-Type: application/json" \
-d '{"input": "你好,这是克隆音色测试", "voice": "xiaoming"}' \
--output cloned_speech.mp3
3.6 前端”音色克隆”标签页
Web 界面新增了”音色克隆”标签页,包含三个区域:
- 上传区:文件选择 + 音色标识 + 展示名称 + 语种 + 保存按钮
- 已克隆列表:卡片式展示,支持试听原音频 / 删除
- 合成区融合:克隆音色带 🎤 标记,与内置音色统一在下拉框中显示
交互流程:
用户打开"音色克隆"面板
│
├── 上传一段参考音频(wav/mp3/flac,建议3-10秒)
├── 输入音色名称(如"小明")
├── 点击"保存音色"
│ └── POST /api/voice/clone ──▶ 保存到 voices/moss_nano/xiaoming/
│
└── 切换到"语音合成"面板
├── 下拉框现在多了 "🎤 小明 (克隆)"
├── 选择"🎤 小明"
├── 输入文本
└── 点击生成
└── voice="xiaoming" ──▶ 后端找到 reference.wav
──▶ prompt_audio_path 传给 ONNX Runtime
──▶ 返回克隆后的合成音频
四、与 OpenAI 兼容 API 的关系
音色克隆功能与 OpenAI 兼容 API 完美融合。/v1/audio/speech 的 voice 字段可以直接传克隆音色名称,无需任何额外改动:
POST /v1/audio/speech
{
"input": "你好,这是克隆音色测试",
"voice": "xiaoming",
"response_format": "wav"
}
这是音色库方案相比”每次上传参考音频”的最大优势——注册一次,永久使用。
五、今日提交记录
本次 v2.0 更新涉及 18 个文件,新增约 1415 行代码:
4702dda 2026-09-05 opt: 优化Audio8两个模型的语音克隆,首次编码注册后缓存,后续直接使用。
704b521 2026-09-05 fix: 修复 audio8 声音克隆失败问题。
165f802 2026-09-05 chore: 在oddtts_config中新增克隆音色根目录
cc18f6e 2026-09-05 chore: 切换模型时自动检测目标模型是否已存在
c66fe83 2026-09-05 opt: 模型路径统一改造总结。
1b9ef99 2026-09-05 feat: 支持 audio8 两个模型的基础音色克隆功能。
20c0782 2026-09-05 fix: 修复上传pypi被拒的问题。
faf60d7 2026-09-04 fix: 修复编译 whl 后缺失 vendor 目录问题。
3ba382c 2026-09-04 feat: 重大更新,加入音色克隆的支持。
六、支持克隆的引擎
| 引擎 | engine 参数值 | 说明 | 纯CPU |
|---|---|---|---|
| MOSS-TTS-Nano 0.1B | moss_nano | OpenMOSS 轻量级多语言 TTS,近20种语言 | ✅ |
| Audio8 0.1B ONNX INT8 | audio8_0_1b | Audio8 0.1B,11种语言,44.1kHz | ✅ |
| Audio8 0.6B ONNX INT4 | audio8_0_6b | Audio8 0.6B,11种语言,44.1kHz | ✅ |
七、实际应用指南
7.1 安装与配置
# 安装OddTTS
pip install oddtts
# 启动服务(首次启动会自动下载模型)
oddtts
7.2 切换引擎
在 Web 界面或配置文件中切换到支持克隆的引擎:
# oddtts_config.py
"tts_type": ODDTTS_TYPE.ODDTTS_MOSS_NANO, # 或 AUDIO8_0_1B_ONNX_INT8 等
7.3 通过 Web 界面克隆音色
- 打开
http://localhost:9001/ - 切换到”音色克隆”标签页
- 上传一段 3-10 秒的参考音频
- 输入音色标识(如
xiaoming)和展示名称(如小明) - 点击”保存音色”
- 切换到”语音合成”标签页,下拉框中选择
🎤 小明 - 输入文本,点击生成
7.4 通过 API 克隆音色
import requests
# 1. 上传参考音频并注册音色
with open("reference.wav", "rb") as f:
response = requests.post(
"http://localhost:9001/api/voice/clone",
files={"audio_file": f},
data={
"name": "xiaoming",
"display_name": "小明",
"engine": "moss_nano"
}
)
print(response.json())
# 2. 使用克隆音色合成语音
response = requests.post("http://localhost:9001/v1/audio/speech", json={
"input": "你好,这是克隆音色测试",
"voice": "xiaoming",
"response_format": "wav"
})
with open("cloned_speech.wav", "wb") as f:
f.write(response.content)
八、总结与展望
8.1 本次更新的意义
- 功能突破:OddTTS 首次支持音色克隆,将 TTS 从”用别人的音色”升级为”用我自己的音色”
- 架构扩展:
VoiceCloneManager的设计为后续更多引擎的克隆支持预留了扩展空间 - API 兼容:克隆音色与内置音色统一管理,OpenAI 兼容 API 无需任何改动
8.2 性能权衡
- MOSS-TTS-Nano:RTF 约 0.5,适合实时场景,克隆效果好
- Audio8 0.1B:合成较慢(RTF ~3.26),但采样率更高(44.1kHz)
- Audio8 0.6B:最慢(RTF ~4.93),但模型参数量最大,理论音质最好
8.3 后续优化方向
- 更多引擎支持:将音色克隆扩展到 Kokoro 等其他引擎
- 批量管理:支持批量上传、批量删除克隆音色
- 音色评估:自动评估克隆音色与参考音频的相似度
- 流式克隆:实现真正的流式克隆合成,减少首字延迟
8.4 社区贡献
欢迎开发者参与 OddTTS 的开发和优化:
- GitHub: https://github.com/oddmeta/oddtts
- 问题反馈: 提交 Issue 或 Pull Request
- 功能建议: 在 GitHub Discussions 中讨论
结语
音色克隆功能的加入标志着 OddTTS 从一个”多引擎 TTS 聚合器”进化为一个”支持个性化音色的 TTS 平台”。无论是个人开发者还是企业用户,都可以用最少的成本获得专属的语音合成能力。
我们期待更多开发者加入,共同推动语音合成技术的发展。
相关资源: