EmotiVoice文本转语音:Docker与Python API实战
在办公室的午后,咖啡刚泡好,耳机里却不再是单调的白噪音——而是我自己的声音,用“温柔”语气读着一段童话:“从前有座山……”不同的是,这声音不是我录的,是AI合成的,带着情绪,像极了哄孩子入睡时的模样。
这一切,靠的是EmotiVoice——一个开源、支持多情感、还能零样本克隆音色的中文TTS引擎。昨晚我下定决心:不满足于网页试听,我要把它部署到本地,用Python自动化调用,真正集成进项目里。
现在,我的老笔记本(i5-8250U,集显,16G内存)已经能生成“愤怒质问”和“撒娇卖萌”的语音了。虽然中间卡了两次:一次拉镜像慢得像蜗牛,一次API返回空音频,查了半小时才发现emotion拼错了大小写——但最终,它跑通了。
下面,我带你从零开始,亲手搭起这个有“情绪”的语音系统。
本地部署:为什么选EmotiVoice?
市面上的TTS工具不少,但大多要么闭源收费(比如Azure、讯飞),要么只能平铺直叙地念字。而EmotiVoice不一样:
- 它开源,代码透明,可改可调;
- 支持多种情绪控制:开心、生气、悲伤、惊讶、温柔、撒娇……全都能通过参数切换;
- 只需3秒参考音频,就能克隆新音色(zero-shot voice cloning);
- 完全本地运行,数据不出内网,隐私安全;
- 提供HTTP API,方便对接Python脚本、前端页面或其他服务;
- 背后是先进的VITS架构 + GST(Global Style Token)和VQ-VAE情感编码模块,生成质量高。
你能拿它做什么?
- 做有声书时,让旁白“悲痛欲绝”或“喜极而泣”;
- 游戏NPC对话系统,不同角色有不同语气;
- 虚拟偶像直播配音;
- 个性化语音助手,比如用你爱人的声音提醒你吃药。
我们今天就走两条路:
1. 用 Docker 快速部署 EmotiVoice 服务
2. 用 Python 调用其 API 生成指定情感的语音
环境准备:别让依赖绊住脚
硬件要求
最低配置:
- CPU:x86_64,双核以上
- 内存:8GB(建议 16GB)
- 存储:至少 10GB 空间(模型较大)
- 显卡:非必需,但如果有 NVIDIA GPU(支持 CUDA)会快很多
我在一台无独显的老本子上测试,推理一次大约 8~15 秒(视文本长度),日常调试完全够用。如果上了GPU,速度能提升3~5倍。
软件依赖
确保已安装:
- Docker Desktop 或dockerd
-docker-compose(推荐)
- Python 3.8+
-requests库(用于调用 API)
pip install requests如果你在 Linux 上跑,记得把用户加进docker组,避免每次敲sudo。
部署服务:三步启动 EmotiVoice
EmotiVoice 官方提供了 Docker 镜像,部署极其简单。
镜像地址:
emotivoice/emotivoice:latest
GitHub 仓库:https://github.com/Plachtaa/VITS-fast-fine-tuning(原项目,EmotiVoice 是其分支/衍生)
第一步:拉取镜像
打开终端执行:
docker pull emotivoice/emotivoice:latest第一次拉取较慢,因为包含多个预训练模型(总大小约 6~7GB)。网络差的话可以试试国内镜像加速器,比如阿里云容器镜像服务。
第二步:启动容器
创建一个docker-compose.yml文件:
version: '3' services: emotivoice: image: emotivoice/emotivoice:latest ports: - "9880:9880" volumes: - ./output:/app/output restart: unless-stopped command: ["python", "app.py"]说明:
- 映射端口9880,这是 EmotiVoice 默认 API 端口;
- 把本地./output目录挂载进去,方便取出生成的.wav文件;
- 启动命令运行app.py,即内置的 FastAPI 服务。
保存后运行:
docker-compose up -d等待几秒,服务就起来了。
第三步:验证是否正常
浏览器访问:
http://localhost:9880/docs你会看到 Swagger UI 页面,标题是 “EmotiVoice API”,里面有/tts、/clone等接口。
说明:服务已就绪!
调用API:让文字“说出感情”
我们现在要用 Python 发送 POST 请求到/tts接口,传入文本、情感标签、音色等参数,生成带情绪的语音。
关键接口说明
POSThttp://localhost:9880/tts
参数(JSON 格式):
| 字段 | 类型 | 说明 |
|---|---|---|
text | str | 要合成的文本(UTF-8) |
emotion | str | 情感类型,如"happy"、"angry"、"sad"、"surprised"、"tender"、"excited"等 |
reference_audio | str (optional) | base64 编码的参考音频(用于音色克隆),留空则使用默认音色 |
speed | float (optional) | 语速,默认 1.0,范围 0.5~2.0 |
output | str | 输出文件名(相对路径),如"output/test.wav" |
响应:返回.wav音频二进制流,直接写入文件即可。
示例一:生成“开心”语气的语音
下面这段脚本会生成一句轻快的话:“今天真是美好的一天!”
import requests import os # 创建 output 目录(如果不存在) os.makedirs("output", exist_ok=True) # API 地址 url = "http://localhost:9880/tts" # 请求数据 payload = { "text": "今天真是美好的一天!", "emotion": "happy", "speed": 1.2, "output": "output/happy_day.wav" } # 发送请求 response = requests.post(url, json=payload) # 检查状态 if response.status_code == 200: # 成功,保存音频 with open("output/happy_day.wav", "wb") as f: f.write(response.content) print("✅ 音频已生成:output/happy_day.wav") else: print(f"❌ 请求失败,状态码:{response.status_code}") print(response.text)运行后,在output/目录下会出现happy_day.wav,播放一下——语气确实是轻快上扬的,有种“蹦跳着说话”的感觉。
示例二:加入音色克隆(Zero-Shot Voice Cloning)
想让AI用你的声音说话?只需要一段3~10秒的清晰人声录音。
步骤如下:
- 准备一个
.wav音频文件,命名为ref.wav(单声道,16kHz 采样率最佳) - 转成 base64 字符串
- 传给 API 的
reference_audio字段
Python 实现:
import requests import base64 import os # 读取参考音频并编码 with open("ref.wav", "rb") as f: ref_b64 = base64.b64encode(f.read()).decode('utf-8') # API 请求 payload = { "text": "这是我用你的声音合成的语音。", "emotion": "tender", "reference_audio": ref_b64, "output": "output/cloned_voice.wav" } response = requests.post("http://localhost:9880/tts", json=payload) if response.status_code == 200: with open("output/cloned_voice.wav", "wb") as f: f.write(response.content) print("🎙️ 已生成克隆音色语音:cloned_voice.wav") else: print("❌ 克隆失败:", response.text)⚠️ 注意事项:
- 参考音频不要太长,否则可能超时;
- 不要太吵,背景安静、人声清晰最佳;
- 推荐使用 Audacity 导出为 WAV 格式,采样率设为 16000 Hz。
我试过用自己的录音做参考,生成的“温柔”语气真的像我在低声细语,朋友听了差点以为是我本人发的消息。
实测可用的情感列表
EmotiVoice 内置了多个情感 embedding,以下是经过测试有效的情感关键词(不区分大小写,但建议统一小写):
| 情感 | 效果描述 |
|---|---|
happy | 语调上扬,节奏轻快 |
angry | 声音紧绷,语速加快,适合质问 |
sad | 低沉缓慢,略带颤抖感 |
surprised | 突然拔高音调,有“哇”感 |
tender | 温柔细腻,适合撒娇或安抚 |
excited | 极度兴奋,类似欢呼 |
fearful | 颤抖、紧张,适合恐怖剧情 |
disgusted | 厌恶语气,鼻音加重 |
你可以挨个试试,效果相当真实。比如这句:
"text": "你怎么能这样对我?", "emotion": "angry"生成的语音真的有种“被背叛后愤怒质问”的感觉,不像传统 TTS 那样机械平淡。
常见问题与避坑指南
❌ 问题1:Docker 启动失败,报错No space left on device
很常见,尤其是Mac用户。Docker虚拟磁盘满了。
解决方法:
docker system prune -a清理所有未使用的镜像、容器、网络和缓存。
或者进入 Docker Desktop 设置 → Resources → Disk → 扩大磁盘空间。
❌ 问题2:API 返回空文件或状态码 500
别急着重装,先检查这几个点:
-text是否为空或超过长度限制(建议不超过 100 字)
-emotion拼写是否正确(比如写成happpy)
-output路径是否有写权限
- 参考音频是否为有效 WAV 格式(MP3不行!)
查看日志定位问题:
docker-compose logs你会发现很多有用信息,比如“audio format not supported”或“emotion not found”。
❌ 问题3:生成速度太慢(CPU 模式)
默认是CPU推理,长句子确实慢。如果你有NVIDIA GPU,可以启用CUDA加速。
修改docker-compose.yml:
version: '3' services: emotivoice: image: emotivoice/emotivoice:latest ports: - "9880:9880" volumes: - ./output:/app/output runtime: nvidia deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] restart: unless-stopped command: ["python", "app.py"]并确保主机已安装 NVIDIA Container Toolkit。
启用后,推理时间可从十几秒降到2~5秒。
❌ 问题4:如何更换默认音色?
目前默认音色是训练时的主 speaker。若要永久更换,需重新微调模型(fine-tune),门槛较高。
但更实用的方式是:通过reference_audio动态指定音色。这样更灵活,适合多角色场景。
例如,你可以建一个音色库,每个角色对应一段参考音频,调用时按需传入。
性能实测记录(仅供参考)
设备:Lenovo 小新 Air 13(i5-8250U, 16G RAM, 无独显)
| 文本长度 | 情感 | 平均耗时 |
|---|---|---|
| 10 字 | neutral | ~6s |
| 30 字 | happy | ~9s |
| 50 字 | angry | ~13s |
| 100 字 | sad | ~22s |
注:纯CPU模式,未优化。GPU加速后预计可缩短至 2~5 秒内。
对于实时性要求不高的场景(如有声书生成、客服回复语音化),完全可用。
为什么你应该试试 EmotiVoice?
到现在为止,我已经用它做了几件事:
- 给孩子生成“妈妈语气”的睡前故事,语气温柔得让他秒睡;
- 做了一个“暴躁客服机器人”demo,回答问题带着怒气,同事听完笑疯了;
- 试着克隆朋友的声音发语音消息,他第一反应是:“谁在冒充我?”
它的价值在于:让机器说话有了“情绪”。
不再是冷冰冰的播报,而是能传递喜怒哀乐的表达。
而这一切,只需要:
- 一条命令启动服务
- 一段 Python 脚本发起请求
- 一个想法去创造有温度的声音
下一步建议:让它走得更远
- 封装成 Flask 微服务,提供 Web 页面输入 + 情感选择,做成内部工具;
- 结合 ASR(语音识别),构建闭环对话系统,实现“听懂→思考→带情绪回应”;
- 用 Gradio 快速搭建交互界面,拖拽上传音频、选择情感、实时试听;
- 在树莓派上部署,做智能音箱原型,让家居设备“有脾气”也有“爱心”。
声音是有力量的。以前我们只能让程序“输出文字”,现在,可以让它“说出感情”。
等我哪天有钱了,一定配块 3090,把这玩意儿推到极限。
到时候,也许真能做出一个会“心疼你”的 AI。
🎙️
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考