spb/ka2 Public
ka2 — explorateur structuré du web québécois (édition légère, Groupe KA). Bot scraper+IA → graphe de connaissances. Claude Haiku + Firecrawl/Scrapfly.
Python 98.1%
Shell 1.9%
1#!/usr/bin/env bash2# Author: Simon-Pierre Boucher3# Contact: contact@spboucher.ai4#5# Déploie ka2 sur un node macOS du cluster (défaut : M4M36) :6# - venv + dépendances7# - 3 services launchd résilients (KeepAlive) : web, bot long terme, tunnel ngrok8# - tunnel ngrok --url=https://www.ka2.bot -> uvicorn 127.0.0.1:87999#10# Usage (depuis le laptop) : bash deploy/deploy.sh [NODE] [PORT] [DOMAIN]11set -euo pipefail1213NODE="${1:-M4M36}"14PORT="${2:-8799}"15DOMAIN="${3:-www.ka2.bot}"16REMOTE_DIR="~/cluster-projects/ka2"17NGROK="/opt/homebrew/bin/ngrok"1819echo "==> Déploiement de ka2 sur ${NODE} (port ${PORT}, domaine ${DOMAIN})"2021# 1) Synchro du code (sans venv/db/git)22rsync -az --delete \23 --exclude '.venv' --exclude '.git' --exclude '*.db' --exclude '*.db-*' \24 --exclude '__pycache__' --exclude 'exports' \25 ./ "${NODE}:${REMOTE_DIR}/"2627# 2) Configuration distante (venv, deps, launchd)28ssh "${NODE}" DOMAIN="${DOMAIN}" PORT="${PORT}" NGROK="${NGROK}" 'bash -s' <<'REMOTE'29set -euo pipefail30DIR="$HOME/cluster-projects/ka2"31cd "$DIR"3233echo "--> venv + dépendances"34python3 -m venv .venv35./.venv/bin/python -m pip install -q --upgrade pip36./.venv/bin/python -m pip install -q -r requirements.txt3738PY="$DIR/.venv/bin/python"39UVICORN="$DIR/.venv/bin/uvicorn"40LOGS="$DIR/logs"; mkdir -p "$LOGS"41LA="$HOME/Library/LaunchAgents"; mkdir -p "$LA"4243write_plist () {44 local label="$1" ; shift45 local plist="$LA/${label}.plist"46 {47 echo '<?xml version="1.0" encoding="UTF-8"?>'48 echo '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'49 echo '<plist version="1.0"><dict>'50 echo " <key>Label</key><string>${label}</string>"51 echo ' <key>ProgramArguments</key><array>'52 for a in "$@"; do echo " <string>${a}</string>"; done53 echo ' </array>'54 echo " <key>WorkingDirectory</key><string>${DIR}</string>"55 echo ' <key>RunAtLoad</key><true/>'56 echo ' <key>KeepAlive</key><true/>'57 echo " <key>StandardOutPath</key><string>${LOGS}/${label}.out.log</string>"58 echo " <key>StandardErrorPath</key><string>${LOGS}/${label}.err.log</string>"59 echo ' <key>EnvironmentVariables</key><dict>'60 echo " <key>PATH</key><string>/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>"61 echo ' </dict>'62 echo '</dict></plist>'63 } > "$plist"64 launchctl unload "$plist" 2>/dev/null || true65 launchctl load "$plist"66 echo " launchd chargé: ${label}"67}6869echo "--> services launchd"70write_plist "com.ka2.web" "$UVICORN" "web.app:app" "--host" "127.0.0.1" "--port" "${PORT}"71write_plist "com.ka2.bot" "$PY" "main.py" "run" "--daily-budget" "800" "--cycle-delay" "20"72write_plist "com.ka2.ngrok" "$NGROK" "http" "--url=https://${DOMAIN}" "${PORT}"7374echo "--> session : 15 min à partir de maintenant (bouton « Continuer » pour +15 min)"75"$PY" - <<'PYSET'76import time77from src.config import config78from src.storage import Store79s = Store(config.db_path)80s.set_setting("run_until", str(time.time() + 15 * 60))81s.set_setting("paused", "0")82s.close()83print("run_until = maintenant + 15 min")84PYSET8586sleep 587echo "--> healthcheck local"88curl -s "http://127.0.0.1:${PORT}/health" || echo "(web pas encore prêt)"89echo90echo "--> tunnel ngrok"91curl -s http://127.0.0.1:4040/api/tunnels 2>/dev/null | head -c 400 || echo "(api ngrok non prête)"92echo93REMOTE9495echo96echo "==> Déploiement terminé. Dashboard : https://${DOMAIN}"97