nex-speech: Sprachdienste für NEX (whisper.cpp CUDA 12 + Piper) als Compose und Ansible-Rolle
ci / test (push) Successful in 29s

- deploy/compose/nex-speech: whisper-server v1.9.4 (sm_52/sm_61, Port 8178, -l de -bs 5
  --convert, tmpfs, Aufwärmen mit 1 s Stille) und OpenAI-kompatibler Piper-Wrapper
  (Port 8179, mp3/opus/aac/flac/pcm gestreamt, wav, PCM 24 kHz mit Rate-Header)
- Host-Netz, damit ufw greift; keine Texte in Logs, kein Access-Log
- Rolle nex-speech + Playbook (nur gpu-pve52): ufw, Modelle mit sha256, Compose bauen/starten
- compose-check um nex-speech erweitert, community.docker in requirements.yml

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Rapp
2026-10-12 20:41:11 +02:00
co-authored by Claude Opus 5.5
parent b66c4c37cc
commit afc5fa0360
13 changed files with 643 additions and 1 deletions
@@ -0,0 +1,76 @@
# NEX-Sprachdienste (Task 6.2, Auftrag docs/auftraege/2026-10-12-sprachmodelle-nex.md)
# nex-stt Erkennung: whisper.cpp whisper-server (CUDA 12, sm_52/sm_61), Port 8178
# nex-tts Ausgabe: Piper (CPU) hinter OpenAI-kompatiblem Wrapper, Port 8179
# Beide im Host-Netz: Veröffentlichte Docker-Ports laufen über DNAT/FORWARD und umgehen ufw.
# So gelten die ufw-Regeln der VM (8178/8179 nur von 192.168.100.29), siehe Ansible-Rolle nex-speech.
# Datenschutz: kein Access-Log, keine Texte im Log, Temp-Dateien nur im tmpfs.
name: nex-speech
x-logging: &logging
driver: local
options: {max-size: "5m", max-file: "2"}
services:
nex-stt:
build:
context: ./whisper
args:
WHISPER_TAG: ${WHISPER_TAG:-v1.9.4}
WHISPER_COMMIT: ${WHISPER_COMMIT:-927cfce34f31707e17f2bff35c349632fb9e2c3a}
CUDA_ARCHS: ${CUDA_ARCHS:-52;61}
image: knaster/nex-whisper:${WHISPER_TAG:-v1.9.4}-cu12.6
container_name: nex-stt
restart: unless-stopped
network_mode: host
read_only: true
environment:
WHISPER_PORT: ${STT_PORT:-8178}
WHISPER_MODEL: /models/whisper/${WHISPER_MODEL_FILE:-ggml-large-v3-turbo.bin}
WHISPER_LANGUAGE: de
WHISPER_BEAM_SIZE: ${WHISPER_BEAM_SIZE:-5}
WHISPER_EXTRA_ARGS: ${WHISPER_EXTRA_ARGS:-}
volumes:
- ${MODELS_DIR:-/srv/models}/whisper:/models/whisper:ro
tmpfs:
- /run/nex-whisper:size=512m,mode=0700
deploy:
resources:
reservations:
devices: [{driver: nvidia, device_ids: ["${STT_GPU:-0}"], capabilities: [gpu]}]
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:$${WHISPER_PORT}/health >/dev/null || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 300s
logging: *logging
nex-tts:
build: ./piper
image: knaster/nex-tts-piper:${PIPER_TTS_VERSION:-1.8.0}
container_name: nex-tts
restart: unless-stopped
network_mode: host
read_only: true
environment:
TTS_PORT: ${TTS_PORT:-8179}
PIPER_VOICES_DIR: /voices
PIPER_VOICES: ${PIPER_VOICES:-de_DE-thorsten-high,de_DE-kerstin-low}
PIPER_DEFAULT_VOICE: ${PIPER_DEFAULT_VOICE:-de_DE-thorsten-high}
PCM_SAMPLE_RATE: ${PCM_SAMPLE_RATE:-24000}
TTS_MAX_CHARS: ${TTS_MAX_CHARS:-5000}
TTS_PARALLEL: ${TTS_PARALLEL:-2}
volumes:
- ${MODELS_DIR:-/srv/models}/piper:/voices:ro
tmpfs:
- /tmp:size=64m
deploy:
resources:
limits: {cpus: "3", memory: 2G} # ein Kern bleibt für whisper-server und das System
healthcheck:
test: ["CMD", "python", "-c", "import os, urllib.request; urllib.request.urlopen(f\"http://127.0.0.1:{os.environ.get('TTS_PORT', '8179')}/health\", timeout=4)"]
interval: 30s
timeout: 5s
retries: 3
start_period: 60s
logging: *logging