Files
esh-pfi-infrastructure/stacks/qwen3-tts/compose.yaml
T
vh 5fd69f06b1 qwen3-tts: wire optimized backend to /app/config.yaml so model registry actually loads
The wrapper's `optimized` backend (torch.compile + CUDA graphs +
real-time streaming) reads its model registry from a YAML config:
default path is ~/qwen3-tts/config.yaml inside the container, which
doesn't exist. Without TTS_CONFIG set, the backend boots with an
empty registry and every synthesis request fails with
"Unknown model key: '<name>'. Available: []".

The repo ships /app/config.yaml with all 4 model variants defined.
Pointing TTS_CONFIG at it lets the optimized backend load cleanly.

This is a prerequisite for benching the optimized backend properly
— it's the path to the upstream's claimed 97 ms streaming TTFB. The
default `official` backend uses naive HF transformers autoregressive
generation that pegged GPU at only 27% utilization and gave us 8-12 s
TTFB on bench (no recompile theory needed — same phrase repeated 4x
plateaued at 8.5 s, ruling out shape-specific recompilation).
2026-04-27 22:07:03 -07:00

84 lines
3.7 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Qwen3-TTS — Alibaba's open-weight TTS, deployed via the
# groxaxo/Qwen3-TTS-Openai-Fastapi wrapper.
#
# Why this stack exists alongside cosyvoice: CosyVoice 3 emits
# Chinese phonemes for non-Chinese inputs (upstream issue
# FunAudioLLM/CosyVoice#1790, no fix). Qwen3-TTS is from the same
# Alibaba team but with English first-class — 10 languages, 97 ms
# streaming TTFB, voice cloning, instruction-driven emotional
# expression. Released Jan 2026, Apache 2.0.
#
# Build: no prebuilt image; pinned to a SHA via docker buildx's git
# context URL so subsequent rebuilds are reproducible. ~510 min on
# first build (CUDA torch + transformers).
#
# Model: 1.7B flagship (~68 GB VRAM with bfloat16) by default; the
# host has plenty of VRAM. Switch to the 0.6B in .env if you ever
# need more headroom.
#
# Voice cloning shape DIFFERS from cosyvoice: profile-based, not
# voice-id. Profiles live under voice_library/profiles/<name>/ with
# meta.json + reference.wav, and are referenced as
# `voice="clone:<name>"` in /v1/audio/speech requests.
#
# All tunables live in .env — edit that, not this file.
services:
qwen3-tts:
image: local/qwen3-tts:${QWEN3_TTS_TAG}
build:
context: https://github.com/groxaxo/Qwen3-TTS-Openai-Fastapi.git#${QWEN3_TTS_SHA}
dockerfile: Dockerfile
# Upstream Dockerfile defines five stages — without an explicit
# target, buildkit picks the LAST named stage (`cpu-base`) and
# produces a CPU-only image with no GPU torch + onnxruntime
# (not -gpu). Pin to `production` to get the CUDA stack with
# flash-attn that the model actually needs.
target: production
container_name: qwen3-tts
restart: unless-stopped
runtime: nvidia
# Upstream image declares `USER appuser` (uid 1000) but writes
# state under /root (mode 0700) — appuser can't traverse it, so
# /v1/voices and any FS-touching endpoint 500s. The model loads
# only because warmup happens in an early root phase. Pin to root
# so all paths are reachable. Files written into the host bind
# mounts become root-owned; that's fine for restic + sudo reads.
user: "0:0"
ports:
- "${QWEN3_TTS_BIND:-0.0.0.0}:${QWEN3_TTS_PORT}:8880"
environment:
- NVIDIA_VISIBLE_DEVICES=all
- PORT=8880
- TTS_BACKEND=${QWEN3_TTS_BACKEND:-official}
- TTS_MODEL_NAME=${QWEN3_TTS_MODEL:-Qwen/Qwen3-TTS-12Hz-1.7B}
# Only used when TTS_BACKEND=optimized — points the optimized backend
# at the upstream config.yaml (which defines the model registry +
# default model). Without this, the optimized backend looks at
# ~/qwen3-tts/config.yaml inside the container, which doesn't exist
# at runtime, leaving the model registry empty and synthesis fails
# with "Unknown model key".
- TTS_CONFIG=/app/config.yaml
- TTS_WARMUP_ON_START=${QWEN3_TTS_WARMUP:-true}
- TTS_MAX_CONCURRENT=${QWEN3_TTS_MAX_CONCURRENT:-1}
- ENABLE_VOICE_STUDIO=${QWEN3_TTS_VOICE_STUDIO:-true}
- VOICE_LIBRARY_DIR=/root/qwen3-tts/voice_library
- HF_HOME=/root/.cache/huggingface
volumes:
- ${QWEN3_TTS_CACHE_DIR}:/root/.cache/huggingface
- ${QWEN3_TTS_VOICES_DIR}:/root/qwen3-tts/voice_library
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8880/health >/dev/null || exit 1"]
interval: 30s
timeout: 10s
retries: 3
# First boot pulls torch + Qwen3-TTS-12Hz-1.7B (~6 GB) and
# optionally warms the model — give it a generous budget.
start_period: 600s
labels:
- homepage.group=AI Systems
- homepage.name=Qwen3-TTS
- homepage.icon=mdi-account-voice
- homepage.description=Multilingual TTS with English-first emotion (irv-ml1)
- homepage.href=http://10.100.79.3:${QWEN3_TTS_PORT}