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:
Dom
2026-01-29 11:23:51 +01:00
parent 21bfa3b337
commit a27b74cf22
1595 changed files with 412691 additions and 400 deletions

271
test_capture_fixed.py Normal file
View File

@@ -0,0 +1,271 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Test de Capture d'Écran Corrigé - RPA Vision V3
Auteur : Dom, Alice, Kiro - 8 janvier 2026
Version corrigée pour les problèmes de threading avec MSS.
"""
import cv2
import numpy as np
import mss
import base64
import io
from PIL import Image
import threading
import time
import logging
class FixedRealScreenCaptureService:
"""
Service de capture d'écran avec correction des problèmes de threading
"""
def __init__(self):
self.is_capturing = False
self.capture_thread = None
self.current_screenshot = None
self.detected_elements = []
self.capture_interval = 1.0
self.monitors = []
self.selected_monitor = 0
# Initialiser MSS dans le thread principal
self._init_mss()
def _init_mss(self):
"""Initialise MSS dans le thread principal"""
try:
with mss.mss() as sct:
self.monitors = sct.monitors
print(f"Détecté {len(self.monitors)} moniteurs")
for i, monitor in enumerate(self.monitors):
print(f"Moniteur {i}: {monitor}")
except Exception as e:
print(f"Erreur lors de l'initialisation MSS: {e}")
self.monitors = [{"top": 0, "left": 0, "width": 1920, "height": 1080}]
def get_monitors(self):
"""Retourne la liste des moniteurs disponibles"""
return [
{
"id": i,
"width": monitor.get("width", 0),
"height": monitor.get("height", 0),
"top": monitor.get("top", 0),
"left": monitor.get("left", 0)
}
for i, monitor in enumerate(self.monitors)
]
def select_monitor(self, monitor_id: int) -> bool:
"""Sélectionne le moniteur à capturer"""
if 0 <= monitor_id < len(self.monitors):
self.selected_monitor = monitor_id
print(f"Moniteur sélectionné: {monitor_id}")
return True
return False
def start_capture(self, interval: float = 1.0) -> bool:
"""Démarre la capture d'écran en temps réel"""
if self.is_capturing:
print("Capture déjà en cours")
return False
self.capture_interval = interval
self.is_capturing = True
# Démarrer le thread de capture
self.capture_thread = threading.Thread(target=self._capture_loop, daemon=True)
self.capture_thread.start()
print(f"Capture démarrée (intervalle: {interval}s)")
return True
def stop_capture(self) -> bool:
"""Arrête la capture d'écran"""
if not self.is_capturing:
return False
self.is_capturing = False
if self.capture_thread and self.capture_thread.is_alive():
self.capture_thread.join(timeout=2.0)
print("Capture arrêtée")
return True
def _capture_loop(self):
"""Boucle principale de capture avec MSS local au thread"""
# Créer une instance MSS locale au thread
try:
with mss.mss() as sct:
while self.is_capturing:
try:
# Capturer l'écran
screenshot = self._capture_screen_with_sct(sct)
if screenshot is not None:
self.current_screenshot = screenshot
print(f"Screenshot capturé: {screenshot.shape}")
# Attendre avant la prochaine capture
time.sleep(self.capture_interval)
except Exception as e:
print(f"Erreur dans la boucle de capture: {e}")
time.sleep(1.0)
except Exception as e:
print(f"Erreur lors de l'initialisation MSS dans le thread: {e}")
def _capture_screen_with_sct(self, sct):
"""Capture l'écran avec une instance MSS donnée"""
try:
if self.selected_monitor >= len(self.monitors):
self.selected_monitor = 0
monitor = self.monitors[self.selected_monitor]
# Capturer avec MSS
screenshot = sct.grab(monitor)
# Convertir en array numpy
img_array = np.array(screenshot)
# Convertir BGRA vers BGR (OpenCV)
if img_array.shape[2] == 4:
img_array = cv2.cvtColor(img_array, cv2.COLOR_BGRA2BGR)
return img_array
except Exception as e:
print(f"Erreur lors de la capture d'écran: {e}")
return None
def capture_single_screenshot(self):
"""Capture une seule image (pour test synchrone)"""
try:
with mss.mss() as sct:
return self._capture_screen_with_sct(sct)
except Exception as e:
print(f"Erreur lors de la capture unique: {e}")
return None
def get_current_screenshot_base64(self):
"""Retourne la capture d'écran actuelle en base64"""
if self.current_screenshot is None:
return None
try:
# Convertir en PIL Image
if len(self.current_screenshot.shape) == 3:
# BGR vers RGB
rgb_image = cv2.cvtColor(self.current_screenshot, cv2.COLOR_BGR2RGB)
pil_image = Image.fromarray(rgb_image)
else:
pil_image = Image.fromarray(self.current_screenshot)
# Redimensionner pour l'affichage web
max_width = 1200
if pil_image.width > max_width:
ratio = max_width / pil_image.width
new_height = int(pil_image.height * ratio)
pil_image = pil_image.resize((max_width, new_height), Image.Resampling.LANCZOS)
# Convertir en base64
buffer = io.BytesIO()
pil_image.save(buffer, format='JPEG', quality=85)
img_base64 = base64.b64encode(buffer.getvalue()).decode('utf-8')
return f"data:image/jpeg;base64,{img_base64}"
except Exception as e:
print(f"Erreur lors de la conversion base64: {e}")
return None
def get_status(self):
"""Retourne le statut du service"""
return {
"is_capturing": self.is_capturing,
"selected_monitor": self.selected_monitor,
"monitors_count": len(self.monitors),
"capture_interval": self.capture_interval,
"elements_detected": len(self.detected_elements),
"has_screenshot": self.current_screenshot is not None
}
def cleanup(self):
"""Nettoie les ressources"""
self.stop_capture()
def test_service_fixe():
"""Test du service corrigé"""
print("=== Test du Service de Capture Corrigé ===")
service = FixedRealScreenCaptureService()
try:
# 1. Test des moniteurs
monitors = service.get_monitors()
print(f"✅ Moniteurs détectés: {len(monitors)}")
# 2. Test de capture unique (synchrone)
print("Test de capture unique...")
screenshot = service.capture_single_screenshot()
if screenshot is not None:
print(f"✅ Capture unique réussie: {screenshot.shape}")
# Convertir en base64 pour test
service.current_screenshot = screenshot
base64_img = service.get_current_screenshot_base64()
if base64_img:
print(f"✅ Conversion base64 réussie: {len(base64_img)} caractères")
else:
print("❌ Échec conversion base64")
else:
print("❌ Échec capture unique")
# 3. Test de capture en continu
print("\nTest de capture en continu...")
success = service.start_capture(interval=1.0)
print(f"✅ Démarrage capture: {success}")
# Attendre quelques captures
print("Attente de 5 secondes...")
time.sleep(5.0)
# Vérifier le statut
status = service.get_status()
print(f"✅ Statut: {status}")
# Obtenir une capture
screenshot_b64 = service.get_current_screenshot_base64()
if screenshot_b64:
print(f"✅ Screenshot en continu: {len(screenshot_b64)} caractères")
else:
print("❌ Aucun screenshot en continu")
# Arrêter la capture
success = service.stop_capture()
print(f"✅ Arrêt capture: {success}")
return screenshot is not None
except Exception as e:
print(f"❌ Erreur lors du test: {e}")
import traceback
traceback.print_exc()
return False
finally:
service.cleanup()
if __name__ == "__main__":
print("🔍 Test du Service de Capture d'Écran Corrigé")
print("=" * 50)
if test_service_fixe():
print("\n🎉 Service de capture entièrement fonctionnel !")
else:
print("\n❌ Problème persistant avec le service de capture")