限时福利领取


背景与痛点

语音合成(TTS)早已不是“朗读文本”这么简单:短视频自动配音、客服机器人、有声书批量生产,甚至游戏 NPC 的实时对话,都在把“秒级、低成本、高自然度”的语音当成刚需。
可真正动手时,新手往往卡在三点:

  • 环境拼积木:Python 版本、PyTorch CUDA 驱动、音频依赖库,一步错步步错。
  • 流程黑盒子:模型权重、Vocoder、声码器、采样率,参数散落在不同仓库,缺乏可视化调试。
  • 生产难落地:并发请求一上来,GPU 显存爆炸;长文本分段不当,停顿诡异;偶尔网络抖动,整条工作流直接崩。

ComfyUI 把 Stable Diffusion 的“节点式”玩法带到语音领域,再接入专为对话场景微调的 ChatTTS,正好把“环境+流程+生产”串成一条可拖拽的透明管线,让入门门槛瞬间降到“会点 Python 就能玩”。

技术选型:为什么选 ChatTTS

维度 ChatTTS 常见云端 API 本地 FastSpeech2
自然度 4.2/5(MOS) 4.4/5 3.8/5
中文韵律 专为对话优化,停顿自然 通用模型,偶尔机器腔 需额外训练
离线可商用 权重可下载,Apache 2.0 按量计费+合规审核 可离线,但需自己找声码器
硬件成本 6G 显存可跑 零硬件,按调用付费 4G 显存,但音质差一截

结论:想要“免费+离线+中文聊天感”,ChatTTS 是当前本地方案里最省心的那一个。

核心实现

1. ComfyUI 环境配置详解

官方仓库已提供一键整合包,但自己动手三步更清爽:

  1. 新建 Python 3.10 虚拟环境,CUDA 11.8 驱动≥522.06。
  2. 安装 ComfyUI 主程序:
    git clone https://github.com/comfyanonymous/ComfyUI.git
    cd ComfyUI
    pip install -r requirements.txt
    
  3. 把 ChatTTS 作为“自定义节点”放进去:
    cd custom_nodes
    git clone https://github.com/2Noise/ComfyUI-ChatTTS
    cd ComfyUI-ChatTTS
    pip install -r requirements.txt
    
    权重会在首次运行时自动下载到 models/ChatTTS/

2. ChatTTS API 集成步骤

节点内部其实只干两件事:

  • 加载 ChatTTS.ChatTTS() 模型实例,常驻显存。
  • 把前端输入的“文本 + 音色种子”打包成 params_infer_code,调用 model.infer() 拿到 16kHz 波形,再转回 ComfyUI 的 AUDIO 类型。

核心代码片段(已含异常捕获):

import ChatTTS
import torch
import numpy as np

class ChatTTSNode:
    def __init__(self):
        self.model = None
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    def load_model(self):
        if self.model is None:
            self.model = ChatTTS.ChatTTS()
            self.model.load(compile=False)  # 编译可提速,但首次慢
        return self.model

    def generate(self, text, seed=42, speed=1.0, temperature=.3):
        model = self.load_model()
        torch.manual_seed(seed)
        wavs = model.infer(
            [text],
            params_infer_code={
                'spk_emb': None,  # 随机音色
                'temperature': temperature,
                'top_P': 0.7,
                'top_K': 20,
                'prompt': "[speed_{}]".format(speed)
            }
        )
        # wavs[0] 是 16kHz 浮点数组,直接返回
        return (wavs[0] * 32767).astype(np.int16)

3. 工作流节点设计

拖拽界面里只需四个节点即可跑通:

  • TextInput → 输入待合成文本
  • ChatTTSNode → 上方代码封装
  • SaveAudio → 输出 wav 到本地
  • PreviewAudio → 前端直接播放

架构示意

节点之间用 AUDIO 类型连线,采样率统一 16kHz,避免二次重采样失真。

完整代码示例:文本预处理 → 语音输出

以下脚本脱离 ComfyUI 也能跑,方便单元测试:

# tts_cli.py
import ChatTTS
import torch
import soundfile as sf
import re
import argparse

def normalize_text(text: str) -> str:
    """简单文本清洗:去掉网址、多余空格"""
    text = re.sub(r"http\S+", "", text)
    text = re.sub(r"\s+", " ", text).strip()
    return text

def generate_audio(text: str, output_path: str, seed: int = 42):
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    chat = ChatTTS.ChatTTS()
    chat.load(compile=False)
    torch.manual_seed(seed)
    wavs = chat.infer([normalize_text(text)], params_infer_code={
        'spk_emb': None,
        'temperature': 0.3,
        'top_P': 0.7,
        'top_K': 20,
        'prompt': '[speed_1]'
    })
    sf.write(output_path, wavs[0], 16000)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--text", required=True, help="待合成文本")
    parser.add_argument("--out",  default="output.wav")
    parser.add_argument("--seed", type=int, default=42)
    args = parser.parse_args()
    generate_audio(args.text, args.out, args.seed)

运行示例:

python tts_cli.py --text "你好,这是一条测试语音。" --out demo.wav

生产考量

  1. 并发处理

    • ChatTTS 模型本身占显存 3.5G,再加安全余量,单卡 6G 只能跑一个实例。
    • 使用 FastAPI + gunicorn 启动多进程时,设置 --workers=1,通过横向扩展容器而不是显存超卖。
  2. 错误处理与重试

    • 捕获 RuntimeError: CUDA out of memory,退回到 CPU 模式并写入日志,不直接抛 500。
    • 对网络下载权重环节加 tenacity 重试,最多 3 次,间隔 5s。
  3. 音频质量调优

    • 温度 0.3→0.5 会让声音更活泼,但过高容易口吃。
    • 长文本提前按句号切分,每段 ≤ 200 字,再批量 infer,可抑制首尾爆音。
    • 输出后用 sox 做一键音量归一化:sox input.wav -r 16000 -b 16 -c 1 output.wav norm -3

避坑指南

坑位 现象 快速解决
权重下载中断 卡在 99% 不动 手动下载到 models/ChatTTS/,确保 *.bin*.json 成对出现
采样率混用 输出听起来像变声器 所有节点统一 16kHz,禁止 44.1k→16k 二次转码
显存泄漏 第二次推理 OOM 节点里 with torch.no_grad() 包裹 infer,并手动 del wavs
音色漂移 同 seed 不同卡声音不一致 固定 torch.manual_seed 前同步 CUDA_LAUNCH_BLOCKING=1
长文本爆音 末尾出现“啪”一声 按 200 字切分 + 静音 0.2s 拼接,再用 sox 淡入淡出

延伸思考

  • 多语言:ChatTTS 已支持中英混输,把 [lang_en][lang_zh] 写进 prompt 即可切换音素集。
  • 情感化:在 params_infer_code 加入 [laugh_0.5] [break_0.3] 可让句子带笑或停顿,适合游戏配音。
  • 实时流式:改 infer 为分块生成,配合 WebSocket 推送,每 0.5s 返回一段音频,实现“边打字边出声”。
  • 声音克隆:官方将释出 speaker embedding 微调脚本,准备 30 条干净音频即可把“默认音色”换成指定主播。

节点拖拽界面

把以上节点保存为模板,下次打开 ComfyUI 直接加载,就能一键复现整条语音合成管线。
先跑通离线 demo,再逐步把并发、监控、音色管理加上,一条可商用的 ChatTTS 工作流就稳稳落地了。

限时福利领取


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐