spb/ka4 Public
ka4 — explorateur structuré du web québécois (édition agressive, Groupe KA). Crawling concurrent, Claude Sonnet+Haiku, Firecrawl/Scrapfly, graphe de connaissances.
Python 97.8%
Shell 2.2%
1#!/usr/bin/env bash2# Author: Simon-Pierre Boucher3# Contact: contact@spboucher.ai4#5# Déploie ka4 (version agressive/concurrente) sur un node macOS du cluster (défaut : M4M36).6# Cohabite avec ka2 sur le même node : port + services + domaine + web-addr ngrok distincts.7# - venv + dépendances8# - 3 services launchd résilients : com.ka4.web / com.ka4.bot / com.ka4.ngrok9# - ngrok --url=https://www.ka4.bot -> uvicorn 127.0.0.1:8899 (inspection sur :4041)10#11# Usage : bash deploy/deploy.sh [NODE] [PORT] [DOMAIN]12set -euo pipefail1314NODE="${1:-M4M36}"15PORT="${2:-8899}"16DOMAIN="${3:-www.ka4.bot}"17REMOTE_DIR="~/cluster-projects/ka4"18NGROK="/opt/homebrew/bin/ngrok"1920echo "==> Déploiement de ka4 sur ${NODE} (port ${PORT}, domaine ${DOMAIN})"2122rsync -az --delete \23 --exclude '.venv' --exclude '.git' --exclude '*.db' --exclude '*.db-*' \24 --exclude '__pycache__' --exclude 'exports' --exclude 'logs' \25 ./ "${NODE}:${REMOTE_DIR}/"2627ssh "${NODE}" DOMAIN="${DOMAIN}" PORT="${PORT}" NGROK="${NGROK}" 'bash -s' <<'REMOTE'28set -euo pipefail29DIR="$HOME/cluster-projects/ka4"30cd "$DIR"3132echo "--> venv + dépendances"33python3 -m venv .venv34./.venv/bin/python -m pip install -q --upgrade pip35./.venv/bin/python -m pip install -q -r requirements.txt3637PY="$DIR/.venv/bin/python"38UVICORN="$DIR/.venv/bin/uvicorn"39LOGS="$DIR/logs"; mkdir -p "$LOGS"40LA="$HOME/Library/LaunchAgents"; mkdir -p "$LA"4142write_plist () {43 local label="$1" ; shift44 local plist="$LA/${label}.plist"45 {46 echo '<?xml version="1.0" encoding="UTF-8"?>'47 echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'48 echo '<plist version="1.0"><dict>'49 echo " <key>Label</key><string>${label}</string>"50 echo ' <key>ProgramArguments</key><array>'51 for a in "$@"; do echo " <string>${a}</string>"; done52 echo ' </array>'53 echo " <key>WorkingDirectory</key><string>${DIR}</string>"54 echo ' <key>RunAtLoad</key><true/>'55 echo ' <key>KeepAlive</key><true/>'56 echo " <key>StandardOutPath</key><string>${LOGS}/${label}.out.log</string>"57 echo " <key>StandardErrorPath</key><string>${LOGS}/${label}.err.log</string>"58 echo ' <key>EnvironmentVariables</key><dict>'59 echo " <key>PATH</key><string>/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>"60 echo ' </dict>'61 echo '</dict></plist>'62 } > "$plist"63 launchctl unload "$plist" 2>/dev/null || true64 launchctl load "$plist"65 echo " launchd chargé: ${label}"66}6768# config ngrok dédiée : inspection sur :4041 (KA2 occupe déjà :4040 sur ce node)69NGCONF="$DIR/ngrok-ka4.yml"70printf 'version: "3"\nagent:\n web_addr: localhost:4041\n' > "$NGCONF"71DEFCONF="$HOME/Library/Application Support/ngrok/ngrok.yml"7273echo "--> services launchd (com.ka4.*)"74write_plist "com.ka4.web" "$UVICORN" "web.app:app" "--host" "127.0.0.1" "--port" "${PORT}"75write_plist "com.ka4.bot" "$PY" "main.py" "run" "--daily-budget" "3000" "--cycle-delay" "8" "--queue-batch" "24" "--session-minutes" "15"76write_plist "com.ka4.ngrok" "$NGROK" "http" "--url=https://${DOMAIN}" "--config" "$DEFCONF" "--config" "$NGCONF" "${PORT}"7778echo "--> session : 15 min dès le déploiement (bouton « Continuer » pour +15 min)"79"$PY" - <<'PYSET'80import time81from src.config import config82from src.storage import Store83s = Store(config.db_path)84s.set_setting("run_until", str(time.time() + 15 * 60))85s.set_setting("paused", "0")86s.close()87print("run_until = maintenant + 15 min")88PYSET8990sleep 691echo "--> healthcheck local"92curl -s "http://127.0.0.1:${PORT}/health" || echo "(web pas encore prêt)"93echo94echo "--> tunnel ngrok (inspection :4041)"95curl -s http://127.0.0.1:4041/api/tunnels 2>/dev/null | head -c 400 || echo "(api ngrok non prête)"96echo97REMOTE9899echo100echo "==> Déploiement terminé. Dashboard ka4 : https://${DOMAIN}"101