基于 ChatTTS 构建支持情感控制的 TTS 服务
在语音合成领域,单纯的自然度往往不够,赋予声音情感色彩能显著提升交互体验。本文将带你从零搭建一个支持情感控制、可二次封装的 TTS 服务,核心基于 ChatTTS 模型,并集成 Flask 提供 API 接口。
环境准备与模型部署
首先,我们需要准备好运行环境。ChatTTS 对 PyTorch 版本和 CUDA 有一定要求,建议直接使用虚拟环境隔离依赖。
1. 初始化项目结构
打开终端,创建项目目录并激活虚拟环境:
mkdir MyEmotionalTTS && cd MyEmotionalTTS
python -m venv venv
# Linux/Mac 激活
source venv/bin/activate
# Windows 激活
venv\Scripts\activate
安装核心依赖。这里以 CUDA 12.1 为例,请根据实际显卡驱动调整:
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install ChatTTS transformers soundfile ipython scipy simpleaudio flask
2. 加载与验证模型
创建一个 init_model.py 脚本,用于下载权重并验证模型可用性。注意,首次运行会自动下载约 2GB 的模型文件。
import ChatTTS
import torch
import warnings
warnings.filterwarnings("ignore")
# 初始化 ChatTTS 实例
chat = ChatTTS.Chat()
# 加载模型,compile=False 可避免部分环境下的编译错误
chat.load_models(compile=False)
print("模型加载成功!")
print(f"设备:{chat.device}")
# 设为推理模式
chat.eval()
运行 python init_model.py 确认无报错后再继续。
核心封装与情感控制
直接调用 ChatTTS 原生接口较为繁琐,且难以灵活控制情感参数。我们将其封装为一个类,通过映射表管理不同情感对应的超参数。
创建 EmotionalTTS.py:
import ChatTTS
import torch
import numpy as np
import soundfile as sf
typing , ,
warnings
warnings.filterwarnings()
:
():
.chat = ChatTTS.Chat()
device:
.chat.load_models(=, device=device)
:
.chat.load_models(=)
.chat.()
.emotion_params_map = {
: {: , : },
: {: , : },
: {: , : },
: {: , : },
: {: , : }
}
()
() -> :
texts = [text]
params = .emotion_params_map.get(emotion, .emotion_params_map[])
rand_spk = np.random.randint(, ) speaker_embedding
torch.no_grad():
wavs, _ = .chat.infer(
texts,
params_refine_text={: },
params_infer_code={
: speaker_embedding,
: rand_spk,
: params[],
},
do_text_normalization=,
return_duration=
)
audio_data = wavs.squeeze()
speed != :
scipy signal
new_length = ((audio_data) / speed)
audio_data = signal.resample(audio_data, new_length)
save_path:
save_path.endswith():
save_path +=
sf.write(save_path, audio_data, samplerate=sample_rate)
()
audio_data, sample_rate
() -> []:
os
os.makedirs(save_dir, exist_ok=)
emotions :
emotions = [] * (texts)
file_paths = []
i, (text, emotion) ((texts, emotions)):
()
save_path = os.path.join(save_dir, )
.synthesize(text, emotion=emotion, save_path=save_path)
file_paths.append(save_path)
file_paths
() -> []:
(.emotion_params_map.keys())


