v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- Frontend v4 accessible sur réseau local (192.168.1.40) - Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard) - Ollama GPU fonctionnel - Self-healing interactif - Dashboard confiance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
356
diagnostic_et_correction_vwb.py
Executable file
356
diagnostic_et_correction_vwb.py
Executable file
@@ -0,0 +1,356 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Diagnostic et Correction VWB
|
||||
Auteur : Dom, Alice, Kiro - 8 janvier 2026
|
||||
|
||||
Ce script diagnostique et corrige les problèmes du Visual Workflow Builder.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import time
|
||||
import requests
|
||||
import signal
|
||||
import os
|
||||
import sys
|
||||
from typing import Optional, Tuple
|
||||
|
||||
class Colors:
|
||||
RED = '\033[0;31m'
|
||||
GREEN = '\033[0;32m'
|
||||
YELLOW = '\033[1;33m'
|
||||
BLUE = '\033[0;34m'
|
||||
PURPLE = '\033[0;35m'
|
||||
CYAN = '\033[0;36m'
|
||||
BOLD = '\033[1m'
|
||||
NC = '\033[0m'
|
||||
|
||||
class VWBDiagnostic:
|
||||
def __init__(self):
|
||||
self.original_dir = os.getcwd()
|
||||
self.vwb_dir = os.path.join(self.original_dir, "visual_workflow_builder")
|
||||
self.backend_dir = os.path.join(self.vwb_dir, "backend")
|
||||
self.frontend_dir = os.path.join(self.vwb_dir, "frontend")
|
||||
|
||||
def print_header(self):
|
||||
"""Affiche l'en-tête du diagnostic"""
|
||||
print(f"{Colors.PURPLE}{Colors.BOLD}")
|
||||
print("╔════════════════════════════════════════════════════════════╗")
|
||||
print("║ 🔧 Diagnostic et Correction VWB ║")
|
||||
print("║ Auteur : Dom, Alice, Kiro - 8 janvier 2026 ║")
|
||||
print("╚════════════════════════════════════════════════════════════╝")
|
||||
print(f"{Colors.NC}")
|
||||
|
||||
def check_directories(self) -> bool:
|
||||
"""Vérifie que les répertoires existent"""
|
||||
print(f"\n{Colors.BLUE}[1/6] Vérification des répertoires{Colors.NC}")
|
||||
print("=" * 50)
|
||||
|
||||
success = True
|
||||
directories = [
|
||||
(self.vwb_dir, "Visual Workflow Builder"),
|
||||
(self.backend_dir, "Backend"),
|
||||
(self.frontend_dir, "Frontend")
|
||||
]
|
||||
|
||||
for dir_path, name in directories:
|
||||
if os.path.exists(dir_path):
|
||||
print(f"{Colors.GREEN}✅ {name} : {dir_path}{Colors.NC}")
|
||||
else:
|
||||
print(f"{Colors.RED}❌ {name} manquant : {dir_path}{Colors.NC}")
|
||||
success = False
|
||||
|
||||
return success
|
||||
|
||||
def check_dependencies(self) -> bool:
|
||||
"""Vérifie les dépendances"""
|
||||
print(f"\n{Colors.BLUE}[2/6] Vérification des dépendances{Colors.NC}")
|
||||
print("=" * 50)
|
||||
|
||||
success = True
|
||||
|
||||
# Vérifier Python et l'environnement virtuel
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["source", "venv_v3/bin/activate", "&&", "python3", "--version"],
|
||||
shell=True, capture_output=True, text=True
|
||||
)
|
||||
if result.returncode == 0:
|
||||
print(f"{Colors.GREEN}✅ Python avec venv_v3 : {result.stdout.strip()}{Colors.NC}")
|
||||
else:
|
||||
print(f"{Colors.RED}❌ Problème avec l'environnement virtuel{Colors.NC}")
|
||||
success = False
|
||||
except Exception as e:
|
||||
print(f"{Colors.RED}❌ Erreur Python : {e}{Colors.NC}")
|
||||
success = False
|
||||
|
||||
# Vérifier Node.js
|
||||
try:
|
||||
result = subprocess.run(["node", "--version"], capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
print(f"{Colors.GREEN}✅ Node.js : {result.stdout.strip()}{Colors.NC}")
|
||||
else:
|
||||
print(f"{Colors.RED}❌ Node.js non trouvé{Colors.NC}")
|
||||
success = False
|
||||
except Exception as e:
|
||||
print(f"{Colors.RED}❌ Erreur Node.js : {e}{Colors.NC}")
|
||||
success = False
|
||||
|
||||
return success
|
||||
|
||||
def cleanup_ports(self) -> bool:
|
||||
"""Nettoie les ports utilisés"""
|
||||
print(f"\n{Colors.BLUE}[3/6] Nettoyage des ports{Colors.NC}")
|
||||
print("=" * 50)
|
||||
|
||||
ports = [3000, 5002]
|
||||
cleaned = False
|
||||
|
||||
for port in ports:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
f"lsof -ti:{port} | xargs -r kill -9",
|
||||
shell=True, capture_output=True
|
||||
)
|
||||
if result.returncode == 0:
|
||||
print(f"{Colors.YELLOW}🧹 Port {port} nettoyé{Colors.NC}")
|
||||
cleaned = True
|
||||
else:
|
||||
print(f"{Colors.GREEN}✅ Port {port} libre{Colors.NC}")
|
||||
except Exception as e:
|
||||
print(f"{Colors.YELLOW}⚠️ Erreur nettoyage port {port} : {e}{Colors.NC}")
|
||||
|
||||
if cleaned:
|
||||
time.sleep(2) # Attendre que les ports se libèrent
|
||||
|
||||
return True
|
||||
|
||||
def start_backend(self) -> Tuple[bool, Optional[subprocess.Popen]]:
|
||||
"""Démarre le backend"""
|
||||
print(f"\n{Colors.BLUE}[4/6] Démarrage du backend{Colors.NC}")
|
||||
print("=" * 50)
|
||||
|
||||
try:
|
||||
os.chdir(self.backend_dir)
|
||||
|
||||
# Commande pour démarrer le backend
|
||||
cmd = [
|
||||
"bash", "-c",
|
||||
"source ../../../venv_v3/bin/activate && python3 app.py"
|
||||
]
|
||||
|
||||
print(f"{Colors.CYAN}🚀 Lancement du backend Flask...{Colors.NC}")
|
||||
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
preexec_fn=os.setsid
|
||||
)
|
||||
|
||||
# Attendre que le backend soit prêt
|
||||
start_time = time.time()
|
||||
timeout = 30
|
||||
|
||||
while time.time() - start_time < timeout:
|
||||
try:
|
||||
response = requests.get("http://localhost:5002/health", timeout=2)
|
||||
if response.status_code == 200:
|
||||
print(f"{Colors.GREEN}✅ Backend prêt sur http://localhost:5002{Colors.NC}")
|
||||
os.chdir(self.original_dir)
|
||||
return True, process
|
||||
except requests.exceptions.RequestException:
|
||||
pass
|
||||
|
||||
# Vérifier si le processus est encore en vie
|
||||
if process.poll() is not None:
|
||||
stdout, stderr = process.communicate()
|
||||
print(f"{Colors.RED}❌ Le backend s'est arrêté{Colors.NC}")
|
||||
print(f"STDERR: {stderr.decode()[-500:]}") # Derniers 500 caractères
|
||||
os.chdir(self.original_dir)
|
||||
return False, None
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
print(f"{Colors.RED}❌ Timeout: Le backend n'a pas démarré en {timeout}s{Colors.NC}")
|
||||
os.chdir(self.original_dir)
|
||||
return False, process
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Colors.RED}❌ Erreur lors du démarrage du backend : {e}{Colors.NC}")
|
||||
os.chdir(self.original_dir)
|
||||
return False, None
|
||||
|
||||
def start_frontend(self) -> Tuple[bool, Optional[subprocess.Popen]]:
|
||||
"""Démarre le frontend"""
|
||||
print(f"\n{Colors.BLUE}[5/6] Démarrage du frontend{Colors.NC}")
|
||||
print("=" * 50)
|
||||
|
||||
try:
|
||||
os.chdir(self.frontend_dir)
|
||||
|
||||
# Vérifier si node_modules existe
|
||||
if not os.path.exists("node_modules"):
|
||||
print(f"{Colors.YELLOW}📦 Installation des dépendances npm...{Colors.NC}")
|
||||
result = subprocess.run(["npm", "install"], capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
print(f"{Colors.RED}❌ Erreur lors de l'installation npm{Colors.NC}")
|
||||
os.chdir(self.original_dir)
|
||||
return False, None
|
||||
|
||||
print(f"{Colors.CYAN}🎨 Lancement du serveur React...{Colors.NC}")
|
||||
|
||||
# Démarrer le frontend
|
||||
env = os.environ.copy()
|
||||
env['BROWSER'] = 'none' # Ne pas ouvrir le navigateur automatiquement
|
||||
|
||||
process = subprocess.Popen(
|
||||
["npm", "start"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
env=env,
|
||||
preexec_fn=os.setsid
|
||||
)
|
||||
|
||||
# Attendre que le frontend soit prêt
|
||||
start_time = time.time()
|
||||
timeout = 60
|
||||
|
||||
while time.time() - start_time < timeout:
|
||||
try:
|
||||
response = requests.get("http://localhost:3000", timeout=2)
|
||||
if response.status_code in [200, 404]: # 404 est OK pour React
|
||||
print(f"{Colors.GREEN}✅ Frontend prêt sur http://localhost:3000{Colors.NC}")
|
||||
os.chdir(self.original_dir)
|
||||
return True, process
|
||||
except requests.exceptions.RequestException:
|
||||
pass
|
||||
|
||||
# Vérifier si le processus est encore en vie
|
||||
if process.poll() is not None:
|
||||
stdout, stderr = process.communicate()
|
||||
print(f"{Colors.RED}❌ Le frontend s'est arrêté{Colors.NC}")
|
||||
print(f"STDERR: {stderr.decode()[-500:]}")
|
||||
os.chdir(self.original_dir)
|
||||
return False, None
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
print(f"{Colors.RED}❌ Timeout: Le frontend n'a pas démarré en {timeout}s{Colors.NC}")
|
||||
os.chdir(self.original_dir)
|
||||
return False, process
|
||||
|
||||
except Exception as e:
|
||||
print(f"{Colors.RED}❌ Erreur lors du démarrage du frontend : {e}{Colors.NC}")
|
||||
os.chdir(self.original_dir)
|
||||
return False, None
|
||||
|
||||
def test_integration(self) -> bool:
|
||||
"""Teste l'intégration frontend-backend"""
|
||||
print(f"\n{Colors.BLUE}[6/6] Test d'intégration{Colors.NC}")
|
||||
print("=" * 50)
|
||||
|
||||
success = True
|
||||
|
||||
# Tester les endpoints du backend
|
||||
backend_endpoints = [
|
||||
("/health", "Health Check"),
|
||||
("/api/workflows", "Workflows API"),
|
||||
("/api/node-types", "Node Types API")
|
||||
]
|
||||
|
||||
for endpoint, description in backend_endpoints:
|
||||
try:
|
||||
response = requests.get(f"http://localhost:5002{endpoint}", timeout=5)
|
||||
if response.status_code in [200, 404, 405]:
|
||||
print(f"{Colors.GREEN}✅ {description}: {endpoint} (status: {response.status_code}){Colors.NC}")
|
||||
else:
|
||||
print(f"{Colors.YELLOW}⚠️ {description}: {endpoint} (status: {response.status_code}){Colors.NC}")
|
||||
except Exception as e:
|
||||
print(f"{Colors.RED}❌ {description}: {endpoint} - Erreur: {e}{Colors.NC}")
|
||||
success = False
|
||||
|
||||
# Tester le frontend
|
||||
try:
|
||||
response = requests.get("http://localhost:3000", timeout=5)
|
||||
if response.status_code == 200:
|
||||
print(f"{Colors.GREEN}✅ Frontend accessible{Colors.NC}")
|
||||
else:
|
||||
print(f"{Colors.YELLOW}⚠️ Frontend status: {response.status_code}{Colors.NC}")
|
||||
except Exception as e:
|
||||
print(f"{Colors.RED}❌ Frontend non accessible : {e}{Colors.NC}")
|
||||
success = False
|
||||
|
||||
return success
|
||||
|
||||
def run_diagnostic(self) -> bool:
|
||||
"""Exécute le diagnostic complet"""
|
||||
self.print_header()
|
||||
|
||||
# Étapes du diagnostic
|
||||
if not self.check_directories():
|
||||
return False
|
||||
|
||||
if not self.check_dependencies():
|
||||
return False
|
||||
|
||||
self.cleanup_ports()
|
||||
|
||||
backend_success, backend_process = self.start_backend()
|
||||
if not backend_success:
|
||||
return False
|
||||
|
||||
frontend_success, frontend_process = self.start_frontend()
|
||||
if not frontend_success:
|
||||
if backend_process:
|
||||
try:
|
||||
os.killpg(os.getpgid(backend_process.pid), signal.SIGTERM)
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
integration_success = self.test_integration()
|
||||
|
||||
# Afficher le résumé
|
||||
print(f"\n{Colors.PURPLE}{Colors.BOLD}📊 RÉSUMÉ DU DIAGNOSTIC{Colors.NC}")
|
||||
print("=" * 60)
|
||||
|
||||
if backend_success and frontend_success and integration_success:
|
||||
print(f"{Colors.GREEN}{Colors.BOLD}🎉 VISUAL WORKFLOW BUILDER OPÉRATIONNEL !{Colors.NC}")
|
||||
print(f"\n{Colors.CYAN}URLs d'accès :{Colors.NC}")
|
||||
print(f" Frontend: http://localhost:3000")
|
||||
print(f" Backend: http://localhost:5002")
|
||||
print(f"\n{Colors.YELLOW}Les services restent en cours d'exécution.{Colors.NC}")
|
||||
print(f"{Colors.YELLOW}Appuyez sur Ctrl+C pour les arrêter.{Colors.NC}")
|
||||
|
||||
# Garder les services en vie
|
||||
try:
|
||||
while True:
|
||||
time.sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
print(f"\n{Colors.YELLOW}🛑 Arrêt des services...{Colors.NC}")
|
||||
if backend_process:
|
||||
try:
|
||||
os.killpg(os.getpgid(backend_process.pid), signal.SIGTERM)
|
||||
except:
|
||||
pass
|
||||
if frontend_process:
|
||||
try:
|
||||
os.killpg(os.getpgid(frontend_process.pid), signal.SIGTERM)
|
||||
except:
|
||||
pass
|
||||
print(f"{Colors.GREEN}✓ Services arrêtés{Colors.NC}")
|
||||
|
||||
return True
|
||||
else:
|
||||
print(f"{Colors.RED}{Colors.BOLD}❌ PROBLÈMES DÉTECTÉS{Colors.NC}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Fonction principale"""
|
||||
diagnostic = VWBDiagnostic()
|
||||
success = diagnostic.run_diagnostic()
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user