Bundle the whisper base model + one-shot standalone provisioning
- models/hf-cache/ vendors Systran/faster-whisper-base (142MB, gitignored); engine spawn pins HF_HUB_CACHE there, so transcription works with a cold ~/.cache and fully offline - verified: HOME=/tmp/fakehome HF_HUB_OFFLINE=1 model loads and transcribes via the bundled cache alone - setup-standalone.sh: idempotent fresh-clone provisioning (local venv, model copy-or-download, engine boot smoke on :8123) — runs green - backend/README rewritten for the desktop bundled-lite reality (was pointing at a nonexistent root README/docs and a Postgres quickstart) Kotlin suite still green (gradlew test, 0 failures)
This commit is contained in:
parent
a94609c07b
commit
c25d3ab150
4 changed files with 77 additions and 9 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,3 +7,4 @@ backend/__pycache__/
|
||||||
**/__pycache__/
|
**/__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
.dev-restart-flag
|
.dev-restart-flag
|
||||||
|
models/hf-cache/
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,9 @@ class DesktopState(private val appDir: File = defaultAppDir()) {
|
||||||
"SHONAR_STORAGE_PATH" to File(appDir, "storage").absolutePath,
|
"SHONAR_STORAGE_PATH" to File(appDir, "storage").absolutePath,
|
||||||
"SHONAR_TRANSCRIPTION_PROVIDER" to "faster_whisper",
|
"SHONAR_TRANSCRIPTION_PROVIDER" to "faster_whisper",
|
||||||
"SHONAR_TRANSCRIPTION_MODEL" to "base",
|
"SHONAR_TRANSCRIPTION_MODEL" to "base",
|
||||||
|
// Bundled whisper model: shipped in models/hf-cache so
|
||||||
|
// transcription works with a cold ~/.cache or offline.
|
||||||
|
"HF_HUB_CACHE" to File(repo, "models/hf-cache").absolutePath,
|
||||||
)
|
)
|
||||||
// Summarizer preference: LAN inference server (H200) when
|
// Summarizer preference: LAN inference server (H200) when
|
||||||
// its key is present in the environment, then local Ollama.
|
// its key is present in the environment, then local Ollama.
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
# S.H.O.N.A.R. backend
|
# S.H.O.N.A.R. backend (desktop bundled-lite)
|
||||||
|
|
||||||
FastAPI + PostgreSQL backend for the S.H.O.N.A.R. Android app.
|
FastAPI engine for SHONAR Desktop, running standalone on this machine:
|
||||||
|
SQLite + in-process queue, self-migrating on boot. No Postgres/Redis/Docker.
|
||||||
|
|
||||||
See the repository root [README](../README.md) and `docs/` for full documentation.
|
## Setup (this repo is self-contained)
|
||||||
|
|
||||||
## Quick start (development)
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd backend
|
cd backend
|
||||||
uv venv .venv && uv pip install -e ".[dev]"
|
uv venv .venv && uv pip install -p .venv/bin/python -e ".[dev,faster-whisper]"
|
||||||
cp ../.env.example .env # then edit SHONAR_SECRET_KEY etc.
|
|
||||||
uvicorn shonar.main:app --reload --port 8000
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Tests: `pytest` · Lint: `ruff check .` · Migrations: `alembic upgrade head`
|
The app (DesktopState) creates this venv's env vars itself, including
|
||||||
|
`HF_HUB_CACHE=models/hf-cache` — the `base` faster-whisper model is vendored
|
||||||
|
under `models/hf-cache/` (gitignored; copy from any HF cache to reprovision).
|
||||||
|
|
||||||
|
Tests: `.venv/bin/python -m pytest` (SQLite by default; point
|
||||||
|
`SHONAR_TEST_DATABASE_URL` at Postgres to test that path) · Lint: `ruff check .`
|
||||||
|
· Migrations: `alembic upgrade head`
|
||||||
|
|
|
||||||
61
setup-standalone.sh
Executable file
61
setup-standalone.sh
Executable file
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# One-shot provisioning for a fresh clone of SHONAR Desktop:
|
||||||
|
# local engine venv + vendored whisper base model. Idempotent.
|
||||||
|
set -uo pipefail
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
echo "==> backend venv (local, editable install of THIS backend)"
|
||||||
|
if [ ! -x backend/.venv/bin/uvicorn ]; then
|
||||||
|
command -v uv >/dev/null || { echo "uv not found — install it: curl -LsSf https://astral.sh/uv/install.sh | sh"; exit 1; }
|
||||||
|
(cd backend && uv venv .venv --python 3.11 && uv pip install -p .venv/bin/python -e ".[dev,faster-whisper]")
|
||||||
|
else
|
||||||
|
echo " already present"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> whisper base model -> models/hf-cache"
|
||||||
|
MC="models/hf-cache/models--Systran--faster-whisper-base"
|
||||||
|
if [ -d "$MC/snapshots" ] && [ -n "$(ls -A "$MC/snapshots" 2>/dev/null)" ]; then
|
||||||
|
echo " already present"
|
||||||
|
else
|
||||||
|
# Prefer copying an existing local copy (works offline)...
|
||||||
|
src=""
|
||||||
|
for c in "${HF_HUB_CACHE:-$HOME/.cache/huggingface/hub}/models--Systran--faster-whisper-base" \
|
||||||
|
"$HOME/.cache/huggingface/hub/models--Systran--faster-whisper-base"; do
|
||||||
|
[ -d "$c/snapshots" ] && { src="$c"; break; }
|
||||||
|
done
|
||||||
|
mkdir -p models/hf-cache
|
||||||
|
if [ -n "$src" ]; then
|
||||||
|
echo " copying from $src"
|
||||||
|
cp -r "$src" models/hf-cache/
|
||||||
|
else
|
||||||
|
echo " no local copy — downloading from HuggingFace (needs internet once)"
|
||||||
|
backend/.venv/bin/python - <<'EOF'
|
||||||
|
from huggingface_hub import snapshot_download
|
||||||
|
snapshot_download("Systran/faster-whisper-base", cache_dir="models/hf-cache")
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> smoke: engine boots on :8123 with the bundled cache"
|
||||||
|
tmp=$(mktemp -d)
|
||||||
|
SHONAR_SECRET_KEY="bootstrap-verify-secret-0123456789abcdef" \
|
||||||
|
SHONAR_DATABASE_URL="sqlite+aiosqlite:///$tmp/e.db" \
|
||||||
|
SHONAR_QUEUE_BACKEND=inline SHONAR_AUTO_MIGRATE=1 \
|
||||||
|
SHONAR_STORAGE_PATH="$tmp/storage" \
|
||||||
|
HF_HUB_CACHE="$PWD/models/hf-cache" \
|
||||||
|
backend/.venv/bin/uvicorn shonar.main:app --app-dir backend --port 8123 \
|
||||||
|
>"$tmp/uvicorn.log" 2>&1 &
|
||||||
|
pid=$!
|
||||||
|
ok=""
|
||||||
|
for _ in $(seq 1 30); do
|
||||||
|
sleep 1
|
||||||
|
curl -sf -m 2 http://127.0.0.1:8123/api/v1/readyz >/dev/null && { ok=1; break; }
|
||||||
|
done
|
||||||
|
kill $pid 2>/dev/null; wait $pid 2>/dev/null
|
||||||
|
rm -rf "$tmp"
|
||||||
|
if [ -n "$ok" ]; then
|
||||||
|
echo " engine ready — provisioning complete. Start the app: ./desktop-dev.sh"
|
||||||
|
else
|
||||||
|
echo " ENGINE FAILED TO START" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Loading…
Add table
Add a link
Reference in a new issue