Files
meetrec/server/whisper-server/entrypoint.sh
T
fegger 76611af7e0 M3d: speaker labels via tinydiarize two-pass merge
- whisper-server stack: second container (port 8086) running the
  English-trained small.en-tdrz model with -tdrz; image patched
  (speaker-turn.patch) to expose speaker_turn_next per segment in
  verbose_json like the cli example does
- core/whisper Diarization: merges the tdrz pass's TURN TIMES onto the
  quality transcript as alternating 'Sprecher 1/2:' labels, splitting
  segments when a turn falls inside them; no turns detected = no
  labels (never mislabels); 6 unit tests
- RemoteWhisperEngine gains a diarize flag (sends tinydiarize=true,
  parses speaker_turn_next); WhisperEngine.Segment carries the flag
- RecorderService: optional second pass on the diarize server after the
  final pass; failures keep the unlabeled transcript
- Settings: Diarize server URL (persisted; empty disables)
- validated infrastructure locally: patched image builds, tdrz model
  downloads from akashmjn/tinydiarize-whisper.cpp, speaker_turn_next
  present in responses; synthetic espeak audio does not trigger the
  model's turn tokens — real two-person speech needed for the
  end-to-end check
2026-09-08 17:07:31 +02:00

73 lines
2.3 KiB
Bash

#!/bin/sh
# Downloads the configured GGML model on first start, then runs whisper-server.
# Uses the GPU (Vulkan) automatically when one is present; set NO_GPU=1
# to force CPU.
#
# Both the freshly downloaded file and any existing file are validated
# (minimum size + ggml magic bytes) so a truncated download or a saved
# error/redirect page can never be mistaken for a model — a poisoned
# file is deleted and re-downloaded instead.
set -eu
MODEL="${MODEL:-small}"
THREADS="${THREADS:-4}"
HOST="${HOST:-0.0.0.0}"
PORT="${PORT:-8085}"
MODEL_DIR="${MODEL_DIR:-/models}"
FILE="$MODEL_DIR/ggml-$MODEL.bin"
# default to the ggerganov collection; TDRZ models live elsewhere
URL="${MODEL_URL:-https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-$MODEL.bin}"
# smallest supported model (ggml-tiny.bin) is ~75 MB
MIN_SIZE=50000000
GGML_MAGIC="$(printf 'lmgg')" # GGML_FILE_MAGIC 0x67676d6c, little-endian
is_valid_model() {
[ -s "$1" ] || return 1
[ "$(stat -c%s "$1")" -ge "$MIN_SIZE" ] || return 1
[ "$(head -c 4 "$1")" = "$GGML_MAGIC" ] || return 1
return 0
}
mkdir -p "$MODEL_DIR"
if ! is_valid_model "$FILE" && [ -e "$FILE" ]; then
echo "existing $FILE is invalid ($(stat -c%s "$FILE") bytes) — " \
"deleting and re-downloading"
fi
if ! is_valid_model "$FILE"; then
rm -f "$FILE" "$FILE.part"
echo "downloading $URL to $FILE ..."
curl -fLS --retry 3 --retry-delay 5 -C - -o "$FILE.part" "$URL"
if ! is_valid_model "$FILE.part"; then
size="$(stat -c%s "$FILE.part" 2>/dev/null || echo 0)"
echo "ERROR: download is not a valid model ($size bytes)."
echo "------- first 400 bytes of the response (probably an error/redirect page):"
head -c 400 "$FILE.part"
echo ""
echo "------- end of response"
rm -f "$FILE.part"
exit 1
fi
mv "$FILE.part" "$FILE"
echo "downloaded $(stat -c%s "$FILE") bytes, magic ok."
fi
GPU_FLAGS=""
if [ "${NO_GPU:-0}" = "1" ]; then
GPU_FLAGS="-ng"
fi
if [ "${TDRZ:-0}" = "1" ]; then
GPU_FLAGS="$GPU_FLAGS -tdrz"
fi
echo "starting whisper-server: model=$MODEL threads=$THREADS host=$HOST port=$PORT gpu=auto"
exec whisper-server \
-m "$FILE" \
-l auto \
-t "$THREADS" \
$GPU_FLAGS \
--host "$HOST" \
--port "$PORT"