e97e8b1d33
The first server deployment downloaded only 1101 bytes (a redirect/error page) and the entrypoint promoted it to ggml-large-v3.bin, after which every restart skipped the download and the server ran without a valid model. Now both fresh downloads and existing files are validated (minimum 50 MB + the ggml magic bytes); invalid files are logged, deleted, and re-downloaded, and a failed download dumps the first 400 bytes of what was actually received for diagnosis before exiting. Validated locally: a poisoned model file is detected, removed, and a valid one re-downloaded; inference served correctly afterwards.
69 lines
2.1 KiB
Bash
69 lines
2.1 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"
|
|
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
|
|
|
|
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" |