diff --git a/stacks/qwen3-tts/.env.example b/stacks/qwen3-tts/.env.example index f83b86a..62cc29b 100644 --- a/stacks/qwen3-tts/.env.example +++ b/stacks/qwen3-tts/.env.example @@ -6,8 +6,10 @@ QWEN3_TTS_SHA=10323ce778c48a75dbda93d0a4891983fb371f58 # Local image tag — bump when you change build context to force a -# fresh layer build. -QWEN3_TTS_TAG=v1 +# fresh layer build. v2 = first GPU build (target=production); v1 +# was the accidental CPU-only image (last stage of upstream's +# multi-stage Dockerfile). +QWEN3_TTS_TAG=v2 # ── network ────────────────────────────────────────────────────────── # Host port (container listens on 8880 internally). @@ -23,10 +25,14 @@ QWEN3_TTS_BIND=0.0.0.0 # more VRAM); `pytorch` = bare pytorch path. QWEN3_TTS_BACKEND=official -# Model variant. 1.7B = flagship, 6–8 GB VRAM with bfloat16, best -# quality + control. 0.6B = lightweight, ~2–3 GB VRAM, faster, slightly -# less expressive. -QWEN3_TTS_MODEL=Qwen/Qwen3-TTS-12Hz-1.7B +# Model variant. Upstream publishes four checkpoints on HF: +# Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice — flagship, voice cloning +# Qwen/Qwen3-TTS-12Hz-1.7B-Base — flagship, no cloning +# Qwen/Qwen3-TTS-12Hz-0.6B-CustomVoice — lightweight, voice cloning +# Qwen/Qwen3-TTS-12Hz-0.6B-Base — lightweight, no cloning +# 1.7B = ~6–8 GB VRAM bfloat16, best quality. 0.6B = ~2–3 GB. +# Use -CustomVoice for `voice="clone:"` to work. +QWEN3_TTS_MODEL=Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice # Warm the model on container start so the first synthesis request # doesn't pay the load latency. Adds ~30 s to startup. Recommended. diff --git a/stacks/qwen3-tts/compose.yaml b/stacks/qwen3-tts/compose.yaml index 1cd4592..ff02623 100644 --- a/stacks/qwen3-tts/compose.yaml +++ b/stacks/qwen3-tts/compose.yaml @@ -29,9 +29,22 @@ services: 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: