microclimate-x / scripts /start_demo.sh
W1nd5pac's picture
Deploy 2026-05-20T06:52:08Z β€” 11e81c5
4eefabb verified
#!/usr/bin/env bash
# ──────────────────────────────────────────────────────────────────────────
# scripts/start_demo.sh β€” one-shot demo for supervisor showcase
#
# What it does:
# 1. Kills any previous demo processes (uvicorn / cloudflared)
# 2. Starts FastAPI on 127.0.0.1:8181 (clean env, isolated from other venvs)
# 3. Waits until /api/health returns 200
# 4. Starts a Cloudflare Quick Tunnel and prints the public URL
# 5. On Ctrl-C, cleanly shuts down both processes
#
# Usage:
# ./scripts/start_demo.sh
#
# Prereqs (already done by the agent on this machine):
# - .venv/ Python 3.9 venv with all deps installed
# - .local/bin/cloudflared (macOS arm64, downloaded from GitHub releases)
# - models/rf_model.pkl (217 MB, real ERA5-trained Random Forest)
# ──────────────────────────────────────────────────────────────────────────
set -euo pipefail
PORT="${PORT:-8181}"
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
LOG_DIR="${TMPDIR:-/tmp}"
UVICORN_LOG="$LOG_DIR/mcx-uvicorn.log"
TUNNEL_LOG="$LOG_DIR/mcx-tunnel.log"
cd "$ROOT"
# ── 1. Kill leftovers from a previous run ────────────────────────────────
pkill -f "uvicorn backend.main:app.*--port $PORT" 2>/dev/null || true
pkill -f "cloudflared tunnel --url http://127.0.0.1:$PORT" 2>/dev/null || true
sleep 1
# ── 2. Start FastAPI in the background ───────────────────────────────────
echo "β–Ά Starting FastAPI on http://127.0.0.1:$PORT …"
env -u PYTHONPATH -u VIRTUAL_ENV -u PYTHONHOME \
".venv/bin/python" -m uvicorn backend.main:app \
--host 127.0.0.1 --port "$PORT" \
> "$UVICORN_LOG" 2>&1 &
UVICORN_PID=$!
cleanup() {
echo
echo "β–Ά Shutting down (uvicorn=$UVICORN_PID, cloudflared=${CF_PID:-n/a})…"
[[ -n "${CF_PID:-}" ]] && kill "$CF_PID" 2>/dev/null || true
kill "$UVICORN_PID" 2>/dev/null || true
wait 2>/dev/null || true
echo "βœ“ Stopped. Logs preserved at:"
echo " $UVICORN_LOG"
echo " $TUNNEL_LOG"
}
trap cleanup EXIT INT TERM
# ── 3. Wait for /api/health ──────────────────────────────────────────────
printf " waiting for ML model load "
for _ in $(seq 1 40); do
if curl -sf --max-time 1 --noproxy '*' "http://127.0.0.1:$PORT/api/health" >/dev/null 2>&1; then
echo " βœ“"
break
fi
printf "."
sleep 1
done
if ! curl -sf --max-time 1 --noproxy '*' "http://127.0.0.1:$PORT/api/health" >/dev/null 2>&1; then
echo
echo "❌ FastAPI did not become ready in 40 s. Last log lines:"
tail -20 "$UVICORN_LOG"
exit 1
fi
HEALTH=$(curl -s --noproxy '*' "http://127.0.0.1:$PORT/api/health")
ML_LOADED=$(echo "$HEALTH" | python3 -c 'import json,sys; print(json.load(sys.stdin)["ml_loaded"])' 2>/dev/null || echo "?")
echo " ML model loaded: $ML_LOADED (response: ${HEALTH:0:80}…)"
echo
# ── 4. Start Cloudflare Quick Tunnel ─────────────────────────────────────
echo "β–Ά Opening Cloudflare Quick Tunnel …"
echo " (your public URL will print below as 'https://*.trycloudflare.com')"
echo " ─────────────────────────────────────────────────────────────────"
# Run cloudflared in foreground so the user sees the URL and can Ctrl-C.
./.local/bin/cloudflared tunnel --url "http://127.0.0.1:$PORT" 2>&1 | tee "$TUNNEL_LOG" &
CF_PID=$!
wait "$CF_PID"