Jesse A. Green / notebook

ChatTTS Admin & Developer Guide

Generated June 2026 from 2noise/ChatTTS at 77b89ee

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is the deep reference for engineers deploying, operating, integrating, or extending ChatTTS — the generative dialogue-oriented text-to-speech model from the 2noise organization. It covers the model architecture, the inference pipeline internals, deployment of the bundled API/UI servers, configuration, security considerations, code structure, and improvement opportunities.

For installation and day-to-day usage, see the companion ChatTTS User Guide. This document assumes you are comfortable with PyTorch, the Hugging Face Transformers stack, and serving Python models.

Important

Licensing has operational consequences. The code is AGPLv3+ (network-use copyleft) and the pretrained model is CC BY-NC 4.0 (non-commercial only). If you deploy ChatTTS as a network service, AGPL obligations attach to your modifications, and the model license forbids commercial use. Treat this repo as an academic/research reference implementation, not a production product.


1. Executive Summary

ChatTTS is a two-stage autoregressive TTS system wrapped in a single Python class, ChatTTS.Chat. The repository is intentionally scoped as "algorithm infrastructure and some simple examples" — it is a model + reference pipeline, not a turnkey hosted product.

Aspect Summary
Purpose Conversational, expressive TTS (EN/ZH) with prosody control.
Language Python (one Go helper for checksums).
Core dependency PyTorch ≥ 2.1 + Hugging Face Transformers (Llama backbone) + Vocos vocoder.
Model size 40,000-hour pretrained base (open), no SFT. Main internal model trained on 100,000+ hours.
Public surfaces Python API, CLI, Gradio web UI, native FastAPI server, OpenAI-compatible FastAPI server.
Sample rate 24,000 Hz, mono.
State Stateless inference; model loaded once into memory, reused per request.
Persistence None beyond model asset files on disk; no database.
Scaling model Single-process, single-model-in-memory; concurrency guarded by a lock in the OpenAI server.

The system's defining design choice is that it generates discrete audio tokens (4 vector-quantization codebooks) with a Llama transformer, then decodes those tokens to a mel-spectrogram via a DVAE, and finally to a waveform via the Vocos neural vocoder.


2. Architecture

2.1 End-to-end pipeline

                ┌─────────────────────────────────────────────────────────────┐
   text  ─────▶ │  Normalizer (norm.py)                                        │
                │   • language detect (zh/en)                                   │
                │   • text normalization (NeMo / WeTextProcessing, optional)   │
                │   • homophone replacement (numba _fast_replace)              │
                └───────────────────────────┬─────────────────────────────────┘
                                            │ cleaned text
                ┌───────────────────────────▼─────────────────────────────────┐
   STAGE 1      │  Refine text (GPT.generate, infer_text=True)                 │
   (optional)   │   • Tokenizer (BertTokenizerFast) → input_ids               │
                │   • Llama backbone predicts prosody-marked token stream      │
                │   • controlled by RefineTextParams                           │
                └───────────────────────────┬─────────────────────────────────┘
                                            │ refined text
                ┌───────────────────────────▼─────────────────────────────────┐
   STAGE 2      │  Infer code (GPT.generate, infer_text=False)                 │
                │   • Speaker prompt injection ([Stts][spk_emb]…[Ptts])        │
                │   • Embed (audio+text token embeddings) → Llama backbone     │
                │   • emits 4 VQ codebook token streams (num_vq=4)             │
                │   • controlled by InferCodeParams                            │
                └───────────────────────────┬─────────────────────────────────┘
                                            │ audio tokens (hiddens or ids)
                ┌───────────────────────────▼─────────────────────────────────┐
   DECODE       │  DVAE / Decoder (dvae.py)                                    │
                │   • GFSQ de-quantize → ConvNeXt decoder → mel-spectrogram    │
                └───────────────────────────┬─────────────────────────────────┘
                                            │ mel spectrogram
                ┌───────────────────────────▼─────────────────────────────────┐
   VOCODER      │  Vocos (external lib)                                        │
                │   • MelSpectrogram features → ISTFT head → waveform          │
                └───────────────────────────┬─────────────────────────────────┘
                                            ▼
                                   24 kHz float32 PCM  ─▶ tools/audio → mp3/wav/ogg

2.2 Component inventory

Component File Role
Chat ChatTTS/core.py Orchestrator. Owns config, normalizer, all sub-models; exposes load/infer/unload/interrupt.
Config (+ nested dataclasses) ChatTTS/config/config.py Static model hyperparameters and asset paths.
Normalizer ChatTTS/norm.py Text cleaning, language detection, homophone replacement (numba-jitted).
Tokenizer ChatTTS/model/tokenizer.py Wraps BertTokenizerFast; encodes text + speaker prompt into (input_ids, attention_mask, text_mask).
Embed ChatTTS/model/embed.py Joint text + 4×audio-codebook embedding tables and output heads.
GPT ChatTTS/model/gpt.py Llama backbone + autoregressive generate() loop (text and code modes).
Speaker ChatTTS/model/speaker.py Speaker-embedding sampling, encode/decode, prompt decoration.
DVAE ChatTTS/model/dvae.py Encoder/decoder + GFSQ vector quantizer; mel-spectrogram ↔ tokens.
gen_logits / processors ChatTTS/model/processors.py Top-P/Top-K warpers + custom repetition penalty.
Utilities ChatTTS/utils/ Asset download + SHA-256 verification, device selection, safetensors I/O, logging.
Audio I/O tools/audio/ PyAV-based load/encode, PCM↔WAV/MP3/OGG conversion, float→int16.
Normalizer adapters tools/normalizer/ Thin factories for NeMo (en) and WeTextProcessing (zh).
Seeder tools/seeder/ctx.py TorchSeedContext for reproducible RNG scopes.
Logger tools/logger/log.py Colorized, timestamped logging formatter.
Checksum tool tools/checksum/*.go Go program that regenerates sha256_map.json for asset integrity.

2.3 Model hyperparameters (from config/config.py)

These are baked-in dataclass defaults — they describe the released model, not user-tunable knobs.

Group Key Value
GPT (Llama backbone) hidden_size 768
intermediate_size 3072
num_attention_heads 12
num_hidden_layers 20
max_position_embeddings 4096
num_audio_tokens 626
num_text_tokens 21178
num_vq (codebooks) 4
spk_emb_dim 192
DVAE / VQ vq.levels (5, 5, 5, 5)
vq.G / vq.R (groups/residuals) 2 / 2
decoder n_layer 12
Vocos feature extractor sample_rate 24000
n_fft / hop_length 1024 / 256
n_mels 100

2.4 Model assets

The model ships as a set of files under an asset/ directory, verified by SHA-256 against the checked-in ChatTTS/res/sha256_map.json:

Asset Purpose
asset/Vocos.safetensors Vocos vocoder weights.
asset/DVAE.safetensors DVAE encoder/decoder (used for cloning + fallback decode).
asset/Decoder.safetensors High-quality decoder (the default decode path).
asset/Embed.safetensors Token embedding tables and heads.
asset/gpt/{config.json, model.safetensors} Llama backbone.
asset/tokenizer/{...} BERT fast tokenizer files.

Assets are obtained either via Hugging Face snapshot_download(repo_id="2Noise/ChatTTS") (source="huggingface") or via an external Go downloader rvcmd (the RVC-Models-Downloader release, used by source="local").


3. The Inference Engine in Detail

3.1 Chat.infer() control flow

infer() (in core.py) is the public entry; _infer() is the generator that does the work:

  1. Sentence splitting — if split_text=True and the input is a string, it is split on newlines, or on 。 / . boundaries, into a list.
  2. Normalization — each sentence passes through Normalizer.__call__ (language detect → normalize → homophone replace → invalid-char rejection).
  3. Refine stage (_refine_text) — unless skip_refine_text=True, the Llama backbone rewrites the text with prosody tokens. With refine_text_only=True, it returns here.
  4. Reference-speaker bootstrap — when splitting multiple sentences and no spk_smp is given, the first sentence is synthesized and re-encoded as a speaker sample so the remaining sentences share a consistent voice.
  5. Code stage (_infer_code) — text + speaker prompt is tokenized and the backbone emits 4 VQ token streams.
  6. Decode (_decode_to_wavs) — tokens → mel via Decoder/DVAE, mel → waveform via _vocos_decode.
  7. Silence trimming — for non-streaming output, samples below 1e-5 magnitude are stripped and (when split) concatenated into one array.

3.2 The autoregressive loop (GPT.generate)

gpt.py's generate() is the heart of the system. Key behaviors operators should understand:

  • Pre-allocation. It pre-allocates inputs_ids_buf and attention_mask_cache sized to prompt_len + max_new_token, then fills them token by token. This bounds memory but means max_new_token directly sets the worst-case allocation.
  • Two modes. infer_text=True predicts text tokens via head_text; infer_text=False predicts audio tokens across all 4 codebooks via head_code.
  • Sampling. Logits are divided by per-codebook temperature, passed through Top-P/Top-K warpers and the repetition penalty, softmaxed, then torch.multinomial samples the next token. A manual_seed makes this deterministic.
  • Empty-output guard. If the model emits EOS at step 0 and ensure_non_empty=True, it recursively restarts generation (logged as "regenerate in order to ensure non-empty"). With a fixed manual_seed, it does not retry (to stay deterministic).
  • Streaming. When stream=True, partial GenerationOutputs are yielded every stream_batch tokens.
  • Termination. Stops when all sequences hit EOS, when context.get() is set (a user interrupt()), or when max_new_token is reached (logged as "incomplete result. hit max_new_token").

Note

The Context object (a tiny interrupt flag in gpt.py) is how Chat.interrupt() cooperatively stops a running stream. It is checked once per generated token.

3.3 Speaker embeddings

Speaker (speaker.py) represents a voice as a 192-dim vector sampled from a Gaussian whose mean/std come from the spk_stat statistics string baked into config.py. Embeddings are serialized for transport by LZMA-compressing the float16 bytes and base16384-encoding the result — that is why speaker strings are long and opaque, and why a corrupted string raises lzma.LZMAError (see Troubleshooting). Voice cloning (sample_audio_speaker) instead encodes DVAE tokens of a reference clip via encode_prompt.

3.4 Prompt grammar (internal control tokens)

The model is conditioned with bracketed control tokens. Two categories matter:

  • Structural tokens injected by the code, not the user: [Stts], [Ptts], [spk_emb], [empty_spk], [Sbreak], [Pbreak], [Ebreak] (EOS for refine). See Speaker.decorate_code_prompts / decorate_text_prompts.
  • User prosody tokens documented in the User Guide: [oral_N], [laugh_N], [break_N] (refine prompt), [speed_N] (infer prompt), and inline [laugh]/[uv_break]/[lbreak].

Tip

The tokenizer special IDs are resolved at load: spk_emb_ids = "[spk_emb]", break_0_ids = "[break_0]", eos_token = "[Ebreak]". If you swap tokenizers, these must exist or generation breaks.


4. Deployment

ChatTTS itself is a library; the deployable artifacts are the example servers. None of them ship with a Dockerfile, process manager, or TLS — that is your responsibility.

4.1 Choosing a server

Server File Output Concurrency Best for
Native API examples/api/main.py ZIP of MP3s None built in Batch synthesis of sentence lists.
OpenAI-compatible API examples/api/openai_api.py mp3/wav/ogg stream asyncio.Lock around inference Drop-in for OpenAI TTS clients.
Web UI examples/web/webui.py In-browser audio Single user Interactive demos and tuning.
# From the project root, with the model reachable
fastapi run examples/api/openai_api.py --host 0.0.0.0 --port 8000

On startup it: loads the model from Hugging Face, registers EN/ZH normalizers, creates an asyncio.Lock, and preloads the voice files in VOICE_MAP (1528.pt, 1384.pt, 2443.pt) into app.state.spk_emb_map. Missing voice files log a warning and fall back to the default speaker.

Important

The server holds exactly one model in memory and serializes inference with an asyncio.Lock. Throughput is one synthesis at a time per process. To scale, run multiple processes behind a load balancer, each with its own GPU/VRAM budget (≥4 GB each). There is no built-in queue, batching across requests, or autoscaling.

4.3 Production checklist

  • [ ] Pin Python to 3.10/3.11 in a clean environment.
  • [ ] Pre-download model assets at build time (chat.load()), not on first request, to avoid cold-start downloads.
  • [ ] Verify asset integrity passes (SHA-256 check in utils/dl.py).
  • [ ] Run behind a reverse proxy that terminates TLS; the example servers serve plain HTTP.
  • [ ] Add authentication/rate limiting at the proxy — the example servers have none (see Security).
  • [ ] Set --server_name/--root_path appropriately if behind a path prefix (web UI).
  • [ ] Run one process per available GPU; cap concurrent requests per process at 1.
  • [ ] Set input length limits at the edge (the OpenAI server caps at 2048 chars; the native server does not).
  • [ ] Monitor VRAM; long max_new_token values raise peak memory.
  • [ ] Provide the community speaker .pt files if you rely on named voices.

4.4 Environment variables

Variable Read in Default Purpose
CHTTS_VER setup.py v0.0.0 Package version stamp at build time.
HF_HOME core.py ~/.cache/huggingface Hugging Face cache root for snapshot lookups.
CHATTTS_SERVICE_HOST client.py / postScript.py localhost / 127.0.0.1 Host the HTTP clients target.
CHATTTS_SERVICE_PORT client.py / postScript.py 8000 / 9900 Port the HTTP clients target.
PYTORCH_ENABLE_MPS_FALLBACK set automatically on macOS 1 Lets unsupported MPS ops fall back to CPU.
TOKENIZERS_PARALLELISM set in tokenizer.py false Silences the HF tokenizer fork warning.

Note

There is no .env file, YAML config, or settings module. "Configuration" is either model hyperparameters (dataclasses in config.py, not meant to change) or per-call parameters (RefineTextParams/InferCodeParams). The handful of environment variables above are the only external config surface.


5. Operations

5.1 Logging

All components use tools/logger/log.py's get_logger(name), which installs a colorized formatter producing lines like:

[+0800 20260411 12:00:03] [INFO] ChatTTS | core | gpt loaded.

Color is disabled on Windows. Noisy third-party loggers (numba, httpx, wetext-zh_normalizer, NeMo-text-processing) are pinned to WARNING. Pass a custom logging.Logger to ChatTTS.Chat(logger=...) to route logs into your own stack.

Key log signals to watch:

Log line Meaning
... loaded. (vocos/dvae/gpt/speaker/decoder/tokenizer) Successful staged model load.
Switching to CPU. GPU/NPU had < min_memory (2047 MB) free.
regenerate in order to ensure non-empty Model emitted immediate EOS; auto-retrying.
incomplete result. hit max_new_token Output truncated by the token cap.
generation is interrupted interrupt() was called mid-stream.
replace homophones: X->Y Homophone substitution applied.
found invalid characters: {...} Characters stripped by the reject pattern.

5.2 Memory management

ChatTTS is aggressive about freeing tensors mid-loop (del, del_all in utils/io.py) because generation pre-allocates large buffers. Chat.unload() deletes all sub-models and re-initializes the object so it can be reloaded. Call unload() before reloading with new options (the web UI's Reload button does exactly this).

5.3 Asset integrity & regeneration

utils/dl.py verifies each asset's SHA-256 against ChatTTS/res/sha256_map.json; mismatches are renamed to .bak and re-downloaded when update=True. If you fine-tune or replace assets, regenerate the map with the Go tool:

cd tools/checksum && go run .   # writes ChatTTS/res/sha256_map.json

5.4 Device selection

utils/gpu.py:select_device() picks, in order: the CUDA/NPU device with the most free memory (if ≥ ~2 GB free), else MPS (only with experimental=True), else DirectML (only with experimental=True), else CPU. Vocos and the MelSpectrogram run on CPU when the device is MPS/NPU because complex-dtype ops are unsupported there.


6. Security Analysis

Caution

The example servers are reference demos, not hardened services. Do not expose them directly to untrusted networks. The findings below are inherent to the shipped code.

Area Finding Mitigation
Authentication None on any endpoint (/generate_voice, /v1/audio/speech, /health, web UI). Put an authenticating reverse proxy / API gateway in front.
Rate limiting / DoS None. max_new_token up to 2048 per request; the native API has no input length cap. A flood of long inputs exhausts GPU/CPU. Enforce request size, length, and rate limits at the edge; cap max_new_token.
Untrusted deserialization The OpenAI server torch.load()s speaker .pt files at startup. torch.load can execute arbitrary code from a malicious pickle. Only load speaker files from trusted sources; prefer safetensors-format speaker files if you control them.
Speaker/coef strings User-supplied spk_emb/coef are LZMA+base16384 decoded. Malformed input raises (handled), but very large inputs could be a memory vector. Validate/limit the size of user-supplied embedding strings.
Network bind default Web UI binds 0.0.0.0:8080 by default. Bind to 127.0.0.1 behind a proxy, or restrict with firewall rules.
Asset download Models fetched over HTTPS from HF / GitHub releases, integrity-checked by SHA-256. This is a reasonable supply-chain posture. Keep sha256_map.json under review; pin asset versions.
CORS Not configured on the FastAPI apps. Add explicit CORS rules if browser clients call the API cross-origin.
Model misuse The model is anti-cloning-hardened (added noise, MP3 compression) but voice synthesis is inherently dual-use. Enforce acceptable-use policy; respect the non-commercial license.

Warning

The startup torch.load(spk_path, map_location="cpu") in openai_api.py is the single highest-severity issue for a hosted deployment. Treat every .pt speaker file as executable code and load only files you produced or fully trust.


7. Code Quality & Patterns

Strengths

  • Clean separation of concerns: orchestration (core.py), model components (model/), I/O and infra (utils/, tools/). Each model piece is an nn.Module with load_pretrained.
  • Config as typed dataclasses: hyperparameters are explicit and discoverable in one file.
  • Performance-conscious: numba-jitted hot paths (homophone replacement, float→int16), pre-allocated generation buffers, eager tensor freeing, optional torch.compile/vLLM.
  • Pluggable normalization: Normalizer.register() lets you add language normalizers without touching core code.
  • Multi-surface, single engine: four front-ends (CLI/UI/two APIs) all funnel into one Chat.infer, avoiding logic duplication of the model path.

Weaknesses / risks

  • Broad except clauses: core.py's HF download path and the web UI's normalizer registration swallow exceptions broadly (except: / except BaseException), which can hide real failures.
  • Deprecated FastAPI patterns: @app.on_event("startup") is deprecated in favor of lifespan handlers; both example servers still use it.
  • Vendored Transformers code: examples/onnx/modeling_llama.py is a large copy of HF's Llama implementation for ONNX export — a maintenance/version-drift liability.
  • Mixed-language comments: core streaming logic (examples/cmd/stream.py) is commented in Chinese only, raising the bar for non-Chinese contributors.
  • Global mutable state in the web UI: funcs.py uses module-level globals (chat, enable_cache, is_in_generate) — fine for a single-user demo, unsafe for multi-user serving.
  • No automated test suite of substance: tests/ holds issue-reproduction scripts (#511.py, #588.py, #655.py) and a shell runner, not unit tests.

8. Repository Structure

ChatTTS/
├── ChatTTS/                 # the installable package
│   ├── core.py             # Chat orchestrator (load / infer / unload)
│   ├── norm.py             # Normalizer (lang detect, homophones)
│   ├── config/config.py    # model hyperparameter dataclasses
│   ├── model/
│   │   ├── gpt.py          # Llama backbone + generate() loop
│   │   ├── dvae.py         # DVAE encoder/decoder + GFSQ quantizer
│   │   ├── embed.py        # token embedding tables + heads
│   │   ├── speaker.py      # speaker sampling / encode / cloning
│   │   ├── tokenizer.py    # BertTokenizerFast wrapper
│   │   ├── processors.py   # logits warpers + repetition penalty
│   │   ├── cuda/           # experimental TransformerEngine path
│   │   └── velocity/       # vLLM-based accelerated GPT backend
│   ├── res/                # homophones_map.json, sha256_map.json
│   └── utils/              # dl (download+verify), gpu, io, log
├── tools/
│   ├── audio/              # PyAV load + PCM↔mp3/wav/ogg
│   ├── normalizer/         # NeMo (en) + WeTextProcessing (zh) adapters
│   ├── seeder/             # TorchSeedContext
│   ├── logger/             # colorized logging formatter
│   ├── llm/                # ChatOpenAI helper (LLM→TTS text prep)
│   └── checksum/           # Go tool to regenerate sha256_map.json
├── examples/
│   ├── cmd/                # run.py (CLI), stream.py (ChatStreamer)
│   ├── web/                # Gradio webui.py + funcs.py + ex.py
│   ├── api/                # main.py, openai_api.py, client.py, postScript.py
│   ├── onnx/               # ONNX exporter + vendored Llama
│   └── ipynb/              # Colab + example notebooks
├── docs/                   # translated READMEs (cn/jp/ru/es/fr/kr)
├── tests/                  # issue-reproduction scripts
├── requirements.txt
└── setup.py

Note

ChatTTS/model/velocity/ is a self-contained vLLM-style engine (block manager, scheduler, sampler, worker) used only when use_vllm=True on Linux. ChatTTS/model/cuda/ holds the experimental TransformerEngine Llama, used only when experimental=True on Linux+CUDA. Both are inert in a default install.


9. Internals Reference

9.1 Key classes and methods

Class.method File:line Notes
Chat.load core.py:142 Downloads + loads all sub-models; returns bool.
Chat.infer core.py:215 Public synthesis entry; wraps the _infer generator.
Chat._infer core.py:395 Normalize → refine → reference-speaker → code → decode.
Chat._infer_code core.py:551 Builds prompts, runs GPT code generation (vLLM-aware).
Chat._refine_text core.py:674 Text-refinement GPT pass.
Chat.sample_random_speaker core.py:183 Gaussian speaker sample → encoded string.
Chat.sample_audio_speaker core.py:186 Encode a reference clip into a speaker sample (cloning).
GPT.generate gpt.py:722 The autoregressive sampling loop.
DVAE.forward dvae.py:271 Encode (mel→tokens) / decode (tokens→mel).
Speaker.encode_prompt/decode_prompt speaker.py LZMA+base16384 (de)serialization of prompts.
Tokenizer.encode tokenizer.py:1321 Left-padded input_ids + masks, optional speaker prompt.
Normalizer.__call__ norm.py:926 The full text-cleaning pipeline.
gen_logits processors.py:1108 Builds Top-P/Top-K warpers + repetition penalty.

9.2 HTTP API reference

Server Method Path Request Response
native POST /generate_voice ChatTTSParams JSON (text[], flags, params_refine_text, params_infer_code) application/zip of {idx}.mp3
openai POST /v1/audio/speech OpenAI TTS JSON (model, input, voice, response_format, speed, stream) streamed audio/mpeg or audio/wav
openai GET /health — {"status":"healthy","model_loaded":true}

The native server's ChatTTSParams (main.py) mirrors infer() arguments; note it embeds the typed ChatTTS.Chat.RefineTextParams/InferCodeParams directly as Pydantic-compatible models. The OpenAI server whitelists request params (ALLOWED_PARAMS) and forces model="tts-1".

9.3 Dependency footprint

Dependency Role
torch>=2.1.0, torchaudio Tensor compute, mel-spectrogram.
transformers>=4.41.1 Llama backbone + BERT tokenizer.
vocos Neural vocoder (mel → waveform).
vector_quantize_pytorch GroupedResidualFSQ for the DVAE.
numba JIT for homophone replace + float→int16.
numpy<3.0.0 Array ops throughout.
pybase16384 Base16384 codec for embeddings.
av, pydub Audio decode/encode (PyAV + FFmpeg detection).
gradio Web UI.
fastapi API example servers.
IPython, tqdm, requests Notebooks, progress bars, downloads.
pynini, WeTextProcessing, nemo_text_processing Linux-only text normalization.

10. Potential Improvements

Derived from the code and community issues — candidates for contributors or downstream forks.

Area Improvement Rationale
Serving Add request batching + a proper queue in the API servers. Current lock serializes all inference; GPU is underutilized under load.
Security Replace startup torch.load of .pt voices with safetensors. Removes arbitrary-code-execution risk from speaker files.
FastAPI Migrate @app.on_event("startup") to lifespan handlers. Deprecated API; future FastAPI removal.
Robustness Narrow broad except:/except BaseException blocks. Hidden download/registration failures are hard to diagnose.
Stability Guard against empty/too-short input before generation. Eliminates the recurring narrow(): length must be non-negative crash (#955/#978).
Packaging Ship a Dockerfile + pinned environment. Removes Python/CUDA/Transformers version drift (#876, #987, #930).
Testing Convert tests/#NNN.py reproductions into a real pytest suite. No regression safety net today.
Docs/i18n Translate Chinese-only inline comments in streaming code. Lowers contribution barrier.
vLLM Investigate timbre bias on the vLLM path (#640, #840, #847). Accelerated path degrades voice quality.
Feature Surface the roadmap's multi-emotion control once models ship. Currently only [laugh]/[uv_break]/[lbreak] work at token level.

11. Quick Reference

Minimal programmatic load + infer

import ChatTTS, torch, torchaudio
chat = ChatTTS.Chat()
assert chat.load(source="huggingface")
wavs = chat.infer(["hello world"], skip_refine_text=True)
torchaudio.save("o.wav", torch.from_numpy(wavs[0]).unsqueeze(0), 24000)

Serve the OpenAI-compatible API

fastapi run examples/api/openai_api.py --host 127.0.0.1 --port 8000
curl -s localhost:8000/health

Regenerate asset checksums

cd tools/checksum && go run .

Reproducible voice

import torch
torch.manual_seed(1111)
spk = chat.sample_random_speaker()   # reuse spk as InferCodeParams.spk_emb

Key invariants

  • Sample rate is always 24000 Hz mono.
  • num_vq = 4 codebooks; backbone is a 20-layer Llama, hidden 768.
  • One model per process; OpenAI server serializes inference via asyncio.Lock.
  • Speaker strings are LZMA + base16384 — store them verbatim.
  • Model is non-commercial (CC BY-NC 4.0); code is AGPLv3+.