Supertonic TTS Deploy auf av-tools-shared-01

Was gemacht

Lokales Open-Source-TTS (Supertonic 3, 99M-Parameter ONNX-Modell, 31 Sprachen) als Service auf bestehender Hetzner-Infra deployed und an Open WebUI VF als TTS-Engine angebunden. ElevenLabs-Replacement fuer Chat-Antwort-Vorlesen und perspektivisch WhatsApp-Voice-Replies.

Architektur

Browser (Open WebUI User)
  -> vf-chat.agenticventures.de (AWS Fargate, av-production)
    -> AUDIO_TTS_OPENAI_API_BASE_URL=https://tts.agenticventures.de/v1
      -> Cloudflare Tunnel av-tools (Zone agenticventures.de)
        -> av-tools-shared-01 (Hetzner cx23, nbg1)
          -> Docker Container `supertonic` (Port 127.0.0.1:7788)
            -> ONNX Runtime CPU-Inferenz
              -> WAV 44.1kHz 16-bit zurueck

Diagnose Server-Performance

cx23 ist Intel Skylake @ 2.0 GHz, 2 shared vCPUs. Alte Architektur fuer CPU-bound ONNX-Workload.

SetupLatenz fuer 5s DE-AudioRTF
cx23, Container-cpus 1.5 (Initial)3.5 s0.70
cx23, Container-cpus 2.0 (Quick-Win nach CPU-Bump)2.3 s0.46
CAX21 (4 vCPU ARM dediziert, geplant)erwartet ~0.8-1.2 serwartet ~0.2

Quick-Win: Container-CPU-Limit von 1.5 auf 2.0 (full host capacity) hat 34% gebracht. Mem-Limit parallel von 1500m auf 2000m, da Modell-Cache + Inferenz-Spike sonst ans Limit ging.

Service-Setup

Server: av-tools-shared-01 (Hetzner Server-ID 131113789, 46.225.16.231) Compose-Pfad: /opt/supertonic/docker-compose.yml Cloudflared-Route: tts.agenticventures.de -> http://localhost:7788 in /etc/cloudflared/config.yml DNS-Record: CNAME tts -> 6537ca14-d606-4011-9062-d31d71b73b86.cfargotunnel.com, proxied, angelegt 2026-05-18 18:30 UTC

Dockerfile (Stand 2026-05-18)

FROM python:3.12-slim
 
ENV PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1 \
    HF_HUB_DISABLE_TELEMETRY=1 \
    HF_HOME=/cache/huggingface
 
WORKDIR /app
 
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl ca-certificates \
    && rm -rf /var/lib/apt/lists/*
 
RUN pip install --upgrade pip && \
    pip install 'supertonic[serve]==1.3.1'
 
EXPOSE 7788
 
HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \
    CMD curl -fsS -X POST http://127.0.0.1:7788/v1/audio/speech \
        -H "Content-Type: application/json" \
        -d '{"model":"supertonic-3","input":"ok","voice":"M1","response_format":"wav"}' \
        -o /dev/null || exit 1
 
CMD ["supertonic", "serve", "--host", "0.0.0.0", "--port", "7788", "--cors", "https://vf-chat.agenticventures.de"]

docker-compose.yml (Stand 2026-05-18, nach Quick-Win)

services:
  supertonic:
    build: .
    container_name: supertonic
    restart: unless-stopped
    ports:
      - "127.0.0.1:7788:7788"
    volumes:
      - supertonic_cache:/cache
    mem_limit: 2000m
    cpus: 2.0
 
volumes:
  supertonic_cache:

Modell-Cache als Docker-Volume supertonic_supertonic_cache — kein Re-Download bei Container-Restart (Modell ~400 MB auf HF).

Open WebUI VF Anbindung

CDK-Stack open-webui-vf-stack.ts Zeile 365-385 erweitert um 5 ENV-Vars:

AUDIO_TTS_ENGINE=openai
AUDIO_TTS_OPENAI_API_BASE_URL=https://tts.agenticventures.de/v1
AUDIO_TTS_OPENAI_API_KEY=dummy-supertonic-no-auth
AUDIO_TTS_MODEL=supertonic-3
AUDIO_TTS_VOICE=M1

CDK Deploy 2026-05-18 18:43 UTC, TaskDef Rev 27, Service open-webui-vf auf steady state. Persistent ueber alle kuenftigen Image-Pulls.

Decisions

EntscheidungBegruendung
Hetzner statt AWS Fargate0 EUR Mehrkosten (Bestandsserver), DSGVO-trivial, Pattern „interne Tools auf Hetzner” konsistent. Fargate-Sidecar haette ~30 EUR/Mo + Task-Size-Upgrade gekostet.
Voice M1 als DefaultDE-Qualitaet bei M-Stimmen besser als F-Stimmen (Marvin-Hoertest aller 10 Voices 2026-05-18).
Bearer-Token dummy-supertonic-no-authSupertonic-Serve validiert keinen Token, aber Open WebUI verlangt einen Wert. Sicherheit kommt durch Cloudflare-Tunnel-Privates-Netz + spaeter optional CF Access.
Modell-Cache als Docker-Volume statt in ImageImage bleibt schlank (~600 MB), Modell laed einmalig beim ersten Start (3-4s auf Server-Bandbreite), persistiert ueber Restart.
—cors https://vf-chat.agenticventures.deFalls Open WebUI in Zukunft TTS direkt vom Browser holt (statt Server-Proxy), CORS erforderlich.

Bekannte Limitationen

  1. Mikrofon-STT auf Deutsch sub-par — Open WebUI 0.9.5 sendet kein language=de Parameter mit zu Groq Whisper. Auto-Detect bei kurzen Schnipseln fehlerhaft. Loesung in Bau: STT-Sprach-Proxy als 4. Container, injiziert language=de.
  2. Latenz auf cx23 immer noch zu hoch — 2.3s fuer 5s Audio ist „spuerbar warten”. CAX21-Migration zur Behebung in Planung (siehe Next Steps).
  3. Telefon-Conversation nicht echtzeitfaehig — Bei RTF >0.3 nicht streaming-tauglich. Fuer Friseur-Bot-Voicebot kommt spaeter Streaming-TTS (Cartesia/ElevenLabs Flash) oder Supertonic-GPU.

Next Steps

  1. CAX21 als dedizierter TTS-Host (4 vCPU ARM Neoverse, 8 GB, 6.49 EUR/Mo) — erwarteter Speedup 3-5x auf <1s. Marvin-OK eingeholt 2026-05-18 18:50, nicht freigegeben bei Run-Stand.
  2. STT-Sprach-Proxy fuer DE-Language-Pinning zu Groq.
  3. Welle-2 Use-Cases sobald Latenz im gruenen Bereich:
    • Tagesplan-Audio (action-items.md vorgelesen, morgens via Routine)
    • WhatsApp-Voice-Replies fuer Friseur-Bot
    • YouTube-Voiceover als Replacement fuer ElevenLabs

Test-Befehle

# Lokaler Quick-Test (von Marvins Mac)
curl -fsS -X POST https://tts.agenticventures.de/v1/audio/speech \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer dummy" \
  -d '{"model":"supertonic-3","input":"Hallo Welt","voice":"M1","response_format":"wav"}' \
  -o /tmp/test.wav && afplay /tmp/test.wav
 
# Server-Seite Latenz-Benchmark
ssh av-tools-shared 'for i in 1 2 3; do
  /usr/bin/time -f "Run %e s" curl -s -X POST http://localhost:7788/v1/audio/speech \
    -H "Content-Type: application/json" \
    -d "{\"model\":\"supertonic-3\",\"input\":\"Test Run $i.\",\"voice\":\"M1\",\"response_format\":\"wav\"}" \
    -o /tmp/t.wav
done'

0 Dateien in diesem Ordner.