CoolFace
Apppublic

uapb/ai

sourceHugging Facemitupdated 1mo agoView on Hugging Face
0likes
run-jem.sh126 linesDownload Raw Back to scripts
1#!/usr/bin/env bash2#3# run-jem.sh — bring the whole Jem stack up on localhost.4#5#   ollama      :11434   serves llama3.2:3b, the model that actually answers6#   jem-agent   :5000    Flask; persona, session memory, SSE streaming7#   site        :8002    FastAPI; serves web/index.html and proxies /chat*8#9# Ollama is a rootless install under ~/.local/ollama (this box has no10# passwordless sudo, so there is no systemd unit to start). Everything here is11# a plain user process, so a WSL restart takes the whole stack down — just run12# this again. Logs land in logs/ at the repo root (already gitignored).13#14# Usage:   ./scripts/run-jem.sh          start anything not already running15#          ./scripts/run-jem.sh stop     stop the agent and the site16#          ./scripts/run-jem.sh restart  stop them, then start again — use this17#                                        after editing jem_agent/app.py, since a18#                                        running agent holds the old persona in19#                                        memory20#21set -uo pipefail22# Guarded: everything below (pkill, log writes) assumes the repo root, so a23# failed cd must stop the script rather than act on some other directory.24cd "$(dirname "$0")/.." || exit 125mkdir -p logs26 27export PATH="$HOME/.local/bin:$PATH"28OLLAMA_BIN="$HOME/.local/ollama/bin/ollama"29PORT="${PORT:-8002}"30AGENT_PORT="${JEM_AGENT_PORT:-5000}"31 32stop_servers () {33  # Match on the listening port rather than the command line: the servers are34  # started with setsid and `pkill -f` has proved unreliable at matching them.35  for p in "$PORT" "$AGENT_PORT"; do36    local pids37    pids=$(ss -ltnpH "sport = :$p" 2>/dev/null | grep -oP 'pid=\K[0-9]+' | sort -u)38    [[ -n "$pids" ]] && kill $pids 2>/dev/null && echo "  stopped whatever held :$p"39  done40  pkill -f "uvicorn server.main:app" 2>/dev/null41  pkill -f "flask --app jem_agent.app" 2>/dev/null42  pkill -f "flask --app app run" 2>/dev/null43  sleep 144}45 46if [[ "${1:-}" == "stop" ]]; then47  stop_servers48  echo "(ollama left running — pkill -f 'ollama serve' to stop it too)"49  exit 050fi51 52if [[ "${1:-}" == "restart" ]]; then53  echo "▶ stopping"54  stop_servers55fi56 57# setsid detaches each server from this shell's session and process group, so58# closing the terminal does not take them with it.59#60# It is NOT what keeps the stack alive, and an earlier version of this comment61# wrongly claimed WSL tears the distro down when the launching command returns.62# It does not — the distro was measured up for 4h58m with every server dead. The63# real killers were the OOM killer and the absence of any supervisor. Use64# ./install-services.sh for anything long-lived; this script is for quick tests.65spawn () {   # spawn <logfile> <command...>66  local log=$1; shift67  setsid "$@" > "$log" 2>&1 < /dev/null &68  disown 2>/dev/null || true69}70 71wait_for () {   # wait_for <url> <label> <tries>72  local url=$1 label=$2 tries=${3:-60}73  for ((i = 0; i < tries; i++)); do74    curl -sf -m 2 "$url" > /dev/null 2>&1 && { echo "  ✅ $label"; return 0; }75    sleep 176  done77  echo "  ❌ $label did not come up"78  return 179}80 81# ── 1. ollama ────────────────────────────────────────────────────────────────82echo "▶ ollama"83if curl -sf -m 2 http://localhost:11434/api/tags > /dev/null 2>&1; then84  echo "  ✅ already serving"85else86  [[ -x "$OLLAMA_BIN" ]] || { echo "  ❌ $OLLAMA_BIN missing — reinstall ollama"; exit 1; }87  spawn logs/ollama.log "$OLLAMA_BIN" serve88  wait_for http://localhost:11434/api/tags "serving on :11434" || { tail -20 logs/ollama.log; exit 1; }89fi90MODEL="${OLLAMA_MODEL:-llama3.2:3b}"91"$OLLAMA_BIN" list 2>/dev/null | grep -q "${MODEL%%:*}" \92  && echo "  ✅ $MODEL present" \93  || echo "  ⚠️  $MODEL not pulled — run: $OLLAMA_BIN pull $MODEL"94 95# ── 2. jem-agent ──────────────────────────────────────────────────────────96echo "▶ jem-agent"97if curl -sf -m 2 "http://localhost:$AGENT_PORT/health" > /dev/null 2>&1; then98  echo "  ✅ already up"99else100  # From the repo root, not inside the package: app.py imports its persona as a101  # package sibling (from .persona import …), which only resolves with the root102  # on sys.path. Same reason install-services.sh sets WorkingDirectory=$REPO.103  spawn logs/jem-agent.log \104    python3 -m flask --app jem_agent.app run --host 127.0.0.1 --port "$AGENT_PORT"105  # /health is deliberately cheap — probing /chat would queue a real generation106  # job per attempt and bury the model under abandoned work.107  wait_for "http://localhost:$AGENT_PORT/health" "up on :$AGENT_PORT" \108    || { tail -20 logs/jem-agent.log; exit 1; }109fi110 111# ── 3. site ──────────────────────────────────────────────────────────────────112echo "▶ site"113if curl -sf -m 2 "http://localhost:$PORT/health" > /dev/null 2>&1; then114  echo "  ✅ already up"115else116  spawn logs/server.log uvicorn server.main:app --host 0.0.0.0 --port "$PORT"117  wait_for "http://localhost:$PORT/health" "up on :$PORT" 150 \118    || { tail -20 logs/server.log; exit 1; }119fi120 121echo122echo "════════════════════════════════════════════════════════════"123echo "  Jem is live:  http://localhost:$PORT"124echo "  agent health:    $(curl -s -m 3 http://localhost:$AGENT_PORT/health)"125echo "════════════════════════════════════════════════════════════"126