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.
| Setup | Latenz fuer 5s DE-Audio | RTF |
|---|---|---|
| cx23, Container-cpus 1.5 (Initial) | 3.5 s | 0.70 |
| cx23, Container-cpus 2.0 (Quick-Win nach CPU-Bump) | 2.3 s | 0.46 |
| CAX21 (4 vCPU ARM dediziert, geplant) | erwartet ~0.8-1.2 s | erwartet ~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
| Entscheidung | Begruendung |
|---|---|
| Hetzner statt AWS Fargate | 0 EUR Mehrkosten (Bestandsserver), DSGVO-trivial, Pattern „interne Tools auf Hetzner” konsistent. Fargate-Sidecar haette ~30 EUR/Mo + Task-Size-Upgrade gekostet. |
| Voice M1 als Default | DE-Qualitaet bei M-Stimmen besser als F-Stimmen (Marvin-Hoertest aller 10 Voices 2026-05-18). |
Bearer-Token dummy-supertonic-no-auth | Supertonic-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 Image | Image bleibt schlank (~600 MB), Modell laed einmalig beim ersten Start (3-4s auf Server-Bandbreite), persistiert ueber Restart. |
| —cors https://vf-chat.agenticventures.de | Falls Open WebUI in Zukunft TTS direkt vom Browser holt (statt Server-Proxy), CORS erforderlich. |
Bekannte Limitationen
- Mikrofon-STT auf Deutsch sub-par — Open WebUI 0.9.5 sendet kein
language=deParameter mit zu Groq Whisper. Auto-Detect bei kurzen Schnipseln fehlerhaft. Loesung in Bau: STT-Sprach-Proxy als 4. Container, injiziertlanguage=de. - Latenz auf cx23 immer noch zu hoch — 2.3s fuer 5s Audio ist „spuerbar warten”. CAX21-Migration zur Behebung in Planung (siehe Next Steps).
- 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
- 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.
- STT-Sprach-Proxy fuer DE-Language-Pinning zu Groq.
- 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'