
📦 第一阶段:环境准备与模型部署
1. 创建项目并安装核心依赖
打开你的终端,执行以下命令:
# 1. 创建项目目录
mkdir MyEmotionalTTS && cd MyEmotionalTTS
# 2. 创建Python虚拟环境(推荐)
python -m venv venv
# 在Linux/Mac上激活:
source venv/bin/activate
# 在Windows上激活:
# venv\Scripts\activate
# 3. 安装PyTorch (根据你的CUDA版本选择,以CUDA 12.1为例)
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu121
# 4. 安装ChatTTS及其他依赖
pip install ChatTTS transformers soundfile ipython
2. 下载并初始化ChatTTS模型
创建一个名为 init_model.py 的脚本,写入以下代码:
import ChatTTS
import torch
import warnings
warnings.filterwarnings("ignore")
# 初始化ChatTTS
chat = ChatTTS.Chat()
# 加载模型(自动下载权重,约2GB)
chat.load_models(compile=False) # `compile=False` 可避免特定环境下的错误
# 查看可用模型参数(可选)
print("模型加载成功!")
print(f"设备: {chat.device}")
# 将模型设为推理模式(重要)
chat.eval()
# 保存模型对象以供后续使用(示例,实际我们会在封装类中管理)
# import pickle
# with open('chat_model.pkl', 'wb') as f:
# pickle.dump(chat, f)
运行它来下载和验证模型:
python init_model.py
🧱 第二阶段:核心封装与情感控制接口

创建一个核心封装类 EmotionalTTS.py,这是二次封装的精髓。
import ChatTTS
import torch
import numpy as np
import soundfile as sf
from typing import List, Optional, Dict
import warnings
warnings.filterwarnings("ignore")
class EmotionalTTS:
"""
情感TTS二次封装类。
提供易于使用的接口,用于控制情感、音色和语速。
"""
def __init__(self, model_path: str = None, device: str = None):
"""
初始化TTS引擎。
Args:
model_path: 预加载的模型路径(暂无用处,ChatTTS自动下载)。
device: 指定设备,如 'cuda', 'cpu'。为None则自动选择。
"""
self.chat = ChatTTS.Chat()
# 加载模型
if device:
self.chat.load_models(compile=False, device=device)
else:
self.chat.load_models(compile=False)
# 设置为评估模式
self.chat.eval()
# 情感-参数映射字典 (你可以根据效果扩展这个字典)
self.emotion_params_map = {
'happy': {'temperature': 0.7, 'spk_emb': None}, # 开心,语速稍快
'sad': {'temperature': 0.3, 'spk_emb': None}, # 悲伤,语速慢
'angry': {'temperature': 0.9, 'spk_emb': None}, # 生气,音调高
'neutral': {'temperature': 0.5, 'spk_emb': None}, # 中性
'friendly': {'temperature': 0.6, 'spk_emb': None}, # 友好
}
print(f"[初始化完成] 模型运行在: {self.chat.device}")
def synthesize(self,
text: str,
emotion: str = 'neutral',
speaker_embedding: Optional[np.ndarray] = None,
speed: float = 1.0,
sample_rate: int = 24000,
save_path: Optional[str] = None) -> np.ndarray:
"""
核心合成函数。
Args:
text: 要合成的文本。
emotion: 情感标签,从 `emotion_params_map` 中选择。
speaker_embedding: 可选,特定说话人音色嵌入。
speed: 语速因子 ( >1 加速, <1 减速)。
sample_rate: 输出音频采样率。
save_path: 如需直接保存,提供.wav文件路径。
Returns:
audio_data: 合成的音频波形数据 (numpy数组)。
"""
# 1. 文本预处理 (ChatTTS要求特殊处理)
texts = [text]
# 2. 情感参数注入 (通过`infer_seed`控制)
params = self.emotion_params_map.get(emotion, self.emotion_params_map['neutral'])
# 3. 生成随机种子以实现不同的情感/音色 (可控的随机性)
rand_spk = np.random.randint(0, 100000) if speaker_embedding is None else None
# 4. 模型推理
with torch.no_grad():
wavs, _ = self.chat.infer(
texts,
params_refine_text={
'prompt': f'[speaker_emo={emotion}]' # 提示词控制情感
},
params_infer_code={
'spk_emb': speaker_embedding,
'seed': rand_spk,
'temperature': params['temperature'],
},
do_text_normalization=True,
return_duration=True
)
audio_data = wavs.squeeze() # 从 [1, samples] 变为 [samples]
# 5. 语速调整 (简单的重采样,生产环境可用更优算法)
if speed != 1.0:
from scipy import signal
new_length = int(len(audio_data) / speed)
audio_data = signal.resample(audio_data, new_length)
# 6. 保存文件(如果提供了路径)
if save_path:
if not save_path.endswith('.wav'):
save_path += '.wav'
sf.write(save_path, audio_data, samplerate=sample_rate)
print(f"[音频已保存] -> {save_path}")
return audio_data, sample_rate
def batch_synthesize(self,
texts: List[str],
emotions: Optional[List[str]] = None,
save_dir: str = "./output_batch") -> List[str]:
"""
批量合成文本。
Args:
texts: 文本列表。
emotions: 对应的情感列表,为None则全部使用中性。
save_dir: 输出目录。
Returns:
file_paths: 保存的音频文件路径列表。
"""
import os
os.makedirs(save_dir, exist_ok=True)
if emotions is None:
emotions = ['neutral'] * len(texts)
file_paths = []
for i, (text, emotion) in enumerate(zip(texts, emotions)):
print(f"处理中 ({i+1}/{len(texts)}): {text[:30]}... [{emotion}]")
save_path = os.path.join(save_dir, f"batch_{i:03d}_{emotion}.wav")
self.synthesize(text, emotion=emotion, save_path=save_path)
file_paths.append(save_path)
return file_paths
def get_available_emotions(self) -> List[str]:
"""返回预定义的情感标签列表。"""
return list(self.emotion_params_map.keys())
# 示例:如何创建音色嵌入(高级功能,用于克隆特定音色)
def create_speaker_embedding(self, reference_audio_path: str) -> np.ndarray:
"""
从参考音频中提取说话人嵌入。
Args:
reference_audio_path: 参考音频文件路径(.wav)。
Returns:
spk_emb: 说话人嵌入向量。
"""
# 注意:ChatTTS官方尚未直接提供此接口,此处为示意。
# 实际可参考其 `infer` 方法中 `spk_emb` 的用法。
# 这里返回一个随机向量作为占位符。
print(f"[提示] 音色克隆功能需参考官方最新实现。")
return np.random.randn(1, 1024).astype(np.float32) # 占位符
🚀 第三阶段:使用与测试
创建一个测试脚本 test_tts.py 来使用我们的封装类。

from EmotionalTTS import EmotionalTTS
import soundfile as sf
import simpleaudio as sa # 用于直接播放,安装: pip install simpleaudio
def main():
# 1. 初始化引擎
print("="*50)
print("初始化情感TTS引擎...")
tts_engine = EmotionalTTS(device='cuda') # 如果你有GPU
# tts_engine = EmotionalTTS(device='cpu') # 使用CPU
# 2. 查看支持的情感
print("支持的情感:", tts_engine.get_available_emotions())
print("="*50)
# 3. 单句合成示例
test_text = "你好,世界!这是一个测试,看看情感语音合成效果怎么样。"
# 用不同的情感合成同一句话
for emo in ['neutral', 'happy', 'sad', 'angry']:
print(f"\n>>> 正在用「{emo}」情感合成...")
audio_data, sr = tts_engine.synthesize(
text=test_text,
emotion=emo,
speed=1.0 if emo != 'sad' else 0.9, # 悲伤时语速放慢
save_path=f"./output/demo_{emo}.wav" # 保存文件
)
# 尝试播放(如果环境支持)
try:
play_obj = sa.play_buffer(audio_data, 1, 2, sr)
play_obj.wait_done()
except:
print(f"音频已保存,如需播放请查看文件: demo_{emo}.wav")
# 4. 批量合成示例
print("\n" + "="*50)
print("开始批量合成示例...")
batch_texts = [
"早上好,今天天气真不错。",
"我对此感到非常失望。",
"太棒了!我们终于成功了!",
"请立即离开这个地方。"
]
batch_emotions = ['friendly', 'sad', 'happy', 'angry']
saved_files = tts_engine.batch_synthesize(
texts=batch_texts,
emotions=batch_emotions,
save_dir="./output/batch"
)
print(f"批量合成完成,共生成 {len(saved_files)} 个文件。")
# 5. 高级:尝试自定义情感参数(直接修改映射)
print("\n" + "="*50)
print("高级:自定义情感参数...")
tts_engine.emotion_params_map['whisper'] = {'temperature': 0.2, 'spk_emb': None} # 耳语
audio_custom, _ = tts_engine.synthesize(
"这是一个秘密,我只告诉你一个人。",
emotion='whisper',
save_path="./output/whisper_secret.wav"
)
print("自定义情感「whisper」合成完成。")
if __name__ == "__main__":
# 确保有输出目录
import os
os.makedirs("./output", exist_ok=True)
os.makedirs("./output/batch", exist_ok=True)
main()
print("\n所有测试完成!请检查 './output' 目录下的音频文件。")
🔧 第四阶段:部署为API服务(Flask示例)
将你的封装部署为Web服务,以便其他程序调用。创建 api_service.py:

from flask import Flask, request, jsonify, send_file
from EmotionalTTS import EmotionalTTS
import io
import soundfile as sf
import numpy as np
import uuid
import os
app = Flask(__name__)
tts_engine = None
def init_engine():
global tts_engine
print("正在加载TTS模型...")
tts_engine = EmotionalTTS(device='cpu') # API服务通常用CPU
print("模型加载完毕,API服务就绪。")
init_engine()
@app.route('/synthesize', methods=['POST'])
def synthesize():
"""API端点:文本转语音"""
data = request.json
# 解析请求参数
text = data.get('text', '')
emotion = data.get('emotion', 'neutral')
speed = float(data.get('speed', 1.0))
if not text:
return jsonify({'error': '文本内容不能为空'}), 400
# 调用引擎合成
try:
audio_data, sr = tts_engine.synthesize(
text=text,
emotion=emotion,
speed=speed
)
# 将音频数据转为字节流返回
audio_bytes = io.BytesIO()
sf.write(audio_bytes, audio_data, samplerate=sr, format='WAV')
audio_bytes.seek(0)
# 也可以选择保存到文件后返回URL(生产环境建议)
# filename = f"{uuid.uuid4()}.wav"
# filepath = os.path.join('./audio_cache', filename)
# sf.write(filepath, audio_data, sr)
# return jsonify({'url': f'/audio/{filename}'})
return send_file(
audio_bytes,
mimetype='audio/wav',
as_attachment=True,
download_name=f'speech_{emotion}.wav'
)
except Exception as e:
return jsonify({'error': f'合成失败: {str(e)}'}), 500
@app.route('/emotions', methods=['GET'])
def list_emotions():
"""返回支持的情感列表"""
return jsonify({'emotions': tts_engine.get_available_emotions()})
if __name__ == '__main__':
os.makedirs('./audio_cache', exist_ok=True)
# 生产环境请使用 waitress 或 gunicorn,不要用debug模式
app.run(host='0.0.0.0', port=5000, debug=True, use_reloader=False)
启动API服务:
python api_service.py
使用CURL测试API:
curl -X POST http://127.0.0.1:5000/synthesize \
-H "Content-Type: application/json" \
-d '{"text": "你好,欢迎使用情感TTS API服务", "emotion": "friendly", "speed": 1.1}' \
--output output_api.wav
📝 重要补充与高级扩展
1. 如何提升效果与定制化
- 优化情感:调整
emotion_params_map中的temperature值(0.1-1.5),值越高声音越有表现力(可能不稳定),值越低保真稳定。 - 细粒度控制:在文本中插入 ChatTTS特定的控制符,例如
[uv_break](短停顿)、[laugh](笑声),能让效果更生动。 - 微调模型:如果想针对特定场景(如广播剧)优化,需准备高质量的
(文本, 音频, 情感标签)配对数据,使用ChatTTS训练脚本进行微调。
2. 项目结构建议
MyEmotionalTTS/
├── EmotionalTTS.py # 核心封装类
├── init_model.py # 初始化脚本
├── test_tts.py # 测试脚本
├── api_service.py # Flask API服务
├── requirements.txt # 依赖列表
├── output/ # 生成音频目录
└── README.md # 项目说明
3. 生产环境注意事项
- 性能:首次推理较慢,后续会缓存。如需高并发,考虑模型预热和队列系统。
- 稳定性:API服务中务必添加异常处理和输入验证。
- 内存:加载模型约占用2-3GB GPU内存(或更多CPU内存)。可尝试使用
torch.compile或模型量化(如torch.quantization)进行优化。
这个方案提供了从安装、封装、测试到部署的完整代码链路。可以直接复制代码运行,并根据注释进行修改和扩展。

2190

被折叠的 条评论
为什么被折叠?



