- Python 96.9%
- Shell 3.1%
| docs | ||
| servers | ||
| src/tts | ||
| .env.example | ||
| .gitignore | ||
| .python-version | ||
| LICENSE-apache.txt | ||
| pyproject.toml | ||
| README.md | ||
Chinese TTS
Chinese TTS scripts using Alibaba's Qwen and inclusionAI's Ming.
Upstream
Install
Dependencies:
sudo apt install sox
Install the package (editable) into the venv; this puts tts-remote-qwen3
on venv/bin/:
./venv/bin/pip install -e .
Local model backends are extras with mutually incompatible pinned dependency stacks, so each goes into its own venv:
python -m venv venv-qwen3 && venv-qwen3/bin/pip install -e '.[qwen3]' # tts-qwen3
python -m venv venv-ming3 && venv-ming3/bin/pip install -e '.[ming3]' # tts-ming3
python -m venv venv-voxcpm2 && venv-voxcpm2/bin/pip install -e '.[voxcpm2]' # tts-voxcpm2
python -m venv venv-auk && venv-auk/bin/pip install -e '.[auk]' # tts-auk
# tts-cosyvoice3 pins torch==2.3.1, which needs Python <= 3.12 (e.g. pyenv 3.10):
python3.10 -m venv venv-cosyvoice3 && venv-cosyvoice3/bin/pip install -e '.[cosyvoice3]' # tts-cosyvoice3
For CPU-only hosts, prefer PyTorch's CPU wheels to avoid downloading the CUDA stack:
venv-ming3/bin/pip install -e '.[ming3]' --extra-index-url https://download.pytorch.org/whl/cpu
For development (ruff):
./venv/bin/pip install -e '.[dev]'
Usage
tts-qwen3 "你好,世界。"
tts-qwen3 --slow --speaker Vivian "今天天气很好。"
tts-qwen3 --speaker Eric --instruct "用开心的语气说" "巴适得很。"
The first time it is run it will download a ~4 GB model from huggingface.
--speaker is free-form: besides the presets shown by
--list-speakers, any name the model/server supports is accepted.
--instruct passes an arbitrary style/emotion instruction to the
model (mutually exclusive with --slow).
Every clip is post-processed by default: leading silence is trimmed
(−42 dB relative to the clip's peak frame, 40 ms pad), the trailing
edge is trimmed at a much lower threshold (−60 dB, floored at −60 dBFS,
150 ms pad) with a raised-cosine fade-out so the final syllable's
natural decay is preserved and the clip ends smoothly at zero, and
loudness is normalized (−20 dBFS RMS target, −1 dBFS peak ceiling), so
a set of clips has uniform edges and loudness. Disable individually with
--no-trim / --no-normalize, or skip all post-processing with --raw
(writes the audio exactly as the model/server produced it).
Local: tts-ming3
tts-ming3 has the same CLI shape as tts-qwen3, but synthesizes locally
with inclusionAI's
Ming-3.0-tts-0.5b
(0.5B dense, 44.1 kHz output). It runs on CPU (slow but usable) as well as
CUDA; the first run downloads a ~3 GB model.
The upstream inference code is not pip-installable, so it is imported from
a git clone: $MING_TTS_REPO if set, otherwise a shallow clone under
~/.cache/chinese-tts/Ming-3.0-tts created automatically on first use.
Usage:
tts-ming3 "你好,世界。"
tts-ming3 --speaker DB30 "今天天气很好。"
tts-ming3 --speaker 灵小安 "内置音色直接报名字。"
tts-ming3 --instruct "用开心的语气说" "巴适得很。"
Differences from tts-qwen3:
--speakerselects one of the local cloning presets shown by--list-speakers(default:lingguang), or any built-in premium voice name (100+ Chinese voices such as灵小安; seecookbooks/instructions.mdin the Ming-3.0-tts clone).--instruct/--slowuse the model's FREEFORM task, which takes no reference voice, so they cannot be combined with--speaker.- Only
--temperature,--seedand--max-new-tokensaffect sampling; the remaining sampling flags are Qwen-only. - Text normalization (numbers, dates, symbols) requires
pynini, which is not in theming3extra (no universal wheel;conda install -c conda-forge pynini==2.1.6if wanted). Without it, normalization is disabled automatically with a warning;--no-text-normalizationsilences the warning.
Local: tts-voxcpm2
tts-voxcpm2 has the same CLI shape as tts-qwen3, but synthesizes locally
with OpenBMB's VoxCPM2 (2B,
tokenizer-free diffusion AR, 48 kHz output), installed from PyPI as the
voxcpm package. It runs on CPU (slow: minutes per clip) as well as CUDA;
the first run downloads a ~5 GB model.
Usage:
tts-voxcpm2 "你好,世界。"
tts-voxcpm2 --speaker myvoice.wav "今天天气很好。"
tts-voxcpm2 --instruct "用开心的语气说" "巴适得很。"
Differences from tts-qwen3:
- VoxCPM2 has no built-in voices — it always clones a reference clip.
--speakeraccepts a bundled preset name (--list-speakers:female(default),female-whisper,male-1,male-2; MIT-licensed AuK demo clips insrc/tts/data/, selected per docs/VOICES.txt) or a path to any reference WAV file. The presets are shared withtts-auk. --instruct/--slowprepend a parenthesized style description to the text (VoxCPM2's controllable-cloning syntax) and combine freely with--speaker.- Only
--seedand--max-new-tokensaffect generation; the remaining sampling flags are Qwen-only. Generation uses the upstream defaultscfg_value=2.0,inference_timesteps=10.
Local: tts-auk
tts-auk synthesizes locally with Tencent's
AuK (1.5B DiT + Qwen2.5-Omni-3B text
encoder, 24 kHz output) via zero-shot voice cloning. It runs on CPU (fp32;
minutes per clip) as well as CUDA. First run downloads ~14 GB of models
(AuK + the Qwen encoder).
The upstream inference code is not on PyPI, so it is imported from a git
clone: $AUK_REPO if set, otherwise a shallow clone under
~/.cache/chinese-tts/AuK created automatically on first use.
Usage:
tts-auk "你好,世界。"
tts-auk --speaker male-1 "今天天气很好。"
tts-auk --speaker myvoice.wav --ref-text "参考音频的逐字稿。" "文本。"
tts-auk --instruct "用开心的语气说" "巴适得很。"
Notes:
--speakeruses the shared bundled presets (--list-speakers) or any reference WAV. Output length is estimated from the reference transcript (known for presets; pass--ref-textfor custom clips) — without a transcript a fixed ~4.2 chars/second heuristic is used.--instruct/--slowadd a style clause to the cloning instruction and combine freely with--speaker.- Only
--seedaffects generation; the other sampling flags are Qwen-only. AuK is a diffusion model pinned to nfe=32 / cfg=2.0.
Local: tts-cosyvoice3
tts-cosyvoice3 synthesizes locally with FunAudioLLM's
Fun-CosyVoice3-0.5B-2512
(0.5B LLM + flow matching + HiFT, 24 kHz output) via zero-shot voice
cloning. It runs on CPU (RTF ~20 on 32 cores) as well as CUDA; the first
run downloads a ~6.4 GB model.
The upstream inference code is not pip-installable, so it is imported from
a git clone: $COSYVOICE_REPO if set, otherwise a shallow clone under
~/.cache/chinese-tts/CosyVoice (with the Matcha-TTS submodule) created
automatically on first use.
Usage:
tts-cosyvoice3 "你好,世界。"
tts-cosyvoice3 --speaker male-1 "今天天气很好。"
tts-cosyvoice3 --speaker myvoice.wav --ref-text "参考音频的逐字稿。" "文本。"
tts-cosyvoice3 --instruct "请用四川话表达" "巴适得很。"
Notes:
--speakeruses the shared bundled presets (--list-speakers) or any reference WAV. Without--ref-text, custom clips fall back to speaker-embedding-only cloning; presets carry known transcripts.--instruct/--slowuse CosyVoice3's instruct mode (dialects/emotion/speed, e.g. "请用广东话表达") and combine freely with--speaker.- Only
--seedaffects generation; the sampling flags are Qwen-only.
Remote: tts-remote-*
The tts-remote-* commands have the same CLI as their local counterparts,
plus a few remote-only options, but synthesize via a remote
OpenAI-compatible TTS server (POST /v1/audio/speech) — vllm-omni,
sglang-omni, or anything else speaking that API — instead of loading the
model locally.
One command per served model; each reads its own prefixed variables from
.env (see .env.example):
| command | served model | env prefix | voice |
|---|---|---|---|
tts-remote-qwen3 |
qwen3-tts | QWEN3_ |
named speakers |
tts-remote-qwen3-base |
qwen3-tts-base | QWEN3_BASE_ |
clones --speaker ref |
tts-remote-qwen3-voice-design |
qwen3-tts-voice-design | QWEN3_VOICE_DESIGN_ |
--instruct (required) |
tts-remote-cosyvoice3 |
cosyvoice3 | COSYVOICE3_ |
clones --speaker ref |
tts-remote-voxcpm2 |
voxcpm2 | VOXCPM2_ |
clones --speaker ref |
tts-remote-moss-tts-local |
moss-tts-local | MOSS_TTS_LOCAL_ |
clones --speaker ref |
tts-remote-moss-voice-generator |
moss-voice-generator | MOSS_VOICE_GENERATOR_ |
--instruct (required) |
tts-remote-auk |
auk | AUK_ |
clones --speaker ref |
tts-remote-auk-flash |
auk-flash | AUK_FLASH_ |
clones --speaker ref |
# Full base URL (required for https:// servers); wins if set:
QWEN3_BASE_URL=https://tts.example.com
# or plain host/port (http:// assumed):
QWEN3_HOST=192.168.1.100
QWEN3_PORT=44001
QWEN3_MODEL=qwen3-tts
COSYVOICE3_HOST=192.168.1.100
COSYVOICE3_PORT=44002
COSYVOICE3_MODEL=cosyvoice3
Connection failures are retried with exponential backoff (3 attempts).
Sampling defaults are greedy (temperature=0.0 for both the talker and
the subtalker/codebook tower) and pinned client-side, because the server
does not reliably apply the checkpoint's own defaults. Sampled decoding
(the model's official temperature=0.9) stochastically produces
shouting, extreme slowness, or sustained-vowel tails on some inputs,
and the server's --seed does not give reproducible audio. For
expressive sampling, set both temperatures, e.g.
--temperature 0.9 --subtalker-temperature 0.9.
Notes:
- Feed the model hanzi, not pinyin (
贾宝玉, notJiǎ Bǎoyù). --seedis accepted but the server does not produce bit-identical audio from it.
Usage:
tts-remote-qwen3 "你好,世界。"
tts-remote-qwen3 --slow --speaker Vivian "今天天气很好。"
tts-remote-qwen3 --instruct "用开心的语气说" "今天天气很好。"
tts-remote-qwen3 --stream --text-file story.txt -o story.wav
tts-remote-qwen3 --response-format mp3 --sample-rate 8000 -o story.mp3 --text-file story.txt
tts-remote-voxcpm2 "你好,世界。"
tts-remote-voxcpm2 --instruct "用开心的语气说" "今天天气很好。"
tts-remote-voxcpm2 --stream --text-file story.txt -o story.wav
tts-remote-cosyvoice3 --speaker male-1 "今天天气很好。"
tts-remote-qwen3-base --speaker myvoice.wav --ref-text "参考音频的逐字稿。" "文本。"
tts-remote-qwen3-voice-design --instruct "一位声音低沉的成年男性。" "你好,世界。"
tts-remote-moss-voice-generator --instruct "活泼的年轻女声。" "你好,世界。"
tts-remote-auk "你好,世界。"
Voice backends:
- Named speakers (
tts-remote-qwen3):--speakerpicks a built-in voice (--list-speakers). - Cloning (
tts-remote-qwen3-base,-cosyvoice3,-voxcpm2,-moss-tts-local,-auk,-auk-flash):--speakerdefaults to a bundled preset clip sent per-request as base64ref_audio(presets carry known transcripts), or a path to any reference WAV — add--ref-textwith its transcript for in-context cloning. - Voice design (
tts-remote-qwen3-voice-design,tts-remote-moss-voice-generator): no--speaker;--instructis required and describes the voice to design, e.g.--instruct "一位声音低沉的成年男性,语速缓慢。". tts-remote-auk*also send aduration_secondsestimate with every request — without it the server generates to a generous default length (~13 s for a one-second text).
Remote-only options:
--response-format {wav,mp3,flac,pcm,opus}— mp3/flac give smaller files.--sample-rate {8000,24000}— 8000 Hz for smaller files. (tts-remote-qwen3* only; the other servers are fixed at their native rates and reject sample_rate, so those CLIs do not offer the flag.)--stream— streams audio from the server (lower time-to-first-audio on long texts); the output file is always WAV.
tts-remote-voxcpm2 notes:
- Voice handling differs from
tts-remote-qwen3. With no reference the server invents a voice from the text, so the timbre changes with every input. To keep one voice across runs,--speakerdefaults to cloning a bundled preset clip (female; see--list-speakers), sent per-request as base64ref_audio; preset clips carry known transcripts, which the server uses for in-context cloning (ref_text). --speakeralso accepts a path to any reference WAV (add--ref-textwith its transcript for higher-quality in-context cloning), the name of an uploaded/precomputed voice on the server (GET /v1/audio/voices, upload viaPOST /v1/audio/voices), orserver-defaultfor the context-inferred voice.- The remaining sampling flags (
--temperature,--top-k, ...) are Qwen-only and are not sent to the VoxCPM2 server.
Help
$ tts-qwen3 --help
usage: tts-qwen3 [-h] [--version] [--text-file PATH] [-o PATH]
[--speaker NAME] [--list-speakers] [--slow | --instruct TEXT]
[--no-trim] [--no-normalize] [--seed SEED]
[--temperature TEMPERATURE] [--top-k TOP_K] [--top-p TOP_P]
[--repetition-penalty REPETITION_PENALTY]
[--subtalker-temperature SUBTALKER_TEMPERATURE]
[--subtalker-top-k SUBTALKER_TOP_K]
[--subtalker-top-p SUBTALKER_TOP_P]
[--max-new-tokens MAX_NEW_TOKENS]
[text]
Synthesize Standard Mandarin Chinese speech with Qwen3-TTS.
positional arguments:
text Chinese text to synthesize (final positional argument).
options:
-h, --help show this help message and exit
--version show program's version number and exit
--text-file PATH Read text to synthesize from a file instead of the positional argument.
-o, --output PATH Output filename. Defaults to an auto-incrementing output-NNN.wav.
--speaker NAME Speaker voice (default: Dylan). Free-form: any name the model/server supports is accepted; --list-speakers shows the standard Chinese presets.
--list-speakers List the standard Chinese speaker presets and exit.
--slow Speak slowly.
--instruct TEXT Style/emotion instruction for the model, e.g. "用开心的语气说". Cannot be combined with --slow.
--no-trim Do not trim leading/trailing silence (trimming is on by default).
--no-normalize Do not loudness-normalize the clip (on by default).
--seed SEED Random seed for reproducible sampling (optional).
--temperature TEMPERATURE
Talker sampling temperature (default: 0.0 = greedy; the model's recommended sampling value is 0.9).
--top-k TOP_K Top-k sampling (default: 50; applies when --temperature > 0).
--top-p TOP_P Top-p sampling (default: 1.0; applies when --temperature > 0).
--repetition-penalty REPETITION_PENALTY
Repetition penalty (default: 1.05).
--subtalker-temperature SUBTALKER_TEMPERATURE
Subtalker (codebook tower) sampling temperature (default: 0.0 = greedy; recommended sampling value is 0.9).
--subtalker-top-k SUBTALKER_TOP_K
Subtalker top-k (default: 50; applies when --subtalker-temperature > 0).
--subtalker-top-p SUBTALKER_TOP_P
Subtalker top-p (default: 1.0; applies when --subtalker-temperature > 0).
--max-new-tokens MAX_NEW_TOKENS
Maximum number of new tokens to generate (optional).
examples:
tts-qwen3 "你好,世界。"
tts-qwen3 --slow --speaker Vivian "今天天气很好。"
tts-qwen3 --speaker Eric --instruct "用开心的语气说" "巴适得很。"
tts-qwen3 --text-file story.txt -o story.wav
tts-qwen3 --list-speakers
License
Apache 2.0 License. See LICENSE-apache.txt for details.
Copyright © 2026 Jeff Moe