drowzeys's picture
Upload folder using huggingface_hub
676f5d4 verified
Raw
History Blame Contribute Delete
5.16 kB
#!/usr/bin/env bash
# =============================================================================
# ONE-SHOT: keys-Auto Receipts Studio (iPhone / may add Autonomous Lamp Skill)
# 1. Python 3.12 venv + app
# 2. Gemma 4 12B-it weights (skip if already on disk)
# 3. vLLM serve --gpu-memory-utilization 0.15 FP8 max-model-len 8192
# 4. Gradio UI on the LAN + print phone URL
# Idempotent. Re-run anytime. Never raises GPU util above 0.85.
# =============================================================================
set -euo pipefail
ROOT="$(cd "$(dirname "$0")" && pwd)"
cd "$ROOT"
MODEL_ID="${RECEIPT_HF_MODEL:-google/gemma-4-12B-it}"
MODEL_DIR="${RECEIPT_GEMMA_PATH:-$HOME/models-gemma4-12b-it}"
PORT_LLM="${RECEIPT_VLLM_PORT:-8080}"
PORT_UI="${RECEIPT_UI_PORT:-7860}"
UTIL="${RECEIPT_GPU_MEMORY_UTILIZATION:-0.15}"
say(){ printf '\n\033[1;36m==> %s\033[0m\n' "$*"; }
die(){ printf '\n\033[1;31mFAILED: %s\033[0m\n' "$*" >&2; exit 1; }
python3 -c 'import sys; assert sys.version_info >= (3,12), sys.version' \
|| die "Python 3.12+ required"
if python3 -c "u=float('$UTIL'); assert u<=0.85" 2>/dev/null; then :; else
die "gpu_memory_utilization $UTIL > 0.85 hard cap"
fi
say "1/5 venv + install"
if [[ ! -x .venv/bin/python ]]; then
python3 -m venv .venv
fi
.venv/bin/pip install -q -U pip
.venv/bin/pip install -q -e ".[dev]"
[[ -f .env ]] || cp .env.example .env
HAVE_VLLM=0
if curl -sf -m3 "http://127.0.0.1:$PORT_LLM/v1/models" >/dev/null 2>&1; then
HAVE_VLLM=1
elif command -v vllm >/dev/null 2>&1; then
HAVE_VLLM=1
fi
say "2/5 Gemma 4 12B-it weights → $MODEL_DIR"
if [[ "$HAVE_VLLM" != 1 ]]; then
echo " skip (no vllm on PATH and nothing on :$PORT_LLM) — UI-only. Point .env at a GPU box."
elif [[ -f "$MODEL_DIR/config.json" ]] && ls "$MODEL_DIR"/*.safetensors >/dev/null 2>&1; then
echo " present"
else
.venv/bin/pip install -q huggingface_hub
mkdir -p "$MODEL_DIR"
.venv/bin/python - "$MODEL_ID" "$MODEL_DIR" <<'PY' || die "weight download failed (run: .venv/bin/hf auth login)"
import sys
from huggingface_hub import snapshot_download
snapshot_download(sys.argv[1], local_dir=sys.argv[2])
print(" downloaded")
PY
fi
say "3/5 vLLM Gemma (util=$UTIL FP8, :$PORT_LLM)"
if curl -sf -m3 "http://127.0.0.1:$PORT_LLM/v1/models" >/dev/null 2>&1; then
echo " already serving"
elif command -v vllm >/dev/null 2>&1 && [[ -f "$MODEL_DIR/config.json" ]]; then
mkdir -p data
nohup bash "$ROOT/scripts/serve-gemma.sh" >> data/vllm-gemma.log 2>&1 &
echo " pid $! log data/vllm-gemma.log"
else
echo " skip — no local vLLM/Gemma. Set RECEIPT_LLM_BASE_URL in .env to the GPU box."
fi
say "4/5 wait until Gemma answers /v1/models (first boot compiles kernels)"
if curl -sf -m3 "http://127.0.0.1:$PORT_LLM/v1/models" >/dev/null 2>&1; then
echo " already healthy"
elif command -v vllm >/dev/null 2>&1 && [[ -f "$MODEL_DIR/config.json" ]]; then
ok=0
for i in $(seq 1 120); do
if curl -sf -m3 "http://127.0.0.1:$PORT_LLM/v1/models" >/dev/null 2>&1; then
echo " healthy ($i)"
ok=1
break
fi
sleep 5
done
[[ "$ok" = 1 ]] || die "vLLM not healthy — tail data/vllm-gemma.log"
else
echo " skip wait (no local Gemma). UI will still start."
fi
say "5/5 UI on LAN :$PORT_UI"
mkdir -p data
export RECEIPT_UI_SHARE_LAN=true
# Only pin LLM URLs to this machine when local Gemma is actually up.
# UI-only boxes must keep .env pointing at the GPU box.
if curl -sf -m3 "http://127.0.0.1:$PORT_LLM/v1/models" >/dev/null 2>&1; then
export RECEIPT_LLM_BASE_URL="http://127.0.0.1:${PORT_LLM}/v1"
export RECEIPT_EMBED_BASE_URL="http://127.0.0.1:${PORT_LLM}/v1"
export RECEIPT_LLM_MODEL="$MODEL_ID"
export RECEIPT_EMBED_MODEL="$MODEL_ID"
export RECEIPT_EMBED_DIM=3840
export RECEIPT_EMBED_BACKEND=omni
fi
if curl -sf -m2 "http://127.0.0.1:$PORT_UI/phone" >/dev/null 2>&1; then
echo " UI already up"
else
nohup .venv/bin/python -m app.cli ui >> data/ui.log 2>&1 &
echo " pid $!"
for i in $(seq 1 40); do
curl -sf -m2 "http://127.0.0.1:$PORT_UI/phone" >/dev/null 2>&1 && break
sleep 0.25
done
fi
LAN="$(python3 - <<'PY'
import socket
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect(("192.0.2.1",1)); print(s.getsockname()[0])
except OSError:
print("127.0.0.1")
finally:
s.close()
PY
)"
printf '\n\033[1;32m✅ READY\033[0m keys-Auto Receipts Studio\n'
printf ' Review (this machine): http://127.0.0.1:%s\n' "$PORT_UI"
printf ' iPhone Safari: http://%s:%s/phone\n' "$LAN" "$PORT_UI"
if curl -sf -m2 "http://127.0.0.1:$PORT_LLM/v1/models" >/dev/null 2>&1; then
printf ' Gemma /v1: http://127.0.0.1:%s/v1 model %s util=%s\n' "$PORT_LLM" "$MODEL_ID" "$UTIL"
else
printf ' Gemma /v1: not local — set RECEIPT_LLM_BASE_URL in .env to the GPU box\n'
fi
printf ' Desktop launcher: bash scripts/install-launcher.sh\n'
printf ' Windows desktop icon: scripts\\install-launcher.bat\n'
printf '\n Hold a receipt up → Take photo on the phone page (Safari).\n'
printf ' Lamp skill: skills/keys-receipt-scanner/ — 12B does not fit in 6GB RAM.\n'