Jesse A. Green / notebook

ChatTTS User 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.

ChatTTS is a generative text-to-speech (TTS) model built for conversational, dialogue-style speech — the kind of natural, expressive narration you want from an LLM voice assistant. It speaks English and Chinese (including mixed-language input), supports multiple speakers, and can place fine-grained prosodic events like laughter, pauses, and intonation breaks directly from markers in your text.

This guide shows you how to install ChatTTS, generate your first audio, control how the voice sounds, and use every interface the project ships: the Python API, the command line, the web UI, and two HTTP API servers.

Important

The released model is published for academic and research purposes only. The code is licensed under AGPLv3+; the pretrained model is licensed under CC BY-NC 4.0 (non-commercial). To discourage misuse, the public 40,000-hour model was trained with added high-frequency noise and compressed audio quality. Use ChatTTS responsibly.


1. Quick Start

The fastest path from zero to audio is three lines of Python. The first call to load() downloads the pretrained model automatically.

import ChatTTS
import torch
import torchaudio

chat = ChatTTS.Chat()
chat.load(compile=False)  # set compile=True for faster inference (slower startup)

texts = ["Hello, this is my first ChatTTS sentence."]
wavs = chat.infer(texts)

torchaudio.save("output.wav", torch.from_numpy(wavs[0]).unsqueeze(0), 24000)
[+0800 20260411 12:00:00] [INFO] ChatTTS | core | vocos loaded.
[+0800 20260411 12:00:01] [INFO] ChatTTS | core | dvae loaded.
[+0800 20260411 12:00:03] [INFO] ChatTTS | core | gpt loaded.
[+0800 20260411 12:00:03] [INFO] ChatTTS | core | speaker loaded.
[+0800 20260411 12:00:04] [INFO] ChatTTS | core | decoder loaded.
[+0800 20260411 12:00:04] [INFO] ChatTTS | core | tokenizer loaded.
code:  100%|██████████| 512/512(max) [00:07, 68.5it/s]

Note

All ChatTTS audio is generated at a 24,000 Hz sample rate, mono. Always pass 24000 as the sample rate when saving.

Tip

wavs[i] is a NumPy float32 array. Some versions of torchaudio expect a 2-D tensor (.unsqueeze(0)) and some expect a 1-D tensor. If torchaudio.save raises a dimension error, try saving without .unsqueeze(0):

try:
    torchaudio.save("output.wav", torch.from_numpy(wavs[0]).unsqueeze(0), 24000)
except Exception:
    torchaudio.save("output.wav", torch.from_numpy(wavs[0]), 24000)

Prefer not to write Python? Two one-line commands give you the same result from the project root:

# Launch the browser-based web UI
python examples/web/webui.py

# Generate audio directly from the command line (saves output_audio_0.mp3)
python examples/cmd/run.py "Your first sentence." "Your second sentence."

2. Requirements

Requirement Detail
Python 3.10 or 3.11 recommended (conda create -n chattts python=3.11)
PyTorch torch>=2.1.0 plus torchaudio
GPU memory At least 4 GB of VRAM for a ~30-second clip. CPU works but is slow.
Disk Room for the pretrained model assets (downloaded on first run)
FFmpeg Optional — needed for MP3/OGG output. Without it, the web UI falls back to WAV.

Hardware acceleration is auto-detected in this order: CUDA GPU → Ascend NPU → Apple MPS (experimental) → DirectML (experimental) → CPU. You do not need to configure anything; ChatTTS picks the best available device and the GPU with the most free memory.

Note

On the 4090 GPU, ChatTTS generates roughly 7 semantic tokens per second, giving a Real-Time Factor (RTF) of about 0.3 (audio is produced ~3× faster than real time). Apple MPS is currently slower than CPU and is only used when you explicitly opt in.


3. Installation

ChatTTS can be installed as a published package or run directly from a clone of the repository. Run-from-clone is required if you want the CLI, web UI, or API examples, because those live in the examples/ folder and depend on the tools/ folder.

From PyPI (library use)

pip install ChatTTS

Latest from GitHub

pip install git+https://github.com/2noise/ChatTTS

Clone + requirements (full project)

git clone https://github.com/2noise/ChatTTS
cd ChatTTS
pip install --upgrade -r requirements.txt

Conda environment

conda create -n chattts python=3.11
conda activate chattts
pip install -r requirements.txt

Editable / dev mode

pip install -e .

Optional: text normalization packages

ChatTTS can normalize numbers, dates, and symbols into spoken words ("$123" → "one hundred and twenty three dollars") before synthesis. This requires extra packages that are not installed by default. They are Linux-friendly and registered manually at runtime (see Section 7).

# Chinese normalization (WeTextProcessing)
conda install -c conda-forge pynini=2.1.5
pip install WeTextProcessing

# English normalization (NeMo)
conda install -c conda-forge pynini=2.1.5
pip install nemo_text_processing

Note

pynini, WeTextProcessing, and nemo_text_processing are declared as Linux-only dependencies in requirements.txt. On Windows/macOS, ChatTTS still runs — it simply skips text normalization and logs a warning telling you which package is missing.

Optional: vLLM acceleration (Linux only)

pip install safetensors vllm==0.2.7 torchaudio

Then pass use_vllm=True to chat.load(...). See Section 9.

Warning

Do NOT install TransformerEngine or FlashAttention-2 for normal use. The TransformerEngine integration is still under development and cannot run properly. FlashAttention-2 currently slows down generation. Both are gated behind experimental flags and are for development only.


4. Everyday Usage (Python API)

The entire Python interface is the ChatTTS.Chat class. The lifecycle is always the same: create → load → infer.

4.1 Load the model

import ChatTTS
chat = ChatTTS.Chat()
chat.load()

load() accepts several useful options:

Parameter Type Default What it does
source "local" / "huggingface" / "custom" "local" Where to get the model. local downloads into the current directory's asset/; huggingface pulls from the HF Hub; custom uses your own custom_path.
force_redownload bool False Re-download even if assets already exist.
compile bool False Compile the model with torch.compile for faster inference. Slower first run; CUDA only.
custom_path str None Path to a directory containing the asset/ model files (used with source="custom", or as a cache dir for HF).
device torch.device None Force a device. If None, ChatTTS auto-selects (see Section 2).
coef str None A custom DVAE coefficient string to tweak the vocoder. Leave unset normally.
use_flash_attn bool False Enable FlashAttention-2. Not recommended (see warning above).
use_vllm bool False Use the vLLM backend for the GPT stage (Linux).
experimental bool False Allow experimental accelerators (MPS, DirectML, TransformerEngine).
enable_cache bool True Use the model's KV cache during generation.

load() returns True on success and False if the model failed to download or load — always check it:

if not chat.load(source="huggingface"):
    raise RuntimeError("ChatTTS model failed to load")

Tip

The first load() downloads several hundred megabytes of model assets. To control where they go, pass custom_path="/path/to/models". To reuse an already-downloaded model without any network access, use source="custom" with custom_path pointing at the folder that contains asset/.

4.2 Generate audio with infer()

infer() is the one method you call to turn text into audio. It accepts a single string or a list of strings and returns a list of NumPy audio arrays.

texts = [
    "Conversational speech, generated locally.",
    "ChatTTS handles a list of sentences in one call.",
]
wavs = chat.infer(texts)

for i, wav in enumerate(wavs):
    torchaudio.save(f"out_{i}.wav", torch.from_numpy(wav).unsqueeze(0), 24000)

The most useful infer() arguments:

Argument Default Purpose
text (required) A string or list of strings to synthesize.
stream False Stream audio chunks as they are generated instead of returning all at once (see Section 6).
lang None Force language for normalization: "zh" or "en". None = auto-detect.
skip_refine_text False Skip the text-refinement pass (see below). Set True when you control prosody yourself with inline tokens.
refine_text_only False Return the refined text without generating audio. Useful for previewing how the model will read your input.
use_decoder True Use the high-quality decoder path (recommended).
do_text_normalization True Normalize numbers/symbols into words (needs the optional packages).
do_homophone_replacement True Fix commonly mispronounced Chinese characters (see Section 7).
split_text True Automatically split long input into sentence-sized batches.
max_split_batch 4 Maximum number of sentences processed per batch when splitting.
params_refine_text RefineTextParams() Controls the text-refinement stage (see Section 5).
params_infer_code InferCodeParams() Controls the audio-generation stage (see Section 5).

Note

What is "refine text"? ChatTTS has two stages. The refine stage rewrites your raw text into a token stream sprinkled with prosody markers (pauses, breaks) so the speech sounds natural. The infer code stage turns that into audio. If you already wrote your own prosody markers into the text, pass skip_refine_text=True so the model uses your markers verbatim.

4.3 Preview refined text without making audio

refined = chat.infer("hello how are you today", refine_text_only=True)
print(refined)
# e.g. ['hello [uv_break] how are you today [uv_break]']

4.4 Unload and interrupt

chat.unload()       # free all model memory; chat can be reloaded later
chat.interrupt()    # stop an in-progress streaming generation

5. Controlling the Voice

There are two layers of control: inline tokens you put inside the text, and parameter objects you pass to infer().

5.1 Inline prosody tokens

ChatTTS understands special bracketed markers inside your text. They tell the model to laugh, pause, or change speaking style at exactly that point.

Token Meaning Where to use it
[laugh] Insert laughter Word level, inside the text
[uv_break] A short, natural pause / breath Word level, inside the text
[lbreak] A longer break (line break) Word level, end of a clause
[oral_N] Oral/casual speaking style, N = 0–9 In the refine prompt
[laugh_N] Laughter intensity, N = 0–2 In the refine prompt
[break_N] Pause length, N = 0–7 In the refine prompt
[speed_N] Speaking speed, N = 0–9 In the infer-code prompt (default [speed_5])

Important

In the current released model, the only token-level control units that work inside the body of your text are [laugh], [uv_break], and [lbreak]. The [oral_N], [laugh_N], and [break_N] tokens belong in the refine-text prompt (see below), and [speed_N] belongs in the infer-code prompt. Additional emotion controls may be released in future model versions.

Word-level example (you supply the prosody, so skip refinement):

text = "What is [uv_break] your favorite english food?[laugh][lbreak]"
wavs = chat.infer(text, skip_refine_text=True)

5.2 RefineTextParams — shaping the text-refinement stage

Pass this as params_refine_text. Its prompt field is where [oral_N], [laugh_N], and [break_N] go.

params_refine_text = ChatTTS.Chat.RefineTextParams(
    prompt="[oral_2][laugh_0][break_6]",
)
wavs = chat.infer(texts, params_refine_text=params_refine_text)
Field Default Meaning
prompt "" Prosody control tokens for refinement (e.g. [oral_2][laugh_0][break_6]).
top_P 0.7 Nucleus sampling probability.
top_K 20 Top-K sampling cutoff.
temperature 0.7 Sampling randomness.
repetition_penalty 1.0 Penalty for repeated tokens.
max_new_token 384 Maximum tokens of refined text.
min_new_token 0 Minimum tokens before the model may stop.
show_tqdm True Show a progress bar.
ensure_non_empty True Retry if the model produces empty output.
manual_seed None Fix the random seed for reproducible refinement.

5.3 InferCodeParams — shaping the audio stage

Pass this as params_infer_code. This is where you attach a speaker and set the speed. It inherits every field from RefineTextParams and adds speaker/streaming fields.

params_infer_code = ChatTTS.Chat.InferCodeParams(
    spk_emb=rand_spk,     # a fixed speaker (see Section 8)
    temperature=0.3,      # default for the audio stage
    top_P=0.7,
    top_K=20,
    prompt="[speed_5]",   # speaking speed
)
wavs = chat.infer(texts, params_infer_code=params_infer_code)
Field Default Meaning
prompt "[speed_5]" Speed token, [speed_0]–[speed_9].
spk_emb None A speaker-embedding string (fixed timbre). None = random each run.
spk_smp None A speaker sample code derived from a reference audio clip (voice cloning).
txt_smp None The transcript of the reference clip used with spk_smp.
temperature 0.3 Sampling randomness for audio (lower = more stable).
repetition_penalty 1.05 Penalty against repetitive audio tokens.
max_new_token 2048 Maximum audio tokens (caps clip length).
stream_batch 24 Tokens per streamed chunk.
stream_speed 12000 Samples emitted per streamed chunk.
pass_first_n_batches 2 Warm-up batches skipped before streaming starts.

Tip

For the most natural results, the README's reference settings are temperature=0.3, top_P=0.7, top_K=20 for the audio stage. Lower the temperature toward 0.1 if the voice wanders or produces artifacts; raise it slightly for more expressive delivery.


6. Streaming Audio

Set stream=True to receive audio chunks as they are generated — ideal for low-latency playback while the rest of the sentence is still synthesizing.

chat = ChatTTS.Chat()
chat.load(compile=False)

rand_spk = chat.sample_random_speaker()
params = ChatTTS.Chat.InferCodeParams(spk_emb=rand_spk, temperature=0.3, top_P=0.7, top_K=20)

stream_gen = chat.infer(
    ["This sentence is produced and played back chunk by chunk."],
    skip_refine_text=True,
    stream=True,
    params_infer_code=params,
)

for chunk in stream_gen:    # chunk is a NumPy array of audio samples
    ...                      # send to your audio sink / websocket

The project also ships a ready-made streaming helper, ChatStreamer, in examples/cmd/stream.py. It buffers small chunks until there is enough audio, formats them as 16-bit PCM, and can play them straight to your speakers:

from examples.cmd.stream import ChatStreamer

stream_gen = chat.infer(texts, skip_refine_text=True, stream=True, params_infer_code=params)
ChatStreamer().play(stream_gen, wait=5)   # buffers ~5 s, then plays in real time

Note

ChatStreamer.play() requires the pyaudio package, which you install manually. It is meant for CPU users where generation is slower than playback — the wait argument is how many seconds to pre-buffer before audio starts.


7. Text Normalization and Homophones

ChatTTS cleans your input text before synthesis. Two independent steps are involved, both controllable from infer().

7.1 Text normalization (do_text_normalization=True)

Converts numbers, dates, currency, and symbols into spoken words, and detects whether the sentence is Chinese or English. It only runs if you have registered a normalizer for that language — otherwise the step is silently skipped.

Register normalizers after loading the model:

from tools.normalizer.en import normalizer_en_nemo_text
from tools.normalizer.zh import normalizer_zh_tn

chat.normalizer.register("en", normalizer_en_nemo_text())
chat.normalizer.register("zh", normalizer_zh_tn())

Warning

The English normalizer needs nemo_text_processing; the Chinese normalizer needs WeTextProcessing. If the package is missing, register() raises and you'll see a log line telling you exactly which pip install to run (see Section 3). The model still synthesizes — it just won't expand "$123" into words.

7.2 Homophone replacement (do_homophone_replacement=True)

For Chinese, ChatTTS ships a built-in map (homophones_map.json) of ~180,000 commonly mispronounced characters, each mapped to a correctly pronounced homophone. When enabled, mispronounced characters are swapped before synthesis and the substitutions are logged.

wavs = chat.infer(zh_texts, do_homophone_replacement=True)
[INFO] ChatTTS | norm | replace homophones: 喲->唷

Note

Homophone replacement defaults to True in the Python API but is set to False in some of the bundled example clients — check the example's body if your output differs from what you expect.


8. Speakers and Voice Cloning

By default, every infer() call samples a fresh random speaker, so the voice changes run to run. To keep a consistent voice, generate a speaker embedding once and reuse it.

8.1 Sample and reuse a fixed speaker

rand_spk = chat.sample_random_speaker()
print(rand_spk)   # a long encoded string — SAVE THIS to recover the timbre later

params = ChatTTS.Chat.InferCodeParams(spk_emb=rand_spk)
wavs = chat.infer(texts, params_infer_code=params)

The returned rand_spk is a compact encoded string. Store it (in a file, database, or config) and pass it back as spk_emb any time you want that exact voice again.

Tip

To make speakers reproducible, fix the torch seed before sampling. The web UI uses this trick to map a numeric "Audio Seed" to a stable timbre:

import torch
torch.manual_seed(1111)
spk = chat.sample_random_speaker()

8.2 Zero-shot voice cloning from a reference clip

Provide a reference audio clip plus its transcript and ChatTTS will imitate that voice:

from tools.audio import load_audio

sample_audio = load_audio("reference.wav", 24000)
spk_smp = chat.sample_audio_speaker(sample_audio)

params = ChatTTS.Chat.InferCodeParams(
    spk_smp=spk_smp,
    txt_smp="the exact transcript of reference.wav",
)
params.spk_emb = None   # cloning and fixed-embedding are mutually exclusive
wavs = chat.infer(texts, params_infer_code=params)

Important

When you supply spk_smp (a cloned voice), set spk_emb=None. The two speaker mechanisms cannot be combined — providing a reference sample disables the speaker embedding.

Caution

Voice cloning quality varies. Community testing reports low speaker similarity in some zero-shot cases. Use a clean, single-speaker reference clip at 24 kHz for best results.


9. Performance and Acceleration

Lever How Effect
compile=True chat.load(compile=True) Compiles the model (CUDA only). Slower first run, faster steady-state inference.
vLLM backend chat.load(use_vllm=True) (Linux) Faster GPT-stage generation. Install vllm==0.2.7 first.
Batch sentences Pass a list to infer() Sentences are batched (max_split_batch=4) for throughput.
Lower max_new_token InferCodeParams(max_new_token=...) Caps clip length and generation time.
Streaming stream=True Reduces time-to-first-audio, not total compute.

Caution

The vLLM-accelerated path has known timbre quirks: community reports note it may bias toward male voices and slightly degrade audio quality compared to the default path. If voice fidelity matters more than speed, use the default (non-vLLM) backend.


10. Using ChatTTS Without Python Code

10.1 Command line (examples/cmd/run.py)

Run from the project root. Positional arguments are the sentences to speak; output is saved as output_audio_0.mp3, output_audio_1.mp3, …

python examples/cmd/run.py "Your text 1." "Your text 2."
Flag Default Description
--spk random A saved speaker-embedding string to fix the voice.
--stream off Generate in streaming mode.
--source local Model source: huggingface, local, or custom.
--custom_path "" Path to a custom model directory (with source custom).
texts — One or more sentences (positional, quote each one).
# Use a custom local model and Chinese input
python -m examples.cmd.run --source custom --custom_path ../../models/2Noise/ChatTTS "你好喲" ":)"

10.2 Web UI (examples/web/webui.py)

A Gradio app that opens in your browser with sliders for temperature, top_P, top_K, seeds, speaker embedding, streaming, and audio/text-seed dice buttons.

python examples/web/webui.py
Flag Default Description
--server_name 0.0.0.0 Host/interface to bind.
--server_port 8080 Port to serve on.
--root_path — Mount path if behind a reverse proxy.
--custom_path — Path to a custom model.
--coef — Custom DVAE coefficient string.
--disable_cache off Disable the model KV cache.
--experimental off Enable experimental accelerators.

The UI lets you type text, pick a timbre, paste a speaker embedding, upload a reference clip for cloning ("Sample Audio" tab), and toggle Stream Mode and Auto Play. The 🎲 buttons randomize the audio/text seeds; the Reload button reloads the model with a new DVAE coefficient.

Note

A valid speaker-embedding string in the UI must start with a specific prefix; if you paste an invalid one, the Generate button quietly produces no audio. Use the 🎲 (audio seed) button to generate a valid embedding.

10.3 HTTP API — native server (examples/api/main.py)

A FastAPI service that accepts a JSON body and returns a ZIP of MP3 files (one per input sentence).

# Start the server (loads the model from Hugging Face on startup)
fastapi run examples/api/main.py

Send a request with the bundled client or your own:

python examples/api/client.py
# The request body shape (examples/api/client.py)
body = {
    "text": ["四川美食确实以辣闻名,但也有不辣的选择。"],
    "stream": False,
    "lang": None,
    "skip_refine_text": True,
    "use_decoder": True,
    "do_text_normalization": True,
    "do_homophone_replacement": False,
    "params_refine_text": {"prompt": "", "top_P": 0.7, "top_K": 20, "temperature": 0.7},
    "params_infer_code": {"prompt": "[speed_5]", "top_P": 0.1, "temperature": 0.3, "spk_emb": None},
}

The endpoint is POST /generate_voice. The client reads the service location from environment variables:

Variable Default (client.py) Purpose
CHATTTS_SERVICE_HOST localhost Host of the API server.
CHATTTS_SERVICE_PORT 8000 Port of the API server.

A second command-line client, examples/api/postScript.py, exposes every inference parameter as a flag (--text, --audio_seed, --infer_temperature, --refine_top_P, …) for scripted batch generation.

10.4 HTTP API — OpenAI-compatible server (examples/api/openai_api.py)

A drop-in replacement for OpenAI's text-to-speech endpoint, so existing OpenAI TTS clients work against ChatTTS.

fastapi run examples/api/openai_api.py
Endpoint Method Purpose
/v1/audio/speech POST Synthesize speech (OpenAI TTS schema).
/health GET Health check; returns {"status": "healthy", "model_loaded": true}.

Request fields follow the OpenAI spec:

Field Default Notes
model tts-1 Forced to tts-1.
input (required) Text to synthesize, max 2048 characters.
voice default One of default, alloy, echo.
response_format mp3 mp3, wav, or ogg.
speed 1.0 Range 0.5–2.0.
stream False Stream the audio response.
curl http://localhost:8000/v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{"model":"tts-1","input":"Hello from ChatTTS","voice":"alloy","response_format":"mp3"}' \
  --output speech.mp3

Note

The three named voices (default, alloy, echo) load from speaker files (1528.pt, 1384.pt, 2443.pt). If a voice file is not present on disk, the server logs a warning and falls back to the default speaker. Download stable speaker files from the community ChatTTS Speaker spaces on ModelScope or Hugging Face.


11. Common Recipes

Reproducible voice + prosody

import torch, ChatTTS, torchaudio
chat = ChatTTS.Chat(); chat.load()

torch.manual_seed(1111)
spk = chat.sample_random_speaker()

wavs = chat.infer(
    "chat T T S is a text to speech model. [uv_break] it sounds natural [laugh].",
    skip_refine_text=True,
    params_infer_code=ChatTTS.Chat.InferCodeParams(spk_emb=spk, temperature=0.3, top_P=0.7, top_K=20),
)
torchaudio.save("repro.wav", torch.from_numpy(wavs[0]).unsqueeze(0), 24000)

Casual, expressive delivery (refine prompt)

wavs = chat.infer(
    "Let me tell you a quick story.",
    params_refine_text=ChatTTS.Chat.RefineTextParams(prompt="[oral_2][laugh_0][break_4]"),
)

English self-introduction (from the README)

inputs_en = (
    "chat T T S is a text to speech model designed for dialogue applications. "
    "[uv_break]it supports mixed language input [uv_break]and offers multi speaker "
    "capabilities with precise control over prosodic elements like "
    "[uv_break]laughter[uv_break][laugh], [uv_break]pauses, [uv_break]and intonation. "
    "[uv_break]it delivers natural and expressive speech,[uv_break]so please"
    "[uv_break] use the project responsibly at your own risk.[uv_break]"
)
wavs = chat.infer(inputs_en, params_refine_text=ChatTTS.Chat.RefineTextParams(prompt="[oral_2][laugh_0][break_4]"))
torchaudio.save("intro.wav", torch.from_numpy(wavs[0]), 24000)

12. Troubleshooting

Error: RuntimeError: narrow(): length must be non-negative.

Cause: The input text was empty, whitespace-only, or too short after normalization/refinement, so the model produced zero tokens. This is one of the most common community-reported errors (issues #955, #978). Solution: Ensure each sentence contains real, non-trivial text. Avoid passing empty strings in a list. If you used skip_refine_text=True, confirm your text still has speakable content after stripping tokens. Prevention: Filter out empty/short entries before calling infer(); keep ensure_non_empty=True (the default).

Error: AttributeError: BertTokenizer has no attribute encode_plus

Cause: A transformers version mismatch — the installed Transformers changed the tokenizer's method surface (issue #987). Solution: Match the required version: pip install "transformers>=4.41.1". ChatTTS already falls back from encode_plus to _encode_plus internally, so upgrading Transformers resolves it. Prevention: Install from requirements.txt rather than pinning Transformers yourself.

Error: lzma.LZMAError: Corrupt input data

Cause: A malformed or truncated speaker-embedding / DVAE-coefficient string was passed to spk_emb/coef (issue #800). These strings are LZMA-compressed and base16384-encoded; any corruption breaks decoding. Solution: Re-generate the speaker string with chat.sample_random_speaker() and copy it whole. Don't hand-edit it or truncate it. Prevention: Store speaker strings verbatim; the web UI validates that valid embeddings start with a fixed prefix.

Error: FileNotFoundError: File not found: <file>

Cause: A reference audio path passed to load_audio() / voice cloning does not exist (from tools/audio/av.py). Solution: Verify the path to your reference clip and that the file is a readable audio format. Prevention: Use absolute paths for reference clips.

Error: ValueError: Padding must be 'center' or 'same'.

Cause: An invalid padding value reached the mel-spectrogram feature extractor (from ChatTTS/model/dvae.py). Solution: Don't override internal feature-extractor config; use the shipped defaults.

Error: Unable to load model. (web UI) / Models load failed. (CLI)

Cause: The model assets failed to download or the integrity (SHA-256) check failed. Solution: Re-run with force_redownload=True (Python) or delete the asset/ directory and let it re-download. Check your network access to Hugging Face / the asset host. Prevention: Ensure enough free disk and a stable connection on first run.

No audio, no error (web UI Generate does nothing)

Cause: The Speaker Embedding field holds an invalid string (it must start with the expected prefix), or generation was interrupted. Solution: Click the 🎲 audio-seed button to regenerate a valid embedding, then Generate again.

Crash on Python 3.12 with CUDA 12.6 (no message)

Cause: An environment-specific incompatibility (issue #876). Solution: Use Python 3.10/3.11 in a clean conda env (conda create -n chattts python=3.11).

no ffmpeg installed, use wav file output

Cause: FFmpeg/ffprobe not on PATH, so MP3/OGG encoding is unavailable. Solution: Install FFmpeg, or accept WAV output. This is a warning, not a failure.

Generation runs but stops early: incomplete result. hit max_new_token

Cause: The clip reached the max_new_token cap before the model finished the sentence. Solution: Increase InferCodeParams(max_new_token=...) (default 2048) for longer text.

CPU synthesis is extremely slow

Cause: No GPU/NPU detected, so generation runs on CPU. Solution: Use a CUDA GPU with ≥4 GB VRAM. For CPU, keep sentences short and consider streaming with a pre-buffer.


13. FAQ

Q: How much VRAM do I need, and how fast is it? For a 30-second clip, at least 4 GB of GPU memory. On a 4090, ChatTTS produces about 7 semantic tokens/second with a Real-Time Factor around 0.3.

Q: Why does the voice sound different every time? Because infer() samples a random speaker by default. Generate one with sample_random_speaker() and reuse it via spk_emb for a consistent voice (see Section 8).

Q: Which languages are supported? English and Chinese, including mixed-language input in a single sentence. Language for normalization is auto-detected or set via lang="zh"/lang="en".

Q: Can I control emotions beyond laughter? In the current released model, the working token-level controls are [laugh], [uv_break], and [lbreak], plus the prompt-level [oral_N], [laugh_N], [break_N], and [speed_N]. Broader emotion control is on the roadmap for future model versions.

Q: The output is unstable — multiple speakers in one clip, or poor quality. Why? This is a known characteristic of autoregressive TTS models. Generate several samples and pick the best, or fix a speaker embedding and lower temperature toward 0.1.

Q: How do I get the same voice across sessions? Print and save the string from sample_random_speaker(), then pass it as spk_emb later. The string fully encodes the timbre.

Q: Do I need the normalization packages? Only if you want numbers/symbols spoken correctly. Without nemo_text_processing (English) or WeTextProcessing (Chinese), ChatTTS still works; it just skips normalization and warns you.

Q: Can I clone a specific person's voice? You can do zero-shot cloning from a reference clip via sample_audio_speaker() + spk_smp/txt_smp. Similarity varies; use a clean 24 kHz reference. Always have the right to use the voice you clone.

Q: Is ChatTTS free for commercial use? No. The code is AGPLv3+ and the model is CC BY-NC 4.0 — non-commercial, academic/research use only.

Q: Should I install FlashAttention-2 or TransformerEngine to go faster? No. FlashAttention-2 currently slows ChatTTS down, and TransformerEngine support is incomplete and cannot run properly. Use compile=True or vLLM instead.

Q: Where do I get higher-quality / additional voices? Community speaker collections are hosted on ModelScope and Hugging Face (the "ChatTTS_Speaker" spaces). Drop the .pt files where the OpenAI-compatible server expects them.

Q: Can I use ChatTTS as an OpenAI TTS drop-in? Yes — run examples/api/openai_api.py and point your OpenAI TTS client at /v1/audio/speech (see Section 10.4).