7.3 KiB
Qwen3-TTS OpenAI-like API
A FastAPI-based OpenAI-compatible API for Qwen3 Text-to-Speech with streaming support and voice cloning capabilities.
Features
- 🎵 Real-time Streaming - Stream audio chunks as they're generated
- 🎭 Voice Cloning - Clone voices using reference audio
- 🌍 Multi-language Support - English, Russian, Chinese, Japanese, Korean, and more
- 📡 OpenAI-like API - Familiar API structure for easy integration
- 🚀 High Performance - Optimized streaming with CUDA support
- 📚 Interactive Docs - Swagger UI at
/docs
Installation
Prerequisites
- Python >= 3.9
- CUDA 11.8+ (for GPU support) or CPU mode
- 8GB+ VRAM recommended for GPU
Setup
-
Install dependencies
pip install fastapi uvicorn gradio requests soundfile librosa numpy torch transformers -
Install Qwen3-TTS package
pip install -e .
Quick Start
Starting the API Server
# Run the API server
python -m api.main
# Or with uvicorn directly
uvicorn api.main:app --host 0.0.0.0 --port 8000
The API will be available at http://localhost:8000
Running the Gradio Demo
In a separate terminal:
python -m api.gradio_demo
The demo will be available at http://localhost:7860
API Endpoints
Health Check
GET /v1/health
Check API status and model readiness.
Response:
{
"status": "healthy",
"model": "Qwen/Qwen3-TTS-12Hz-1.7B-Base",
"device": "cuda",
"ready": true
}
List Models
GET /v1/models
Get available TTS models.
Response:
{
"object": "list",
"data": [
{
"id": "Qwen/Qwen3-TTS-12Hz-1.7B-Base",
"object": "model",
"owned_by": "Alibaba",
"supported_languages": ["English", "Russian", "Chinese", "Japanese", "Korean"],
"supports_streaming": true,
"supports_voice_clone": true
}
]
}
Text-to-Speech (Standard)
POST /v1/audio/speech
Generate audio from text.
Request:
{
"text": "Hello, how are you?",
"language": "English",
"model": "Qwen/Qwen3-TTS-12Hz-1.7B-Base",
"voice_clone_mode": "disabled",
"speed": 1.0,
"pitch": 1.0
}
Response:
{
"id": "req_abc123def456",
"object": "audio",
"created": 1708284000,
"model": "Qwen/Qwen3-TTS-12Hz-1.7B-Base",
"audio_base64": "UklGRi...",
"duration": 2.5,
"sample_rate": 24000,
"language": "English"
}
Text-to-Speech (Streaming)
POST /v1/audio/speech/stream
Stream audio chunks as they're generated.
Request:
{
"text": "Hello, this is a streaming test.",
"language": "English",
"voice_clone_mode": "disabled",
"stream_options": {
"emit_every_frames": 8,
"decode_window_frames": 80,
"overlap_samples": 512
}
}
Response:
- Binary stream of WAV frame chunks
- Each chunk is prefixed with a 4-byte length (big-endian)
- Format:
[length (4 bytes)][WAV frame data]...
Voice Cloning
Setup
Voice cloning requires two files in assets/voice_cloning/:
-
ref_audio.wav- Reference audio file- Format: WAV
- Duration: 5-30 seconds
- Clear, natural speech
-
ref_text.txt- Transcription of reference audio- Plain text UTF-8
- Must exactly match the audio content
Using Voice Cloning
# 1. Place reference files
cp your_reference.wav assets/voice_cloning/ref_audio.wav
echo "Reference text here..." > assets/voice_cloning/ref_text.txt
# 2. Start the API (it will load voice cloning automatically)
python -m api.main
# 3. Use voice cloning in requests
curl -X POST "http://localhost:8000/v1/audio/speech" \
-H "Content-Type: application/json" \
-d '{
"text": "New text to synthesize",
"language": "English",
"voice_clone_mode": "reference_audio"
}'
Python Integration
Using the API from Python
import requests
import base64
from io import BytesIO
import soundfile as sf
# Generate speech
response = requests.post(
"http://localhost:8000/v1/audio/speech",
json={
"text": "Hello, world!",
"language": "English",
"voice_clone_mode": "disabled"
}
)
data = response.json()
audio_bytes = base64.b64decode(data["audio_base64"])
audio, sr = sf.read(BytesIO(audio_bytes))
# Save to file
sf.write("output.wav", audio, sr)
Streaming Example
import requests
response = requests.post(
"http://localhost:8000/v1/audio/speech/stream",
json={
"text": "This is a streaming test.",
"language": "English",
},
stream=True
)
chunks = []
for chunk in response.iter_content(chunk_size=65536):
# Parse frame length (4 bytes)
frame_len = int.from_bytes(chunk[:4], byteorder='big')
# Extract WAV frame data
frame_data = chunk[4:4 + frame_len]
chunks.append(frame_data)
Configuration
Model Selection
Currently supports:
Qwen/Qwen3-TTS-12Hz-1.7B-Base(default)
More models can be added to TTSModel enum in api/models.py.
Device Selection
The API automatically selects the best available device:
- CUDA GPU (if available and with sufficient VRAM)
- CPU (fallback)
To force a specific device, modify api/main.py:
# In ModelState.__init__
self.device = "cpu" # Force CPU mode
Streaming Options
Adjust streaming performance in api/models.py:
class StreamOptions(BaseModel):
emit_every_frames: int = 8 # Lower = more chunks, lower latency
decode_window_frames: int = 80 # Higher = better quality, higher latency
overlap_samples: int = 512 # Overlap for smooth transitions
Performance Tips
-
GPU Optimization
- Use CUDA 11.8+ for better performance
flash_attention_2is automatically enabled when available
-
Streaming Optimization
- Lower
emit_every_framesfor faster first chunk - Increase
decode_window_framesfor better audio quality
- Lower
-
Production Deployment
- Use a production ASGI server like Gunicorn or Hypercorn
- Enable response caching for identical requests
- Monitor GPU memory usage
Troubleshooting
API won't start
error: No module named 'transformers'
→ pip install transformers accelerate
Model loading fails
error: CUDA out of memory
→ Use CPU mode: modify device to "cpu" in api/main.py
→ Or reduce batch size
Voice cloning not working
- Verify
ref_audio.wavandref_text.txtexist inassets/voice_cloning/ - Check file permissions
- Ensure reference text matches audio content exactly
Slow responses
- Check GPU/CPU utilization
- Reduce
decode_window_framesfor faster (but lower quality) generation - Ensure sufficient system memory available
API Documentation
Once the server is running, visit:
- Interactive Docs (Swagger UI):
http://localhost:8000/docs - ReDoc Documentation:
http://localhost:8000/redoc
Examples
See the examples/ directory for more usage examples:
test_streaming.py- Streaming generation exampletest_model_12hz_base.py- Base model usagetest_model_12hz_custom_voice.py- Voice cloning example
License
This API is licensed under the Apache 2.0 License. See LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit pull requests.
Support
For issues, questions, or suggestions:
- Check the troubleshooting section
- Review the API documentation at
/docs - Check logs for detailed error messages