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 isCC 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:
- Sentence splitting — if
split_text=Trueand the input is a string, it is split on newlines, or on。/.boundaries, into a list. - Normalization — each sentence passes through
Normalizer.__call__(language detect → normalize → homophone replace → invalid-char rejection). - Refine stage (
_refine_text) — unlessskip_refine_text=True, the Llama backbone rewrites the text with prosody tokens. Withrefine_text_only=True, it returns here. - Reference-speaker bootstrap — when splitting multiple sentences and no
spk_smpis given, the first sentence is synthesized and re-encoded as a speaker sample so the remaining sentences share a consistent voice. - Code stage (
_infer_code) — text + speaker prompt is tokenized and the backbone emits 4 VQ token streams. - Decode (
_decode_to_wavs) — tokens → mel viaDecoder/DVAE, mel → waveform via_vocos_decode. - Silence trimming — for non-streaming output, samples below
1e-5magnitude 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_bufandattention_mask_cachesized toprompt_len + max_new_token, then fills them token by token. This bounds memory but meansmax_new_tokendirectly sets the worst-case allocation. - Two modes.
infer_text=Truepredicts text tokens viahead_text;infer_text=Falsepredicts audio tokens across all 4 codebooks viahead_code. - Sampling. Logits are divided by per-codebook
temperature, passed through Top-P/Top-K warpers and the repetition penalty, softmaxed, thentorch.multinomialsamples the next token. Amanual_seedmakes 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 fixedmanual_seed, it does not retry (to stay deterministic). - Streaming. When
stream=True, partialGenerationOutputsare yielded everystream_batchtokens. - Termination. Stops when all sequences hit EOS, when
context.get()is set (a userinterrupt()), or whenmax_new_tokenis reached (logged as "incomplete result. hit max_new_token").
Note
The
Contextobject (a tiny interrupt flag ingpt.py) is howChat.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). SeeSpeaker.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. |
4.2 Running the OpenAI-compatible server (recommended for integration)
# 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_pathappropriately if behind a path prefix (web UI). - [ ] Run one process per available GPU; cap concurrent requests per process at 1.
- [ ] Set
inputlength limits at the edge (the OpenAI server caps at 2048 chars; the native server does not). - [ ] Monitor VRAM; long
max_new_tokenvalues raise peak memory. - [ ] Provide the community speaker
.ptfiles 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
.envfile, YAML config, or settings module. "Configuration" is either model hyperparameters (dataclasses inconfig.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")inopenai_api.pyis the single highest-severity issue for a hosted deployment. Treat every.ptspeaker 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 annn.Modulewithload_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
exceptclauses: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.pyis 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.pyuses 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 whenuse_vllm=Trueon Linux.ChatTTS/model/cuda/holds the experimental TransformerEngine Llama, used only whenexperimental=Trueon 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 = 4codebooks; 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+.