# Deploy Qwen3-TTS to irv-ml1. # # Builds the image locally from groxaxo/Qwen3-TTS-Openai-Fastapi via # docker buildx's git URL context (no source vendored on the host), # stages compose + .env under /opt/docker/compose/qwen3-tts/, brings # up, waits for /health, and verifies the web surface + MCP-irrelevant # REST endpoints answer. # # First run is slow: ~3-5 min for the docker build (CUDA torch + # transformers wheels) plus ~3-5 min for the 1.7B model download # from HF on first inference / warmup. The healthz wait below has # a generous deadline. # # Usage: # scripts/elway irv-ml1 --playbook playbooks/deploy-qwen3-tts.yaml # # Idempotent — every step is creates-/when-gated; rerun is safe. vars: compose_dir: /opt/docker/compose/qwen3-tts cache_dir: /worktank/qwen3-tts/cache voices_dir: /worktank/qwen3-tts/voices host_port: "8191" steps: # ── host-side dirs ────────────────────────────────────────────────── - name: Ensure /worktank/qwen3-tts root exists (one-time, sudo) shell: mkdir -p /worktank/qwen3-tts sudo: true creates: /worktank/qwen3-tts - name: Chown /worktank/qwen3-tts to lkraven shell: chown lkraven:lkraven /worktank/qwen3-tts sudo: true when: '[ "$(stat -c %U /worktank/qwen3-tts)" != lkraven ]' - name: Ensure cache dir exists shell: mkdir -p {{ cache_dir }} creates: "{{ cache_dir }}" - name: Ensure voices dir exists shell: mkdir -p {{ voices_dir }} creates: "{{ voices_dir }}" - name: Ensure compose dir exists shell: mkdir -p {{ compose_dir }} creates: "{{ compose_dir }}" # ── deploy compose files ──────────────────────────────────────────── - name: Upload compose.yaml upload: src: stacks/qwen3-tts/compose.yaml dest: "{{ compose_dir }}/compose.yaml" mode: "0644" - name: Seed .env from template (only if absent) upload: src: stacks/qwen3-tts/.env.example dest: "{{ compose_dir }}/.env" mode: "0644" when: "[ ! -f {{ compose_dir }}/.env ]" # ── build + bring up ──────────────────────────────────────────────── - name: docker compose build (~3-5 min first time; cached after) shell: cd {{ compose_dir }} && docker compose build - name: docker compose up -d shell: cd {{ compose_dir }} && docker compose up -d - name: Wait for /health to respond # 1.7B model download on first boot can take a few minutes; allow # up to ~10 minutes for the wait, polling every 5s. shell: | for i in $(seq 1 120); do curl -sf -o /dev/null --max-time 3 http://localhost:{{ host_port }}/health && exit 0 sleep 5 done exit 1 changed_when: "false" verify: - name: /health returns 200 shell: curl -sf -o /dev/null http://localhost:{{ host_port }}/health changed_when: "false" - name: /v1/models lists at least one model shell: curl -sf http://localhost:{{ host_port }}/v1/models | grep -q '"data"\|Qwen3-TTS\|model' changed_when: "false" - name: /v1/voices endpoint reachable shell: curl -sf -o /dev/null http://localhost:{{ host_port }}/v1/voices changed_when: "false" - name: Web UI root serves HTML shell: '[ "$(curl -s -o /dev/null -w %{http_code} http://localhost:{{ host_port }}/)" -eq 200 ]' changed_when: "false" - name: Container running + healthy or starting shell: docker inspect qwen3-tts --format '{{.State.Status}}' | grep -q running changed_when: "false"