进阶 docs.voicebox.sh 2026-10-11 09:58:06 · 25 阅读

第25章 TTS 语音生成

开发者 | TTS 生成

Voicebox 多引擎后端中的文本转语音生成机制

概览

Voicebox 内置八种 TTS 引擎——Qwen3-TTS、Qwen CustomVoice、Qwen VoiceDesign、LuxTTS、Chatterbox Multilingual、Chatterbox Turbo、TADA 和 Kokoro——均通过统一的 TTSBackend Protocol 提供服务。它们暴露相同的异步接口,使路由和服务层无需针对特定引擎进行分支判断。

本页介绍生成流程如何穿过这层抽象。关于添加新引擎的分步指南,请参阅 TTS Engines。

TTSBackend Protocol

每个引擎都实现相同的契约(定义在 backend/backends/__init__.py 中):

@runtime_checkable
class TTSBackend(Protocol):
    async def load_model(self, model_size: str) -> None: ...
    async def create_voice_prompt(
        self, audio_path: str, reference_text: str, use_cache: bool = True
    ) -> Tuple[dict, bool]: ...
    async def combine_voice_prompts(
        self, audio_paths: List[str], reference_texts: List[str]
    ) -> Tuple[np.ndarray, str]: ...
    async def generate(
        self,
        text: str,
        voice_prompt: dict,
        language: str = "en",
        seed: Optional[int] = None,
        instruct: Optional[str] = None,
    ) -> Tuple[np.ndarray, int]: ...
    def unload_model(self) -> None: ...
    def is_loaded(self) -> bool: ...

ModelConfig 注册表

每种可下载的模型变体都由 ModelConfig dataclass 描述:

@dataclass
class ModelConfig:
    model_name: str       # "luxtts", "qwen-tts-1.7B", "kokoro"
    display_name: str     # "LuxTTS (Fast, CPU-friendly)"
    engine: str           # "luxtts", "qwen", "kokoro"
    hf_repo_id: str       # "YatharthS/LuxTTS"
    model_size: str = "default"
    size_mb: int = 0
    needs_trim: bool = False
    retries_runaway: bool = False
    supports_instruct: bool = False
    languages: list[str] = field(default_factory=lambda: ["en"])

backends/__init__.py 中的注册表辅助函数取代了以往针对单个引擎的 if/elif 链:

  • get_all_model_configs() — 获取所有 TTS + STT 变体
  • get_tts_model_configs() — 仅获取 TTS 变体
  • get_model_config(model_name) — 按名称查找
  • engine_needs_trim(engine) — 判断输出是否需经过 trim_tts_output()
  • engine_retries_runaway(engine) — 判断不稳定输出是否需以更小块重试
  • load_engine_model(engine, model_size) — 下载并加载模型,支持多尺寸引擎
  • get_tts_backend_for_engine(engine) — 线程安全的后端工厂,采用双重检查锁定

TTS_ENGINES 字典是内置引擎名称的规范列表:

TTS_ENGINES = {
    "qwen": "Qwen TTS",
    "qwen_custom_voice": "Qwen CustomVoice",
    "luxtts": "LuxTTS",
    "chatterbox": "Chatterbox TTS",
    "chatterbox_turbo": "Chatterbox Turbo",
    "tada": "TADA",
    "kokoro": "Kokoro",
}

语音提示模式

各引擎通过 create_voice_prompt() 返回的 prompt dict 决定如何表示语音。目前使用三种模式:

模式 A — 预计算张量(Qwen3-TTS, LuxTTS)

encoded = model.encode_prompt(audio_path)
return encoded, False  # (prompt_dict, was_cached)

模式 B — 延迟文件路径(Chatterbox, Chatterbox Turbo, TADA)

return {"ref_audio": audio_path, "ref_text": reference_text}, False

模式 C — 预设语音指针(Kokoro, Qwen CustomVoice)

return {
    "voice_type": "preset",
    "preset_engine": "kokoro",
    "preset_voice_id": "am_adam",
}, False

模式 C 用于 voice_type 为 "preset" 的配置文件——无需克隆步骤;引擎直接通过 ID 查找内置语音。

缓存语音提示的引擎会为其缓存键添加前缀以避免冲突:

cache_key = f"{engine}_{hash(audio_path, reference_text)}"

设备选择

引擎通过 backends/base.py 中的 get_torch_device() 选择设备,其优先级分层如下:

  • VOICEBOX_FORCE_CPU 环境变量覆盖
  • CUDA(若已编译且可用)
  • XPU(Intel Arc 通过 IPEX)
  • MPS(Apple Silicon)— 仅限支持该特性的引擎;部分引擎(如 Chatterbox 和旧版 Qwen 路径)因上游算子缺失而跳过 MPS,回退至 CPU
  • CPU

Qwen TTS 在 Apple Silicon 上直接使用 MLX,而非通过 PyTorch——详见 mlx_backend.py。

生成流程

从前端到音频文件的请求路径:

  • 请求 — 携带 GenerationRequest 的 POST /generate:
    {
      "profile_id": "uuid",
      "text": "...",
      "language": "en",
      "seed": 42,
      "model_size": "1.7B",
      "instruct": "warm, slightly amused",
      "engine": "qwen",
      "max_chunk_chars": 800
    }
    
    引擎字段需通过正则 ^(qwen|qwen_custom_voice|luxtts|chatterbox|chatterbox_turbo|tada|kokoro)$ 验证。
  • 路由 — routes/generate.py 验证输入并委托处理。
  • 服务 — services/generation.py 获取配置文件,通过 get_tts_backend_for_engine(engine) 解析引擎后端,并确保模型已加载(首次使用时下载并提供实时进度)。
  • 语音提示 — 服务调用 create_voice_prompt()(或预设等价物)。对于包含多个样本的克隆配置文件,先调用 combine_voice_prompts() 合并参考音频。
  • 队列 — 请求通过 services/task_queue.py 串行化,避免多个生成任务争抢 GPU。
  • 推理 — 引擎的 generate() 返回 (audio_array, sample_rate)。
  • 验证与后处理 — 带有 retries_runaway=True 的引擎将以更小块重试不稳定输出。若 engine_needs_trim(engine) 为 True,trim_tts_output() 将去除尾部静音。特效链(如有)应用于生成版本,而非干净版本。
  • 持久化 — 音频写入生成目录,在 generations 表中插入一行,响应中包含生成元数据。

长文本分块

超过 max_chunk_chars 的文本(默认 800,范围 100–5000)将在句子边界处拆分,依次生成并交叉淡化拼接。分块行为与引擎无关——它位于服务层,而非单个后端中。

Instruct 模式

两种引擎支持通过 instruct 关键字参数进行自然语言语速控制:

  • Qwen CustomVoice — supports_instruct=True,完全接入模型的 instruct 头。
  • Qwen Base — 静默丢弃 instruct 文本(supports_instruct=False)。前端对 Base 配置文件隐藏 instruct 输入。
# 优质的 instruct 提示示例:
"warm and conversational, slight smile"
"whisper, intimate and close"
"authoritative, broadcast quality"

其他引擎完全忽略 instruct。

内存管理

模型在首次使用时惰性加载并驻留内存。在模型尺寸之间切换(如 Qwen 1.7B ↔ 0.6B)时,会先卸载旧模型再加载新模型,以避免 OOM:

def unload_model(self):
    if self.model is not None:
        del self.model
        self.model = None
        if torch.cuda.is_available():
            torch.cuda.empty_cache()

模型管理 API(/models/load, /models/unload)允许用户手动释放 VRAM——详见 Model Management。

API 端点

方法端点描述
POST/generate从文本生成语音
GET/audio/{generation_id}提供生成的音频文件

响应模式

{
  "id": "generation_uuid",
  "profile_id": "profile_uuid",
  "text": "...",
  "language": "en",
  "audio_path": "/path/to/audio.wav",
  "duration": 3.5,
  "seed": 42,
  "engine": "qwen",
  "model_size": "1.7B",
  "instruct": "...",
  "created_at": "2026-04-18T10:30:00Z"
}

性能考量

  • CUDA 是所有基于 PyTorch 引擎的最快后端。对于 Qwen TTS,Apple Silicon MLX 可与 CUDA 竞争。
  • 串行队列 — 每个进程同时仅运行一个生成任务;并发请求将被排队。
  • 语音提示缓存可为同一配置文件的重复生成节省约 1-2 秒。
  • 模型固定 — 首次加载较慢(下载 + 加载),后续生成复用内存中缓存的模型。

各引擎 VRAM 占用(CUDA 下近似值)

引擎VRAM
Kokoro~150 MB
LuxTTS~1 GB
Chatterbox Turbo~1.5 GB
Qwen 0.6B / Qwen CustomVoice 0.6B~2 GB
Chatterbox Multilingual~3 GB
Qwen 1.7B / Qwen CustomVoice 1.7B~6 GB
TADA 1B~4 GB
TADA 3B~8 GB

后续步骤

  • TTS Engines 添加新引擎 — 完整的分阶段工作流
  • Model Management 模型下载、加载和卸载
  • Voice Profiles 克隆与预设配置文件模式

Edit on GitHub | Voice Profiles — Voicebox 中语音配置文件管理的工作原理 | TTS Engines — 如何向 Voicebox 添加新的文本转语音引擎

评论 (0)