# CosyVoice — multilingual expressive TTS with voice cloning.
#
# Ships the Fun-CosyVoice3-0.5B-2512 model from FunAudioLLM (latest
# as of 2026-04). Streaming PCM chunks with ~150 ms TTFB. Emotional
# control via either XML tags (<angry>text</angry>) or instruction
# prompts (`You are a helpful assistant. <|endofprompt|>` syntax).
#
# Runs on irv-ml1 (dual GPU). Both GPUs exposed via
# NVIDIA_VISIBLE_DEVICES=all; image reads CUDA_VISIBLE_DEVICES if
# you later want to pin.
#
# Path split:
#   /worktank/cosyvoice/voices  → /data/voices   cloned speaker profiles
#   /worktank/cosyvoice/input   → /data/input    scratch for uploaded source audio
#   /worktank/cosyvoice/output  → /data/output   synthesized clips
#
# Models (~2–3 GB) download on first run into the image's internal
# pretrained_models/ path. Not bind-mounted (the image expects an
# exact layout we don't have authoritative docs for); recreating the
# container without the cached image will re-download. Cached image
# layer persists through `compose up -d` recreates.
#
# API routes (OpenAI-compatible where marked):
#   POST /v1/audio/speech         — OpenAI drop-in for TTS
#   POST /v1/voices/create        — voice cloning (reference audio in)
#   GET  /v1/voices               — list cloned voices
#   GET  /health                  — health probe
#
# All tunables live in .env — edit that, not this file.

services:
  cosyvoice:
    image: neosun/cosyvoice:${COSYVOICE_VERSION}
    container_name: cosyvoice
    restart: unless-stopped
    runtime: nvidia
    ports:
      - "${COSYVOICE_BIND:-0.0.0.0}:${COSYVOICE_PORT}:8188"
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - MODEL_DIR=${COSYVOICE_MODEL_DIR:-pretrained_models/Fun-CosyVoice3-0.5B}
      - PORT=8188
      - GPU_IDLE_TIMEOUT=${COSYVOICE_GPU_IDLE_TIMEOUT:-600}
    volumes:
      - ${COSYVOICE_VOICES_DIR}:/data/voices
      - ${COSYVOICE_INPUT_DIR}:/data/input
      - ${COSYVOICE_OUTPUT_DIR}:/data/output
    healthcheck:
      test: ["CMD-SHELL", "curl -fsS http://localhost:8188/health >/dev/null || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      # First boot pulls ~2–3 GB of model weights.
      start_period: 300s
    labels:
      - homepage.group=AI - Dormant
      - homepage.name=CosyVoice
      - homepage.icon=mdi-account-voice
      - homepage.description=Expressive multilingual TTS + cloning (irv-ml1)
      - homepage.href=http://10.100.79.3:${COSYVOICE_PORT}
