#!/usr/bin/env bash # p2ctl.sh — run / stop Sanad Package 2 (Premium Communication) in dev mode # (no Docker), against the vendored engine in ./vendor. Self-contained: no sibling # Sanad/ checkout needed. # # ./p2ctl.sh start | stop | restart | status | logs [N] # # The conda env must have google-genai AND (for the LED mask) bleak==0.22.3 + Pillow. # Override env: SANAD_P2_PY, SANAD_DASHBOARD_PORT (8012), SANAD_AUDIO_PROFILE (builtin), # SANAD_DDS_INTERFACE (eth0), SANAD_MASK_DIR, SANAD_LICENSE / SANAD_PUBKEY. set -u PKG_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PY="${SANAD_P2_PY:-$HOME/miniconda3/envs/gemini_sdk/bin/python}" PORT="${SANAD_DASHBOARD_PORT:-8012}" APP="$PKG_DIR/app_p2.py" LOG="$PKG_DIR/p2.log" LIC="${SANAD_LICENSE:-$PKG_DIR/license/sanad.lic}"; [ -f "$LIC" ] || LIC="$PKG_DIR/license/sanad.lic.example" _start() { if pgrep -f app_p2.py >/dev/null 2>&1; then echo "P2 already running on :$PORT"; return 0; fi [ -f "$APP" ] || { echo "ERROR: $APP not found (deploy first)"; return 1; } cd "$PKG_DIR" export SANAD_APP_DIR="$PKG_DIR/vendor" \ SANAD_LICENSE="$LIC" \ SANAD_PUBKEY="${SANAD_PUBKEY:-$PKG_DIR/license/pubkey.ed25519}" \ SANAD_MASK_DIR="${SANAD_MASK_DIR:-$PKG_DIR/vendor/mask}" \ PYTHONPATH="$PKG_DIR/vendor" \ SANAD_DASHBOARD_PORT="$PORT" SANAD_DASHBOARD_HOST="0.0.0.0" \ SANAD_VOICE_BRAIN="gemini" \ SANAD_AUDIO_PROFILE="${SANAD_AUDIO_PROFILE:-builtin}" \ SANAD_DDS_INTERFACE="${SANAD_DDS_INTERFACE:-eth0}" \ PYTHONUNBUFFERED=1 [ -f /usr/lib/aarch64-linux-gnu/libgomp.so.1 ] && export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libgomp.so.1 nohup "$PY" "$APP" > "$LOG" 2>&1 & sleep 3 if pgrep -f app_p2.py >/dev/null 2>&1; then echo "P2 started -> http://$(hostname -I | awk '{print $1}'):$PORT (log: $LOG)" else echo "P2 failed to start. Last log lines:"; tail -20 "$LOG" fi } _stop() { pgrep -f app_p2.py >/dev/null 2>&1 || { echo "P2 was not running."; return 0; } pkill -f app_p2.py 2>/dev/null for _ in $(seq 1 8); do pgrep -f app_p2.py >/dev/null 2>&1 || break; sleep 1; done pgrep -f app_p2.py >/dev/null 2>&1 && pkill -9 -f app_p2.py 2>/dev/null sleep 1 pgrep -f app_p2.py >/dev/null 2>&1 && echo "P2 still running (could not kill)." || echo "P2 stopped." } _status() { if pgrep -af app_p2.py; then echo -n "health: "; curl -s --max-time 4 "http://127.0.0.1:$PORT/api/health"; echo; else echo "P2 not running."; fi; } _logs() { tail -n "${1:-40}" "$LOG" 2>/dev/null || echo "no log at $LOG"; } case "${1:-}" in start) _start ;; stop) _stop ;; restart) _stop; sleep 2; _start ;; status) _status ;; logs) shift; _logs "${1:-40}" ;; *) echo "usage: $0 {start|stop|restart|status|logs [N]}"; exit 2 ;; esac