- 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>
296 lines
11 KiB
Python
296 lines
11 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Diagnostic et réparation complète du backend VWB
|
||
Auteur : Dom, Alice, Kiro - 8 janvier 2026
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import subprocess
|
||
import requests
|
||
import time
|
||
import json
|
||
import psutil
|
||
from pathlib import Path
|
||
|
||
class DiagnosticBackend:
|
||
"""Classe pour diagnostiquer et réparer le backend VWB"""
|
||
|
||
def __init__(self):
|
||
self.backend_port = 5002
|
||
self.backend_url = f'http://localhost:{self.backend_port}'
|
||
self.backend_path = 'visual_workflow_builder/backend'
|
||
self.venv_path = './venv_v3'
|
||
|
||
def verifier_environnement(self):
|
||
"""Vérifier l'environnement Python et les dépendances"""
|
||
print("🔍 Vérification de l'environnement...")
|
||
|
||
# Vérifier Python
|
||
try:
|
||
python_version = sys.version_info
|
||
print(f" ✅ Python {python_version.major}.{python_version.minor}.{python_version.micro}")
|
||
except Exception as e:
|
||
print(f" ❌ Problème Python: {e}")
|
||
return False
|
||
|
||
# Vérifier l'environnement virtuel
|
||
if os.path.exists(self.venv_path):
|
||
print(f" ✅ Environnement virtuel trouvé: {self.venv_path}")
|
||
else:
|
||
print(f" ❌ Environnement virtuel manquant: {self.venv_path}")
|
||
return False
|
||
|
||
# Vérifier les dépendances critiques
|
||
dependances_critiques = ['flask', 'flask_cors', 'flask_socketio', 'requests']
|
||
for dep in dependances_critiques:
|
||
try:
|
||
__import__(dep)
|
||
print(f" ✅ Dépendance {dep} disponible")
|
||
except ImportError:
|
||
print(f" ❌ Dépendance {dep} manquante")
|
||
return False
|
||
|
||
return True
|
||
|
||
def nettoyer_processus_existants(self):
|
||
"""Nettoyer les processus backend existants"""
|
||
print("🧹 Nettoyage des processus existants...")
|
||
|
||
processus_tues = 0
|
||
for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
|
||
try:
|
||
cmdline = ' '.join(proc.info['cmdline'] or [])
|
||
if 'visual_workflow_builder/backend/app.py' in cmdline:
|
||
print(f" 🔪 Arrêt du processus PID {proc.info['pid']}")
|
||
proc.terminate()
|
||
processus_tues += 1
|
||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||
continue
|
||
|
||
if processus_tues > 0:
|
||
print(f" ✅ {processus_tues} processus arrêtés")
|
||
time.sleep(2) # Attendre que les processus se terminent
|
||
else:
|
||
print(" ℹ️ Aucun processus backend en cours")
|
||
|
||
return True
|
||
|
||
def verifier_fichiers_backend(self):
|
||
"""Vérifier l'intégrité des fichiers backend"""
|
||
print("📁 Vérification des fichiers backend...")
|
||
|
||
fichiers_critiques = [
|
||
'visual_workflow_builder/backend/app.py',
|
||
'visual_workflow_builder/backend/api/__init__.py',
|
||
'visual_workflow_builder/backend/api/workflows.py',
|
||
'visual_workflow_builder/backend/api/screen_capture.py',
|
||
]
|
||
|
||
for fichier in fichiers_critiques:
|
||
if os.path.exists(fichier):
|
||
taille = os.path.getsize(fichier)
|
||
print(f" ✅ {fichier} ({taille} bytes)")
|
||
else:
|
||
print(f" ❌ {fichier} manquant")
|
||
return False
|
||
|
||
return True
|
||
|
||
def demarrer_backend(self):
|
||
"""Démarrer le backend en mode diagnostic"""
|
||
print("🚀 Démarrage du backend...")
|
||
|
||
# Commande pour démarrer le backend
|
||
cmd = [
|
||
f'{self.venv_path}/bin/python',
|
||
'visual_workflow_builder/backend/app.py'
|
||
]
|
||
|
||
try:
|
||
# Démarrer en arrière-plan
|
||
process = subprocess.Popen(
|
||
cmd,
|
||
stdout=subprocess.PIPE,
|
||
stderr=subprocess.PIPE,
|
||
cwd='.',
|
||
env=dict(os.environ, FLASK_ENV='development')
|
||
)
|
||
|
||
print(f" 🔄 Processus démarré (PID: {process.pid})")
|
||
|
||
# Attendre que le serveur démarre
|
||
for tentative in range(10):
|
||
try:
|
||
response = requests.get(f'{self.backend_url}/health', timeout=2)
|
||
if response.status_code == 200:
|
||
print(f" ✅ Backend démarré avec succès sur le port {self.backend_port}")
|
||
return process
|
||
except requests.exceptions.ConnectionError:
|
||
pass
|
||
|
||
print(f" ⏳ Tentative {tentative + 1}/10...")
|
||
time.sleep(2)
|
||
|
||
# Si on arrive ici, le démarrage a échoué
|
||
stdout, stderr = process.communicate(timeout=5)
|
||
print(f" ❌ Échec du démarrage")
|
||
print(f" 📝 STDOUT: {stdout.decode()}")
|
||
print(f" 📝 STDERR: {stderr.decode()}")
|
||
return None
|
||
|
||
except Exception as e:
|
||
print(f" ❌ Erreur lors du démarrage: {e}")
|
||
return None
|
||
|
||
def tester_endpoints(self):
|
||
"""Tester tous les endpoints critiques"""
|
||
print("🧪 Test des endpoints critiques...")
|
||
|
||
endpoints = [
|
||
('/health', 'GET', None),
|
||
('/api/workflows/', 'GET', None),
|
||
('/api/screen-capture/', 'POST', {}),
|
||
]
|
||
|
||
resultats = {}
|
||
for endpoint, methode, data in endpoints:
|
||
try:
|
||
url = f'{self.backend_url}{endpoint}'
|
||
if methode == 'GET':
|
||
response = requests.get(url, timeout=10)
|
||
elif methode == 'POST':
|
||
response = requests.post(url, json=data, timeout=10)
|
||
|
||
resultats[endpoint] = {
|
||
'status': response.status_code,
|
||
'success': response.status_code < 400
|
||
}
|
||
|
||
status_icon = "✅" if response.status_code < 400 else "❌"
|
||
print(f" {status_icon} {methode} {endpoint}: {response.status_code}")
|
||
|
||
except Exception as e:
|
||
resultats[endpoint] = {
|
||
'status': 'ERREUR',
|
||
'success': False,
|
||
'error': str(e)
|
||
}
|
||
print(f" ❌ {methode} {endpoint}: ERREUR - {e}")
|
||
|
||
return resultats
|
||
|
||
def generer_rapport(self, resultats_tests):
|
||
"""Générer un rapport de diagnostic"""
|
||
print("\n" + "=" * 60)
|
||
print("📊 RAPPORT DE DIAGNOSTIC BACKEND")
|
||
print("=" * 60)
|
||
|
||
total_tests = len(resultats_tests)
|
||
tests_reussis = sum(1 for r in resultats_tests.values() if r['success'])
|
||
taux_reussite = (tests_reussis / total_tests) * 100 if total_tests > 0 else 0
|
||
|
||
print(f"📈 Taux de réussite: {tests_reussis}/{total_tests} ({taux_reussite:.1f}%)")
|
||
|
||
if taux_reussite == 100:
|
||
print("🎉 Backend entièrement fonctionnel !")
|
||
statut = "EXCELLENT"
|
||
elif taux_reussite >= 70:
|
||
print("⚠️ Backend partiellement fonctionnel")
|
||
statut = "ACCEPTABLE"
|
||
else:
|
||
print("🚨 Backend défaillant")
|
||
statut = "CRITIQUE"
|
||
|
||
# Sauvegarder le rapport
|
||
rapport = {
|
||
'timestamp': time.time(),
|
||
'statut': statut,
|
||
'taux_reussite': taux_reussite,
|
||
'tests': resultats_tests,
|
||
'recommandations': self.generer_recommandations(resultats_tests)
|
||
}
|
||
|
||
with open('diagnostic_backend_rapport.json', 'w', encoding='utf-8') as f:
|
||
json.dump(rapport, f, indent=2, ensure_ascii=False)
|
||
|
||
print(f"📄 Rapport sauvegardé: diagnostic_backend_rapport.json")
|
||
return statut
|
||
|
||
def generer_recommandations(self, resultats_tests):
|
||
"""Générer des recommandations basées sur les résultats"""
|
||
recommandations = []
|
||
|
||
for endpoint, resultat in resultats_tests.items():
|
||
if not resultat['success']:
|
||
if endpoint == '/health':
|
||
recommandations.append("Vérifier la configuration Flask de base")
|
||
elif endpoint == '/api/workflows/':
|
||
recommandations.append("Vérifier la base de données et les modèles")
|
||
elif endpoint == '/api/screen-capture/':
|
||
recommandations.append("Vérifier les dépendances de capture d'écran")
|
||
|
||
if not recommandations:
|
||
recommandations.append("Backend fonctionnel - aucune action requise")
|
||
|
||
return recommandations
|
||
|
||
def executer_diagnostic_complet(self):
|
||
"""Exécuter le diagnostic complet"""
|
||
print("🏥 DIAGNOSTIC COMPLET DU BACKEND VWB")
|
||
print("=" * 50)
|
||
|
||
# Étape 1: Vérifier l'environnement
|
||
if not self.verifier_environnement():
|
||
print("❌ Environnement défaillant - arrêt du diagnostic")
|
||
return False
|
||
|
||
# Étape 2: Nettoyer les processus existants
|
||
self.nettoyer_processus_existants()
|
||
|
||
# Étape 3: Vérifier les fichiers
|
||
if not self.verifier_fichiers_backend():
|
||
print("❌ Fichiers backend manquants - arrêt du diagnostic")
|
||
return False
|
||
|
||
# Étape 4: Démarrer le backend
|
||
process = self.demarrer_backend()
|
||
if not process:
|
||
print("❌ Impossible de démarrer le backend")
|
||
return False
|
||
|
||
try:
|
||
# Étape 5: Tester les endpoints
|
||
resultats_tests = self.tester_endpoints()
|
||
|
||
# Étape 6: Générer le rapport
|
||
statut = self.generer_rapport(resultats_tests)
|
||
|
||
return statut in ['EXCELLENT', 'ACCEPTABLE']
|
||
|
||
finally:
|
||
# Nettoyer le processus de test
|
||
if process and process.poll() is None:
|
||
print("🧹 Nettoyage du processus de test...")
|
||
process.terminate()
|
||
|
||
def main():
|
||
"""Fonction principale"""
|
||
diagnostic = DiagnosticBackend()
|
||
|
||
try:
|
||
succes = diagnostic.executer_diagnostic_complet()
|
||
exit_code = 0 if succes else 1
|
||
|
||
print(f"\n🏁 Diagnostic terminé (code de sortie: {exit_code})")
|
||
return exit_code
|
||
|
||
except KeyboardInterrupt:
|
||
print("\n⚠️ Diagnostic interrompu par l'utilisateur")
|
||
return 2
|
||
except Exception as e:
|
||
print(f"\n❌ Erreur critique lors du diagnostic: {e}")
|
||
return 3
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main()) |