nex-speech: Sprachdienste für NEX (whisper.cpp CUDA 12 + Piper) als Compose und Ansible-Rolle
ci / test (push) Successful in 29s
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:
co-authored by
Claude Opus 5.5
parent
b66c4c37cc
commit
afc5fa0360
@@ -0,0 +1,39 @@
|
||||
# whisper.cpp whisper-server für Maxwell (sm_52, Quadro M4000) und Pascal (sm_61, Quadro P2000).
|
||||
# CUDA 12 ist Pflicht: CUDA 13 unterstützt Maxwell/Pascal nicht mehr. Treiber R580 in der VM.
|
||||
# Version und Commit sind fest; ein Wechsel ist ein bewusster Schritt (Tag und Commit gemeinsam ändern).
|
||||
ARG CUDA_DEVEL=nvidia/cuda:12.6.3-devel-ubuntu24.04@sha256:392c0df7b577ecae17a17f6ba7f2009c217bb4422f8431c053ae9af61a8c148a
|
||||
ARG CUDA_RUNTIME=nvidia/cuda:12.6.3-runtime-ubuntu24.04@sha256:92906d87596d638d35015c6353053121bd299d25943b875763321653884ba924
|
||||
|
||||
FROM ${CUDA_DEVEL} AS build
|
||||
ARG WHISPER_TAG=v1.9.4
|
||||
ARG WHISPER_COMMIT=927cfce34f31707e17f2bff35c349632fb9e2c3a
|
||||
ARG CUDA_ARCHS="52;61"
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends git cmake build-essential ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /src
|
||||
RUN git clone --depth 1 --branch "${WHISPER_TAG}" https://github.com/ggml-org/whisper.cpp.git . \
|
||||
&& test "$(git rev-parse HEAD)" = "${WHISPER_COMMIT}"
|
||||
# Statisch gegen ggml/whisper linken: eine einzelne Binary, keine .so-Kopien in der Laufzeit-Stufe.
|
||||
# libcuda kommt zur Laufzeit vom Treiber; beim Bauen reicht der Stub.
|
||||
RUN cmake -B build \
|
||||
-DGGML_CUDA=ON \
|
||||
-DCMAKE_CUDA_ARCHITECTURES="${CUDA_ARCHS}" \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DWHISPER_BUILD_TESTS=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="-L/usr/local/cuda/lib64/stubs" \
|
||||
&& cmake --build build --target whisper-server -j"$(nproc)" \
|
||||
&& strip build/bin/whisper-server
|
||||
|
||||
FROM ${CUDA_RUNTIME}
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ffmpeg curl ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=build /src/build/bin/whisper-server /usr/local/bin/whisper-server
|
||||
# ffmpeg-Hülle: whisper-server ruft "ffmpeg … 2>&1" auf und schriebe sonst Banner und
|
||||
# Container-Metadaten des Uploads ins Log. Die Hülle liegt vor /usr/bin im PATH.
|
||||
COPY ffmpeg-quiet.sh /usr/local/bin/ffmpeg
|
||||
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
RUN chmod 0755 /usr/local/bin/ffmpeg /usr/local/bin/entrypoint.sh
|
||||
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
# Start von whisper-server für NEX (Spracherkennung, OpenAI-kompatibel).
|
||||
# - Parameter laut Auftrag: -l de -bs 5 --convert, ohne --print-realtime (kein Text im Log).
|
||||
# - Temp-Dateien nur im tmpfs; Reste (Fehlerpfad von whisper-server) werden regelmäßig gelöscht.
|
||||
# - Nach dem Start einmal mit 1 s Stille aufwärmen.
|
||||
set -eu
|
||||
|
||||
MODEL="${WHISPER_MODEL:-/models/whisper/ggml-large-v3-turbo.bin}"
|
||||
PORT="${WHISPER_PORT:-8178}"
|
||||
HOST="${WHISPER_HOST:-0.0.0.0}"
|
||||
TMP_DIR="${WHISPER_TMP_DIR:-/run/nex-whisper}"
|
||||
BEAM="${WHISPER_BEAM_SIZE:-5}"
|
||||
LANGUAGE="${WHISPER_LANGUAGE:-de}"
|
||||
# Zusätzliche Schalter, z. B. "-nfa" (Flash-Attention aus) oder "-t 4"
|
||||
EXTRA="${WHISPER_EXTRA_ARGS:-}"
|
||||
|
||||
mkdir -p "$TMP_DIR"
|
||||
chmod 0700 "$TMP_DIR"
|
||||
|
||||
# Aufräumer: Dateien älter als 10 Minuten im tmpfs löschen
|
||||
( while sleep 300; do find "$TMP_DIR" -type f -mmin +10 -delete 2>/dev/null || true; done ) &
|
||||
cleaner=$!
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
whisper-server -m "$MODEL" -l "$LANGUAGE" -bs "$BEAM" --convert --tmp-dir "$TMP_DIR" \
|
||||
--inference-path /v1/audio/transcriptions --host "$HOST" --port "$PORT" $EXTRA &
|
||||
pid=$!
|
||||
|
||||
stop() { kill -TERM "$pid" 2>/dev/null || true; kill "$cleaner" 2>/dev/null || true; }
|
||||
trap stop TERM INT
|
||||
|
||||
# Warten, bis das Modell geladen ist (/health liefert bis dahin 503)
|
||||
i=0
|
||||
until curl -fsS "http://127.0.0.1:${PORT}/health" >/dev/null 2>&1; do
|
||||
kill -0 "$pid" 2>/dev/null || { echo "whisper-server beendet sich beim Start" >&2; wait "$pid" || exit $?; exit 1; }
|
||||
i=$((i + 1))
|
||||
[ "$i" -le 600 ] || { echo "whisper-server nach 600 s nicht bereit" >&2; stop; exit 1; }
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Aufwärmen: 1 s Stille, Ergebnis wird verworfen
|
||||
warm="$TMP_DIR/warmup.wav"
|
||||
if ffmpeg -f lavfi -i anullsrc=r=16000:cl=mono -t 1 -c:a pcm_s16le -y "$warm" \
|
||||
&& curl -fsS -o /dev/null -F "file=@${warm}" -F response_format=json \
|
||||
"http://127.0.0.1:${PORT}/v1/audio/transcriptions"; then
|
||||
echo "whisper-server bereit und aufgewärmt (Port ${PORT})"
|
||||
else
|
||||
echo "Aufwärmen fehlgeschlagen, Dienst läuft trotzdem" >&2
|
||||
fi
|
||||
rm -f "$warm"
|
||||
|
||||
# Auf whisper-server warten; nach einem Signal erneut warten, bis er wirklich beendet ist
|
||||
rc=0
|
||||
wait "$pid" || rc=$?
|
||||
while kill -0 "$pid" 2>/dev/null; do wait "$pid" || rc=$?; done
|
||||
kill "$cleaner" 2>/dev/null || true
|
||||
exit "$rc"
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
# Leise ffmpeg-Hülle für whisper-server (--convert): kein Banner, keine Metadaten, nur Fehler.
|
||||
exec /usr/bin/ffmpeg -hide_banner -nostdin -loglevel error "$@"
|
||||
Reference in New Issue
Block a user