REST API for Qwen3-TTS speech synthesis.
Supports all three generation modes: Custom Voice, Voice Design, and Voice Clone.
| Method | Path | Description |
|---|---|---|
| GET | /health |
Server health check |
| GET | /speakers |
List available preset speakers |
| GET | /languages |
List supported languages |
Uses preset speakers (ryan, vivian, aiden, etc.) with optional emotion instructions.
| Method | Path | Description |
|---|---|---|
| POST | /v1/custom-voice/generate |
Returns JSON with base64 audio |
| POST | /v1/custom-voice/generate/wav |
Returns WAV file |
| POST | /v1/custom-voice/generate/batch |
Batch generation (multiple segments) |
| POST | /v1/custom-voice/generate/stream |
SSE stream (segments sent as they complete) |
Creates voices from natural language descriptions.
| Method | Path | Description |
|---|---|---|
| POST | /v1/voice-design/generate |
Returns JSON with base64 audio |
| POST | /v1/voice-design/generate/wav |
Returns WAV file |
| POST | /v1/voice-design/generate/batch |
Batch generation |
| POST | /v1/voice-design/generate/stream |
SSE stream |
Clones a voice from uploaded reference audio.
| Method | Path | Description |
|---|---|---|
| POST | /v1/voice-clone/ref-audio |
Upload reference audio (multipart) |
| GET | /v1/voice-clone/ref-audio |
List uploaded reference audios |
| DELETE | /v1/voice-clone/ref-audio/{id} |
Delete a reference audio |
| POST | /v1/voice-clone/generate |
Returns JSON with base64 audio |
| POST | /v1/voice-clone/generate/wav |
Returns WAV file |
| POST | /v1/voice-clone/generate/batch |
Batch generation (same ref audio) |
| POST | /v1/voice-clone/generate/stream |
SSE stream (same ref audio) |
Design a custom voice from a text description, then use it for generation. Automatically loads both VoiceDesign and Base models. The created voice is saved as a reference audio and can be reused with /v1/voice-clone/* endpoints.
| Method | Path | Description |
|---|---|---|
| POST | /v1/voice-design-clone/create-voice |
Design + save voice, returns ref_audio_id |
| POST | /v1/voice-design-clone/generate |
Design + generate in one call |
| POST | /v1/voice-design-clone/generate/wav |
Design + generate, returns WAV |
| POST | /v1/voice-design-clone/generate/batch |
Design + batch generate |
| POST | /v1/voice-design-clone/generate/stream |
Design + SSE stream |
Encode audio to compact codes (~200x smaller) and decode back. Useful for storage, transport, and fine-tuning data preparation.
| Method | Path | Description |
|---|---|---|
| GET | /v1/tokenizer/info |
Tokenizer model info (sample rates, etc.) |
| POST | /v1/tokenizer/encode |
Encode audio file to codes (multipart) |
| POST | /v1/tokenizer/decode |
Decode codes to audio (JSON response) |
| POST | /v1/tokenizer/decode/wav |
Decode codes to audio (WAV file) |
bash setup.sh
source /workspace/venv/bin/activate
python -m src.maindocker build -t qwen-tts-api .
docker run --gpus all -p 8000:8000 qwen-tts-apiEnvironment variables:
| Variable | Default | Description |
|---|---|---|
MODEL_NAME |
Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice |
HuggingFace model ID |
DEVICE |
cuda:0 |
PyTorch device |
HOST |
0.0.0.0 |
Server bind address |
PORT |
8000 |
Server port |
REF_AUDIO_DIR |
/tmp/qwen-tts-ref-audio |
Storage for uploaded reference audios |
| Model | Use case |
|---|---|
Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice |
Preset speakers + emotion control |
Qwen/Qwen3-TTS-12Hz-1.7B-VoiceDesign |
Voice creation from text descriptions |
Qwen/Qwen3-TTS-12Hz-1.7B-Base |
Voice cloning from reference audio |
Qwen/Qwen3-TTS-12Hz-0.6B-CustomVoice |
Smaller/faster preset speakers |
Qwen/Qwen3-TTS-12Hz-0.6B-Base |
Smaller/faster voice cloning |
Note: Each model supports different endpoints. CustomVoice models work with
/v1/custom-voice/*, VoiceDesign with/v1/voice-design/*, and Base models with/v1/voice-clone/*. Loading a model that doesn't support an endpoint will return a 500 error.
# JSON response with base64 audio
curl -X POST http://localhost:8000/v1/custom-voice/generate \
-H "Content-Type: application/json" \
-d '{"text": "Hello world!", "speaker": "ryan", "language": "english"}'
# WAV file
curl -X POST http://localhost:8000/v1/custom-voice/generate/wav \
-H "Content-Type: application/json" \
-d '{"text": "Hello!", "speaker": "ryan", "instruct": "Excited and happy"}' \
-o output.wav
# Batch
curl -X POST http://localhost:8000/v1/custom-voice/generate/batch \
-H "Content-Type: application/json" \
-d '{
"segments": [
{"text": "First line.", "speaker": "ryan", "language": "english", "instruct": ""},
{"text": "Second line.", "speaker": "vivian", "language": "english", "instruct": ""}
]
}'# 1. Upload reference audio
curl -X POST http://localhost:8000/v1/voice-clone/ref-audio \
-F "file=@reference.wav" \
-F "ref_text=This is the transcript of my reference audio."
# Response: {"id": "a1b2c3d4e5f6", "ref_text": "...", "duration_seconds": 8.5}
# 2. Generate with cloned voice
curl -X POST http://localhost:8000/v1/voice-clone/generate/wav \
-H "Content-Type: application/json" \
-d '{"text": "New text in cloned voice.", "language": "english", "ref_audio_id": "a1b2c3d4e5f6"}' \
-o output.wav# 1. Create a reusable custom voice
curl -X POST http://localhost:8000/v1/voice-design-clone/create-voice \
-H "Content-Type: application/json" \
-d '{
"sample_text": "Hello, this is a sample of my designed voice.",
"language": "english",
"instruct": "Male, 35 years old, warm baritone, calm podcast narrator."
}'
# Response: {"ref_audio_id": "abc123", "ref_audio_base64": "...", ...}
# The ref_audio_id can now be used with /v1/voice-clone/* endpoints.
# 2. Or design + generate in one shot
curl -X POST http://localhost:8000/v1/voice-design-clone/generate/wav \
-H "Content-Type: application/json" \
-d '{
"sample_text": "A short sample for the voice design.",
"instruct": "Female, 28 years old, energetic, bright voice.",
"text": "This is the actual text I want spoken in the designed voice.",
"language": "english"
}' \
-o output.wav# Encode audio to compact codes
curl -X POST http://localhost:8000/v1/tokenizer/encode \
-F "file=@audio.wav"
# Response: {"audio_codes": [[1995, 1159, ...], ...], "num_codebooks": 16, "num_frames": 120, ...}
# Decode codes back to audio
curl -X POST http://localhost:8000/v1/tokenizer/decode/wav \
-H "Content-Type: application/json" \
-d '{"audio_codes": [[1995, 1159, 355, ...], [1028, 862, ...]]}' \
-o decoded.wavStream segment results as they are generated via Server-Sent Events. Each segment is sent as soon as it completes, instead of waiting for all segments.
curl -N -X POST http://localhost:8000/v1/custom-voice/generate/stream \
-H "Content-Type: application/json" \
-d '{
"segments": [
{"text": "First segment.", "speaker": "ryan", "language": "english", "instruct": ""},
{"text": "Second segment.", "speaker": "vivian", "language": "english", "instruct": ""}
]
}'Response (SSE stream):
event: segment
data: {"event":"segment","index":0,"audio_base64":"UklGR...","sample_rate":24000,"duration_seconds":2.5,"generation_time_seconds":6.1}
event: segment
data: {"event":"segment","index":1,"audio_base64":"UklGR...","sample_rate":24000,"duration_seconds":3.1,"generation_time_seconds":5.8}
event: done
data: {"event":"done","total_segments":2,"total_duration_seconds":5.6,"total_generation_time_seconds":11.9}
All generation endpoints accept optional params for fine-tuning:
{
"text": "Hello!",
"speaker": "ryan",
"params": {
"max_new_tokens": 2048,
"temperature": 0.8,
"top_p": 0.95,
"top_k": 50,
"repetition_penalty": 1.1,
"non_streaming_mode": false
}
}Run the full test suite against a running server (requires Node.js/Bun):
cd e2e
npx tsx test-all.ts --host http://localhost:8000Tests all 28 endpoints: custom-voice, voice-design-clone, voice-clone, tokenizer, and error handling. Generated audio files are saved to e2e-output/.
Interactive Swagger docs available at http://localhost:8000/docs when the server is running.