SPB Git forge

spb/llm-api

Public
0commits 0branches 0releases
0 Bsize
maindefault branch
—last push
4.5 KB · 99 lines shellscript
Raw Blame History
1#!/usr/bin/env bash2# LLM API — install on a clean Apple Silicon Mac.3# Usage: ./scripts/install.sh [--root ~/llm-api] [--no-llama] [--no-web] [--test]4set -euo pipefail56ROOT="${LLM_API_ROOT:-$HOME/llm-api}"7WITH_LLAMA=18WITH_WEB=19RUN_TEST=010for a in "$@"; do11  case "$a" in12    --root) shift; ROOT="$1";;13    --root=*) ROOT="${a#--root=}";;14    --no-llama) WITH_LLAMA=0;;15    --no-web) WITH_WEB=0;;16    --test) RUN_TEST=1;;17  esac18done19HERE="$(cd "$(dirname "$0")/.." && pwd)"20say() { printf "\033[1;34m==>\033[0m %s\n" "$*"; }21warn() { printf "\033[1;33m!!\033[0m %s\n" "$*"; }2223# 1. platform checks -------------------------------------------------------24[ "$(uname -s)" = "Darwin" ] || { echo "macOS required"; exit 1; }25[ "$(uname -m)" = "arm64" ] || { echo "Apple Silicon (arm64) required"; exit 1; }26CHIP=$(sysctl -n machdep.cpu.brand_string)27MEM_GB=$(( $(sysctl -n hw.memsize) / 1024 / 1024 / 1024 ))28FREE_GB=$(df -g "$HOME" | awk 'NR==2 {print $4}')29say "Detected $CHIP, ${MEM_GB} GB unified memory, ${FREE_GB} GB free on $HOME"30[ "$MEM_GB" -ge 16 ] || warn "Less than 16 GB of memory: only small models will run."31[ "$FREE_GB" -ge 120 ] || warn "Less than 120 GB free: downloads stop at the MIN_FREE_DISK_GB reserve."32export PATH="/opt/homebrew/bin:$HOME/.local/bin:$PATH"3334# 2. toolchain ---------------------------------------------------------------35xcode-select -p >/dev/null 2>&1 || { say "Installing Xcode Command Line Tools (a dialog may appear)"; xcode-select --install || true; }36command -v brew >/dev/null || { say "Installing Homebrew"; /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; eval "$(/opt/homebrew/bin/brew shellenv)"; }37command -v uv >/dev/null || { say "Installing uv"; brew install uv; }38if [ "$WITH_WEB" = 1 ]; then39  command -v node >/dev/null || { say "Installing Node"; brew install node; }40  command -v pnpm >/dev/null || { say "Installing pnpm"; brew install pnpm; }41fi42if [ "$WITH_LLAMA" = 1 ]; then43  command -v llama-server >/dev/null || { say "Installing llama.cpp (Metal)"; brew install llama.cpp; }44fi4546# 3. directories ---------------------------------------------------------------47say "Creating $ROOT"48mkdir -p "$ROOT"/{models/{mlx,gguf,embeddings,rerankers,vision,manifests},data,logs}49chmod 700 "$ROOT/data"5051# 4. python env -----------------------------------------------------------------52cd "$HERE/server"53if [ ! -x .venv/bin/python ]; then54  say "Creating Python 3.13 virtualenv"55  uv venv --python 3.13 .venv56fi57say "Installing Python dependencies (MLX, MLX-LM, mlx-vlm, FastAPI…)"58uv pip install --python .venv/bin/python -q -e ".[mlx,test]" "mlx-vlm>=0.7" asgi-lifespan59.venv/bin/python - <<'PY'60import mlx.core as mx, mlx_lm61print(f"    mlx {mx.__version__} · mlx-lm {mlx_lm.__version__} · Metal device: {mx.default_device()}")62PY6364# 5. web ------------------------------------------------------------------------65if [ "$WITH_WEB" = 1 ]; then66  say "Installing and building the dashboard"67  (cd "$HERE/web" && pnpm install --frozen-lockfile --silent && NEXT_TELEMETRY_DISABLED=1 pnpm build | tail -3)68fi6970# 6. env file (never overwrite) ----------------------------------------------------71if [ ! -f "$ROOT/.env" ]; then72  say "Writing $ROOT/.env from .env.example (edit ADMIN_EMAIL / ADMIN_PASSWORD / HF_TOKEN)"73  sed "s#/Users/USERNAME/llm-api#$ROOT#" "$HERE/.env.example" > "$ROOT/.env"74  chmod 600 "$ROOT/.env"75else76  say "$ROOT/.env already exists — left untouched"77fi7879# 7. database + scan ------------------------------------------------------------------80say "Initializing database and scanning $ROOT/models"81(cd "$ROOT" && "$HERE/server/.venv/bin/llm-api" scan | tail -5)8283# 8. optional local inference test -------------------------------------------------------84if [ "$RUN_TEST" = 1 ]; then85  say "Downloading a tiny test model and running one generation"86  "$HERE/server/.venv/bin/hf" download mlx-community/Qwen3-0.6B-4bit --local-dir "$ROOT/models/mlx/qwen/Qwen3-0.6B-4bit" >/dev/null87  "$HERE/server/.venv/bin/python" -m mlx_lm generate --model "$ROOT/models/mlx/qwen/Qwen3-0.6B-4bit" --prompt "Say hello in one word." --max-tokens 8 | tail -388fi8990cat <<EOF9192Done. Next steps:93  1. Edit $ROOT/.env (ADMIN_EMAIL, ADMIN_PASSWORD, HF_TOKEN, PUBLIC_URL)94  2. Start the API:        cd $ROOT && $HERE/server/.venv/bin/llm-api serve95  3. Start the dashboard:  cd $HERE/web && pnpm start -p 8301 -H 127.0.0.196  4. Open http://127.0.0.1:8300 — or put a TLS reverse proxy in front for https://$(grep -E '^DOMAIN=' "$ROOT/.env" | cut -d= -f2)97  Process management: see docs/deployment.md (PM2 / launchd examples).98EOF99