Files
Jarvis/scripts/fetch-openwakeword-models.sh
james.maes 4d52126ade feat(06-02): ModelManifest SHA-256 verifier + fetch script (Task 1)
- ModelManifest.verify(modelDir:) reads MANIFEST.json via JSONDecoder,
  checks SHA-256 of each ONNX file via CryptoKit; fail-closed on mismatch
- WakeWordError: modelHashMismatch / missingModel / ortInitFailed
- Resources/models/openwakeword/MANIFEST.json placeholder (hashes populated
  by scripts/fetch-openwakeword-models.sh on first run)
- scripts/fetch-openwakeword-models.sh: downloads 3 ONNX files from
  dscripka/openWakeWord v0.5.1, computes and writes SHA-256 to MANIFEST.json
- .gitignore: add Resources/models/**/*.onnx (large gitignored binaries)
- ModelManifestTests M1..M4: all pass (4/4 GREEN)
2026-04-27 11:42:21 -05:00

68 lines
2.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# fetch-openwakeword-models.sh — Download and hash-pin openWakeWord ONNX weights.
#
# Usage:
# bash scripts/fetch-openwakeword-models.sh
#
# What it does:
# 1. Downloads three ONNX files from the dscripka/openWakeWord v0.5.1 release.
# 2. Computes SHA-256 for each downloaded file.
# 3. Writes updated SHA-256 values to Resources/models/openwakeword/MANIFEST.json.
#
# Run this once on a fresh checkout, or after intentionally upgrading model weights.
# The ONNX files are gitignored — only MANIFEST.json is committed.
#
# DO NOT auto-redownload on hash mismatch at runtime — fail closed via
# WakeWordError.modelHashMismatch (VOICE-01 / T-06-02-01).
#
# After running, verify with:
# swift test --package-path packages/Voice --filter VoiceTests.ModelManifestTests
#
# Note: ${VAR-default} (no colon) used intentionally — empty DEST is meaningful.
set -euo pipefail
DEST=${DEST-Resources/models/openwakeword}
URLS=(
"https://github.com/dscripka/openWakeWord/releases/download/v0.5.1/melspectrogram.onnx"
"https://github.com/dscripka/openWakeWord/releases/download/v0.5.1/embedding_model.onnx"
"https://github.com/dscripka/openWakeWord/releases/download/v0.5.1/hey_jarvis_v0.1.onnx"
)
echo "Downloading openWakeWord ONNX models to ${DEST}..."
for url in "${URLS[@]}"; do
name=$(basename "$url")
echo " fetching ${name}..."
curl -fSL "$url" -o "${DEST}/${name}"
done
echo "Computing SHA-256 hashes and updating MANIFEST.json..."
python3 - <<'PYEOF'
import hashlib, json, pathlib, sys
dest = pathlib.Path("Resources/models/openwakeword")
filenames = ["melspectrogram.onnx", "embedding_model.onnx", "hey_jarvis_v0.1.onnx"]
models = []
for fn in filenames:
path = dest / fn
if not path.exists():
print(f"ERROR: {path} not found after download", file=sys.stderr)
sys.exit(1)
sha256 = hashlib.sha256(path.read_bytes()).hexdigest()
models.append({"filename": fn, "sha256": sha256})
print(f" {fn}: {sha256}")
manifest = {"version": 1, "models": models}
manifest_path = dest / "MANIFEST.json"
manifest_path.write_text(json.dumps(manifest, indent=2) + "\n")
print(f"\nMANIFEST.json updated at {manifest_path}")
PYEOF
echo ""
echo "Done. The MANIFEST.json now contains pinned SHA-256 hashes."
echo "Commit MANIFEST.json to lock the weight versions."
echo ""
echo "Verify integrity:"
echo " swift test --package-path packages/Voice --filter VoiceTests.ModelManifestTests"