Files
rpa_vision_v3/svc.sh
Dom d5deac3029 feat: replay visuel VLM-first, worker séparé, package Léa, AZERTY, sécurité HTTPS
Pipeline replay visuel :
- VLM-first : l'agent appelle Ollama directement pour trouver les éléments
- Template matching en fallback (seuil strict 0.90)
- Stop immédiat si élément non trouvé (pas de clic blind)
- Replay depuis session brute (/replay-session) sans attendre le VLM
- Vérification post-action (screenshot hash avant/après)
- Gestion des popups (Enter/Escape/Tab+Enter)

Worker VLM séparé :
- run_worker.py : process distinct du serveur HTTP
- Communication par fichiers (_worker_queue.txt + _replay_active.lock)
- Le serveur HTTP ne fait plus jamais de VLM → toujours réactif
- Service systemd rpa-worker.service

Capture clavier :
- raw_keys (vk + press/release) pour replay exact indépendant du layout
- Fix AZERTY : ToUnicodeEx + AltGr detection
- Enter capturé comme \n, Tab comme \t
- Filtrage modificateurs seuls (Ctrl/Alt/Shift parasites)
- Fusion text_input consécutifs, dédup key_combo

Sécurité & Internet :
- HTTPS Let's Encrypt (lea.labs + vwb.labs.laurinebazin.design)
- Token API fixe dans .env.local
- HTTP Basic Auth sur VWB
- Security headers (HSTS, CSP, nosniff)
- CORS domaines publics, plus de wildcard

Infrastructure :
- DPI awareness (SetProcessDpiAwareness) Python + Rust
- Métadonnées système (dpi_scale, window_bounds, monitors, os_theme)
- Template matching multi-scale [0.5, 2.0]
- Résolution dynamique (plus de hardcode 1920x1080)
- VLM prefill fix (47x speedup, 3.5s au lieu de 180s)

Modules :
- core/auth/ : credential vault (Fernet AES), TOTP (RFC 6238), auth handler
- core/federation/ : LearningPack export/import anonymisé, FAISS global
- deploy/ : package Léa (config.txt, Lea.bat, install.bat, LISEZMOI.txt)

UX :
- Filtrage OS (VWB + Chat montrent que les workflows de l'OS courant)
- Bibliothèque persistante (cache local + SQLite)
- Clustering hybride (titre fenêtre + DBSCAN)
- EdgeConstraints + PostConditions peuplés
- GraphBuilder compound actions (toutes les frappes)

Agent Rust :
- Token Bearer auth (network.rs)
- sysinfo.rs (DPI, résolution, window bounds via Win32 API)
- config.txt lu automatiquement
- Support Chrome/Brave/Firefox (pas que Edge)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 10:19:18 +01:00

612 lines
19 KiB
Bash
Executable File

#!/bin/bash
# RPA Vision V3 - Gestionnaire de Services Centralisé
# Supporte deux modes : systemd (défaut) et legacy (PID files)
#
# Usage: ./svc.sh [start|stop|status|restart|logs|enable|disable|install] [service_name|all]
#
# Exemples:
# ./svc.sh start all # Démarrer tout (via systemd)
# ./svc.sh start vwb # Démarrer VWB (backend + frontend)
# ./svc.sh stop streaming # Arrêter le streaming server
# ./svc.sh status # État de tous les services
# ./svc.sh restart dashboard # Redémarrer le dashboard
# ./svc.sh logs streaming # Voir les logs du streaming server
# ./svc.sh logs streaming -f # Suivre les logs en temps réel
# ./svc.sh enable # Activer le démarrage auto au boot
# ./svc.sh disable # Désactiver le démarrage auto au boot
# ./svc.sh install # Installer/recharger les fichiers systemd
# ./svc.sh --legacy start all # Mode legacy (PID files, sans systemd)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# Couleurs
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
# Répertoires
VENV_DIR="$SCRIPT_DIR/.venv"
LOG_DIR="$SCRIPT_DIR/logs"
PID_DIR="$SCRIPT_DIR/.pids"
SYSTEMD_DIR="$HOME/.config/systemd/user"
mkdir -p "$LOG_DIR" "$PID_DIR"
# Mode : systemd (défaut) ou legacy
USE_SYSTEMD=true
if [ "${1:-}" = "--legacy" ]; then
USE_SYSTEMD=false
shift
fi
# Carte des ports (source de vérité)
declare -A PORTS=(
[api]=8000
[dashboard]=5001
[vwb-backend]=5002
[monitoring]=5003
[agent-chat]=5004
[streaming]=5005
[worker]=5099
[vwb-frontend]=3002
)
# Mapping nom court -> nom service systemd
declare -A SYSTEMD_UNITS=(
[dashboard]="rpa-dashboard.service"
[vwb-backend]="rpa-vwb-backend.service"
[agent-chat]="rpa-agent-chat.service"
[streaming]="rpa-streaming.service"
[worker]="rpa-worker.service"
[vwb-frontend]="rpa-vwb-frontend.service"
)
# Services gérés par systemd (ceux qui ont un .service)
SYSTEMD_SERVICES="streaming worker agent-chat dashboard vwb-backend vwb-frontend"
# Tous les services connus
ALL_SERVICES="api dashboard vwb-backend monitoring agent-chat streaming worker vwb-frontend"
declare -A COMMANDS=(
[api]="$VENV_DIR/bin/python3 server/api_upload.py"
[dashboard]="$VENV_DIR/bin/python3 web_dashboard/app.py"
[vwb-backend]="cd $SCRIPT_DIR/visual_workflow_builder/backend && $VENV_DIR/bin/python3 app.py"
[monitoring]="$VENV_DIR/bin/python3 monitoring_server.py"
[agent-chat]="$VENV_DIR/bin/python3 -m agent_chat.app"
[streaming]="$VENV_DIR/bin/python3 -m agent_v0.server_v1.api_stream"
[worker]="$VENV_DIR/bin/python3 -m agent_v0.server_v1.run_worker"
[vwb-frontend]="cd $SCRIPT_DIR/visual_workflow_builder/frontend_v4 && npm run dev"
)
# Groupes de services
declare -A SVC_GROUPS=(
[vwb]="vwb-backend vwb-frontend"
[all]="api dashboard vwb-backend vwb-frontend"
[full]="api dashboard vwb-backend vwb-frontend monitoring agent-chat streaming worker"
[boot]="streaming worker agent-chat dashboard vwb-backend vwb-frontend"
)
# =============================================================================
# Fonctions systemd
# =============================================================================
systemd_start() {
local name=$1
local unit=${SYSTEMD_UNITS[$name]:-}
if [ -z "$unit" ]; then
# Pas de service systemd pour ce composant -> fallback legacy
echo -e " ${YELLOW}$name${NC}: pas de service systemd, lancement legacy..."
legacy_start "$name"
return
fi
echo -n " Démarrage $name... "
if systemctl --user start "$unit" 2>/dev/null; then
sleep 1
if systemctl --user is-active --quiet "$unit" 2>/dev/null; then
echo -e "${GREEN}OK${NC}"
else
echo -e "${RED}ECHEC${NC}"
echo " -> journalctl --user -u $unit --no-pager -n 10"
fi
else
echo -e "${RED}ECHEC${NC}"
echo " -> journalctl --user -u $unit --no-pager -n 10"
fi
}
systemd_stop() {
local name=$1
local unit=${SYSTEMD_UNITS[$name]:-}
if [ -z "$unit" ]; then
legacy_stop "$name"
return
fi
echo -n " Arrêt $name... "
systemctl --user stop "$unit" 2>/dev/null || true
echo -e "${GREEN}OK${NC}"
}
systemd_restart() {
local name=$1
local unit=${SYSTEMD_UNITS[$name]:-}
if [ -z "$unit" ]; then
legacy_stop "$name"
sleep 1
legacy_start "$name"
return
fi
echo -n " Redémarrage $name... "
if systemctl --user restart "$unit" 2>/dev/null; then
sleep 1
if systemctl --user is-active --quiet "$unit" 2>/dev/null; then
echo -e "${GREEN}OK${NC}"
else
echo -e "${RED}ECHEC${NC}"
fi
else
echo -e "${RED}ECHEC${NC}"
fi
}
systemd_status() {
echo ""
echo -e "${BOLD}Service Port Status Mode${NC}"
echo "─────────────────────────────────────────────────"
for name in $ALL_SERVICES; do
local port=${PORTS[$name]:-?}
local unit=${SYSTEMD_UNITS[$name]:-}
if [ -n "$unit" ]; then
# Service systemd
local state
state=$(systemctl --user is-active "$unit" 2>/dev/null) || state="inactive"
local mode="systemd"
if [ "$state" = "active" ]; then
printf " %-18s %-6s ${GREEN}%-14s${NC} %s\n" "$name" "$port" "$state" "$mode"
elif [ "$state" = "failed" ]; then
printf " %-18s %-6s ${RED}%-14s${NC} %s\n" "$name" "$port" "$state" "$mode"
else
# Vérifier si le port est quand même occupé (lancement legacy possible)
if ss -tlnp 2>/dev/null | grep -q ":${port} "; then
printf " %-18s %-6s ${YELLOW}%-14s${NC} %s\n" "$name" "$port" "running (ext)" "port"
else
printf " %-18s %-6s ${RED}%-14s${NC} %s\n" "$name" "$port" "$state" "$mode"
fi
fi
else
# Pas de service systemd -> vérifier PID/port
if is_running_legacy "$name"; then
printf " %-18s %-6s ${GREEN}%-14s${NC} %s\n" "$name" "$port" "running" "legacy"
else
printf " %-18s %-6s ${RED}%-14s${NC} %s\n" "$name" "$port" "stopped" "legacy"
fi
fi
done
echo ""
# Afficher l'état du target
local target_state
target_state=$(systemctl --user is-active "rpa-vision.target" 2>/dev/null) || target_state="inactive"
local target_enabled
target_enabled=$(systemctl --user is-enabled "rpa-vision.target" 2>/dev/null) || target_enabled="disabled"
echo -e "${BOLD}Target rpa-vision.target:${NC} $target_state (boot: $target_enabled)"
echo ""
}
systemd_logs() {
local name=$1
shift
local unit=${SYSTEMD_UNITS[$name]:-}
if [ -z "$unit" ]; then
# Fallback vers fichier log
if [ -f "$LOG_DIR/${name}.log" ]; then
tail -50 "$LOG_DIR/${name}.log"
else
echo "Pas de logs pour $name"
fi
return
fi
# Passer les arguments restants a journalctl (ex: -f pour follow)
journalctl --user -u "$unit" --no-pager -n 50 "$@"
}
# =============================================================================
# Fonctions legacy (PID files)
# =============================================================================
is_running_legacy() {
local name=$1
local port=${PORTS[$name]:-}
local pid_file="$PID_DIR/${name}.pid"
if [ -f "$pid_file" ]; then
local pid
pid=$(cat "$pid_file")
if kill -0 "$pid" 2>/dev/null; then
return 0
fi
rm -f "$pid_file"
fi
if [ -n "$port" ] && ss -tlnp 2>/dev/null | grep -q ":${port} "; then
return 0
fi
return 1
}
legacy_start() {
local name=$1
local port=${PORTS[$name]:-}
local cmd=${COMMANDS[$name]:-}
if [ -z "$cmd" ]; then
echo -e "${RED}Service inconnu: $name${NC}"
return 1
fi
if is_running_legacy "$name"; then
echo -e " ${YELLOW}$name${NC} deja en cours (port $port)"
return 0
fi
if [ -n "$port" ] && ss -tlnp 2>/dev/null | grep -q ":${port} "; then
echo -e " ${RED}Port $port occupe !${NC} Liberez-le avec: fuser -k ${port}/tcp"
return 1
fi
echo -n " Démarrage $name (port $port)... "
bash -c "$cmd" > "$LOG_DIR/${name}.log" 2>&1 &
local pid=$!
echo "$pid" > "$PID_DIR/${name}.pid"
local max_wait=15
if [ "$name" = "vwb-frontend" ]; then
max_wait=60
fi
for i in $(seq 1 $max_wait); do
if ! kill -0 "$pid" 2>/dev/null; then
echo -e "${RED}ECHEC${NC} (process mort)"
echo " -> tail $LOG_DIR/${name}.log"
tail -5 "$LOG_DIR/${name}.log" 2>/dev/null || true
rm -f "$PID_DIR/${name}.pid"
return 1
fi
if [ -n "$port" ] && curl -s "http://localhost:$port" > /dev/null 2>&1; then
echo -e "${GREEN}OK${NC} (PID $pid)"
return 0
fi
sleep 1
done
if kill -0 "$pid" 2>/dev/null; then
echo -e "${GREEN}OK${NC} (PID $pid, port non verifie)"
return 0
fi
echo -e "${RED}TIMEOUT${NC}"
return 1
}
legacy_stop() {
local name=$1
local pid_file="$PID_DIR/${name}.pid"
local port=${PORTS[$name]:-}
if [ -f "$pid_file" ]; then
local pid
pid=$(cat "$pid_file")
if kill -0 "$pid" 2>/dev/null; then
kill "$pid" 2>/dev/null
for i in $(seq 1 5); do
kill -0 "$pid" 2>/dev/null || break
sleep 1
done
kill -9 "$pid" 2>/dev/null || true
fi
rm -f "$pid_file"
fi
if [ -n "$port" ]; then
fuser -k "${port}/tcp" 2>/dev/null || true
fi
echo -e " ${name}: ${GREEN}arrete${NC}"
}
# =============================================================================
# Fonctions utilitaires
# =============================================================================
resolve_services() {
local input=$1
if [ -n "${SVC_GROUPS[$input]:-}" ]; then
echo "${SVC_GROUPS[$input]}"
else
echo "$input"
fi
}
do_install() {
echo -e "${CYAN}${BOLD}Installation des services systemd...${NC}"
echo ""
# Vérifier que les fichiers existent
local missing=false
for unit in rpa-streaming.service rpa-worker.service rpa-agent-chat.service rpa-dashboard.service rpa-vwb-backend.service rpa-vwb-frontend.service rpa-vision.target; do
if [ -f "$SYSTEMD_DIR/$unit" ]; then
echo -e " ${GREEN}OK${NC} $unit"
else
echo -e " ${RED}MANQUANT${NC} $unit"
missing=true
fi
done
if [ "$missing" = true ]; then
echo ""
echo -e "${RED}Fichiers manquants dans $SYSTEMD_DIR${NC}"
echo "Les fichiers .service doivent etre dans ~/.config/systemd/user/"
return 1
fi
echo ""
# Recharger systemd
echo -n " Rechargement systemd... "
systemctl --user daemon-reload
echo -e "${GREEN}OK${NC}"
# Vérifier le lingering
if loginctl show-user "$(whoami)" 2>/dev/null | grep -q "Linger=yes"; then
echo -e " Lingering: ${GREEN}actif${NC}"
else
echo -n " Activation du lingering... "
loginctl enable-linger "$(whoami)" 2>/dev/null || {
echo -e "${YELLOW}necessaire en root : sudo loginctl enable-linger $(whoami)${NC}"
}
echo -e "${GREEN}OK${NC}"
fi
echo ""
echo -e "${GREEN}Installation terminee.${NC}"
echo " -> ./svc.sh enable # Activer le demarrage au boot"
echo " -> ./svc.sh start boot # Démarrer maintenant"
}
do_enable() {
echo -e "${CYAN}${BOLD}Activation du demarrage automatique au boot...${NC}"
systemctl --user daemon-reload
systemctl --user enable rpa-vision.target
for unit in rpa-streaming.service rpa-worker.service rpa-agent-chat.service rpa-dashboard.service rpa-vwb-backend.service rpa-vwb-frontend.service; do
systemctl --user enable "$unit" 2>/dev/null
echo -e " ${GREEN}OK${NC} $unit"
done
echo ""
echo -e "${GREEN}Les services demarreront automatiquement au boot.${NC}"
}
do_disable() {
echo -e "${YELLOW}${BOLD}Desactivation du demarrage automatique...${NC}"
systemctl --user disable rpa-vision.target 2>/dev/null || true
for unit in rpa-streaming.service rpa-worker.service rpa-agent-chat.service rpa-dashboard.service rpa-vwb-backend.service rpa-vwb-frontend.service; do
systemctl --user disable "$unit" 2>/dev/null || true
echo -e " ${GREEN}OK${NC} $unit"
done
echo ""
echo -e "${YELLOW}Les services ne demarreront plus au boot.${NC}"
}
show_help() {
echo -e "${CYAN}${BOLD}RPA Vision V3 - Gestionnaire de Services${NC}"
echo ""
echo -e "${BOLD}Usage:${NC} $0 [ACTION] [TARGET]"
echo ""
echo -e "${BOLD}Actions:${NC}"
echo " start [svc|group] Demarrer un service ou un groupe"
echo " stop [svc|group] Arreter un service ou un groupe"
echo " restart [svc|group] Redemarrer un service ou un groupe"
echo " status Etat de tous les services"
echo " logs [svc] [-f] Voir les logs (ajouter -f pour suivre)"
echo " install Installer/recharger les fichiers systemd"
echo " enable Activer le demarrage auto au boot"
echo " disable Desactiver le demarrage auto au boot"
echo ""
echo -e "${BOLD}Services:${NC}"
echo " streaming Streaming Server HTTP (port 5005)"
echo " worker VLM Worker GPU (process séparé)"
echo " agent-chat Agent Chat (port 5004)"
echo " dashboard Web Dashboard (port 5001)"
echo " vwb-backend VWB Backend Flask (port 5002)"
echo " vwb-frontend VWB Frontend Vite (port 3002)"
echo " api API Server (port 8000) [legacy uniquement]"
echo " monitoring Monitoring (port 5003) [legacy uniquement]"
echo ""
echo -e "${BOLD}Groupes:${NC}"
echo " boot Services systemd (streaming, worker, chat, dashboard, vwb)"
echo " vwb VWB backend + frontend"
echo " all Core (api, dashboard, vwb)"
echo " full Tous les services"
echo ""
echo -e "${BOLD}Options:${NC}"
echo " --legacy Forcer le mode legacy (PID files au lieu de systemd)"
echo ""
echo -e "${BOLD}Exemples:${NC}"
echo " $0 start boot # Demarrer les 5 services systemd"
echo " $0 stop boot # Arreter les 5 services systemd"
echo " $0 restart streaming # Redemarrer le streaming server"
echo " $0 logs streaming -f # Suivre les logs du streaming"
echo " $0 status # Voir l'etat de tout"
echo " $0 install # Installer les services systemd"
echo " $0 enable # Activer le boot automatique"
echo ""
}
# =============================================================================
# Main
# =============================================================================
ACTION="${1:-status}"
TARGET="${2:-}"
# Fonctions dispatching
dispatch_start() {
local svc=$1
if [ "$USE_SYSTEMD" = true ]; then
systemd_start "$svc"
else
legacy_start "$svc"
fi
}
dispatch_stop() {
local svc=$1
if [ "$USE_SYSTEMD" = true ]; then
systemd_stop "$svc"
else
legacy_stop "$svc"
fi
}
dispatch_restart() {
local svc=$1
if [ "$USE_SYSTEMD" = true ]; then
systemd_restart "$svc"
else
legacy_stop "$svc"
sleep 1
legacy_start "$svc"
fi
}
case "$ACTION" in
start)
if [ -z "$TARGET" ]; then
echo "Usage: $0 start [service|boot|all|full|vwb]"
exit 1
fi
echo -e "${CYAN}${BOLD}Demarrage des services...${NC}"
# Activer le venv pour le mode legacy
if [ "$USE_SYSTEMD" = false ] && [ -d "$VENV_DIR" ]; then
source "$VENV_DIR/bin/activate"
fi
services=$(resolve_services "$TARGET")
for svc in $services; do
dispatch_start "$svc"
done
echo ""
echo -e "${GREEN}${BOLD}URLs d'acces :${NC}"
for svc in $services; do
port=${PORTS[$svc]:-}
if [ -n "$port" ]; then
echo -e " $svc: ${BLUE}http://localhost:$port${NC}"
fi
done
;;
stop)
if [ -z "$TARGET" ]; then
TARGET="full"
fi
echo -e "${YELLOW}${BOLD}Arret des services...${NC}"
services=$(resolve_services "$TARGET")
for svc in $services; do
dispatch_stop "$svc"
done
;;
restart)
if [ -z "$TARGET" ]; then
echo "Usage: $0 restart [service|boot|all|full|vwb]"
exit 1
fi
echo -e "${CYAN}${BOLD}Redemarrage...${NC}"
services=$(resolve_services "$TARGET")
for svc in $services; do
dispatch_restart "$svc"
done
;;
status)
echo -e "${CYAN}${BOLD}RPA Vision V3 - Etat des services${NC}"
if [ "$USE_SYSTEMD" = true ]; then
systemd_status
else
# Status legacy
echo ""
echo -e "${BOLD}Service Port Status${NC}"
echo "──────────────────────────────────────"
for name in $ALL_SERVICES; do
port=${PORTS[$name]:-?}
if is_running_legacy "$name"; then
pid=""
if [ -f "$PID_DIR/${name}.pid" ]; then
pid=" (PID $(cat "$PID_DIR/${name}.pid"))"
fi
printf " %-18s %-6s ${GREEN}running${NC}%s\n" "$name" "$port" "$pid"
else
printf " %-18s %-6s ${RED}stopped${NC}\n" "$name" "$port"
fi
done
echo ""
fi
;;
logs)
if [ -z "$TARGET" ]; then
echo "Usage: $0 logs [service] [-f]"
echo "Services: streaming, agent-chat, dashboard, vwb-backend, vwb-frontend"
exit 1
fi
# Passer les arguments supplementaires (ex: -f)
shift 2 2>/dev/null || true
systemd_logs "$TARGET" "$@"
;;
install)
do_install
;;
enable)
do_enable
;;
disable)
do_disable
;;
-h|--help|help)
show_help
;;
*)
show_help
exit 1
;;
esac