nitdaa / start.sh
AI Agent
Fix Kuzu graph write lock error and suppress pip/transformer warnings
5ed03b8
Raw
History Blame Contribute Delete
6.94 kB
#!/bin/bash
# start.sh β€” HealthExpert service orchestrator
#
# Usage:
# bash start.sh # Full GPU mode (default desktop)
# bash start.sh -hf # HuggingFace low-resource mode (CPU, small models)
# bash start.sh -hf -noadmin # HF mode with admin controls disabled (public endpoint)
#
# Environment variables set by this script:
# HF_MODE=1 β†’ Activates low-resource CPU path in config.py, nvidia_llm.py, embed_llm.py
# ADMIN_MODE=0 β†’ Disables admin API routes and hides UI admin controls
# GEN_MODEL_ID β†’ Overridden for HF mode (microsoft/Phi-3.5-mini-instruct)
# EMBED_MODEL_ID β†’ Overridden for HF mode (bge-small-en-v1.5)
# NOTE: Do NOT use 'set -e' here β€” background processes exiting would abort the script.
# ── Parse CLI arguments ────────────────────────────────────────────────────────
HF_MODE_FLAG=0
ADMIN_MODE_FLAG=1
for arg in "$@"; do
case "$arg" in
-hf|--hf) HF_MODE_FLAG=1 ;;
-noadmin|--noadmin) ADMIN_MODE_FLAG=0 ;;
*) ;;
esac
done
# ── Export mode flags ──────────────────────────────────────────────────────────
export HF_MODE=$HF_MODE_FLAG
export ADMIN_MODE=$ADMIN_MODE_FLAG
# ── Mode-specific overrides ────────────────────────────────────────────────────
if [ "$HF_MODE_FLAG" -eq 1 ]; then
export GEN_MODEL_ID="Jackrong/Qwen3.5-2B-Claude-4.6-Opus-Reasoning-Distilled-GGUF"
export GEN_MODEL_FILENAME="Qwen3.5-2B.Q4_K_M.gguf"
export EMBED_MODEL_ID="BAAI/bge-small-en-v1.5"
export LLM_MAX_TOKENS=2048
export EMBEDDING_BATCH_SIZE=2
export TOP_K_VECTOR=3
export TOP_K_GRAPH=3
export EMBED_FP16=false # CPU only β€” FP16 unsupported
export TORCH_COMPILE_SKIP=1 # Skip torch.compile() on CPU (no benefit, adds 30s startup)
# Crucial to prevent CPU thrashing and PyTorch OOM when multiple threads query
export OMP_NUM_THREADS=2
export MKL_NUM_THREADS=2
export OPENBLAS_NUM_THREADS=2
MODE_LABEL="HuggingFace / CPU"
else
export GEN_MODEL_ID="${GEN_MODEL_ID:-Jackrong/Qwen3.5-2B-Claude-4.6-Opus-Reasoning-Distilled-GGUF}"
export GEN_MODEL_FILENAME="${GEN_MODEL_FILENAME:-Qwen3.5-2B.Q4_K_M.gguf}"
export EMBED_MODEL_ID="${EMBED_MODEL_ID:-BAAI/bge-small-en-v1.5}"
MODE_LABEL="GPU (Desktop)"
fi
if [ "$ADMIN_MODE_FLAG" -eq 0 ]; then
ADMIN_LABEL="Admin: DISABLED (public mode)"
else
ADMIN_LABEL="Admin: ENABLED"
fi
# ── Startup banner ─────────────────────────────────────────────────────────────
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " HealthExpert β€” Starting"
echo " Mode : $MODE_LABEL"
echo " $ADMIN_LABEL"
echo " Gen LLM : $GEN_MODEL_ID"
echo " Embed : $EMBED_MODEL_ID"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# ── Auto-cleanup: kill any stale services from a previous run ──────────────────
# This prevents "Address already in use" errors after a crash or incomplete shutdown.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
CLEANUP_SCRIPT="$SCRIPT_DIR/scripts/cleanup.sh"
if [ -f "$CLEANUP_SCRIPT" ]; then
echo "[pre-flight] Cleaning up stale services on ports 8002, 8003, 5050, 7860..."
bash "$CLEANUP_SCRIPT" --quiet
echo "[pre-flight] Cleanup done."
else
# Inline fallback if cleanup.sh is not present
echo "[pre-flight] Freeing ports 8002, 8003, 5050, 7860..."
for port in 8002 8003 5050 7860; do
if command -v fuser &>/dev/null; then
fuser -k "${port}/tcp" 2>/dev/null || true
else
lsof -t -i:"${port}" 2>/dev/null | xargs kill -9 2>/dev/null || true
fi
done
# Also kill by process name for orphaned workers
pkill -9 -f "agents/nvidia_llm.py" 2>/dev/null || true
pkill -9 -f "agents/embed_llm.py" 2>/dev/null || true
sleep 2
echo "[pre-flight] Done."
fi
# ── Uninstall conflicting torchaudio to prevent OSError ─────────────────────────
echo "[pre-flight] Removing torchaudio to prevent transformers loading issues on HF..."
export TRANSFORMERS_NO_ADVISORY_WARNINGS=1
python -m pip uninstall -y torchaudio --root-user-action=ignore || true
# ── Start embed_llm on port 8003 ──────────────────────────────────────────────
echo "[1/3] Starting embed_llm (port 8003)..."
python agents/embed_llm.py &
EMBED_PID=$!
echo " embed_llm PID: $EMBED_PID"
# ── Start nvidia_llm on port 8002 ────────────────────────────────────────────────
echo "[2/3] Starting nvidia_llm (port 8002)..."
python agents/nvidia_llm.py &
GEN_PID=$!
echo " nvidia_llm PID: $GEN_PID"
# ── Wait for microservices to initialise ──────────────────────────────────────
echo "Waiting for LLM microservices to initialise..."
if [ "$HF_MODE_FLAG" -eq 1 ]; then
# CPU model load takes 30-60s; wait longer
sleep 30
else
sleep 5
fi
# ── Start Flask web application ───────────────────────────────────────────────
echo "[3/3] Starting Flask web application (port ${PORT:-7860})..."
python app.py &
APP_PID=$!
echo " app.py PID: $APP_PID"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " All services started."
echo " Access: http://0.0.0.0:${PORT:-7860}"
echo " PIDs : embed=$EMBED_PID gen=$GEN_PID app=$APP_PID"
echo " Stop : bash scripts/cleanup.sh"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# ── Wait for any process to exit; clean up the rest ───────────────────────────
wait -n 2>/dev/null || wait
echo "[shutdown] A service exited. Running cleanup..."
bash "$CLEANUP_SCRIPT" --quiet 2>/dev/null || true
exit 0