348 lines
11 KiB
Python
348 lines
11 KiB
Python
"""
|
|
Intégration Orchestrator ↔ GUI
|
|
Module pour connecter l'Orchestrator à l'interface graphique
|
|
"""
|
|
|
|
import logging
|
|
from typing import Optional
|
|
from .human_logger import HumanLogger
|
|
from .signals import GUISignals
|
|
from .improved_gui import ImprovedGUI
|
|
|
|
|
|
class OrchestratorGUIBridge:
|
|
"""
|
|
Pont entre l'Orchestrator et la GUI.
|
|
|
|
Facilite la communication bidirectionnelle:
|
|
- Orchestrator → GUI : Logs, stats, changements de mode
|
|
- GUI → Orchestrator : Commandes (start, stop, pause)
|
|
|
|
Attributes:
|
|
orchestrator: Instance de l'Orchestrator
|
|
gui: Instance de l'ImprovedGUI
|
|
human_logger: Instance du HumanLogger
|
|
signals: Signaux Qt pour communication
|
|
"""
|
|
|
|
def __init__(self, orchestrator, gui: Optional[ImprovedGUI] = None):
|
|
"""
|
|
Initialise le pont Orchestrator-GUI.
|
|
|
|
Args:
|
|
orchestrator: Instance de l'Orchestrator
|
|
gui: Instance de l'ImprovedGUI (optionnel, sera créée si None)
|
|
"""
|
|
self.logger = logging.getLogger(__name__)
|
|
self.orchestrator = orchestrator
|
|
|
|
# Créer ou utiliser la GUI fournie
|
|
if gui is None:
|
|
self.gui = ImprovedGUI(orchestrator)
|
|
else:
|
|
self.gui = gui
|
|
|
|
# Créer le HumanLogger
|
|
self.human_logger = HumanLogger()
|
|
|
|
# Utiliser les signaux de la GUI
|
|
self.signals = self.gui.signals
|
|
|
|
# Connecter les signaux
|
|
self._connect_gui_to_orchestrator()
|
|
self._inject_logging_into_orchestrator()
|
|
|
|
self.logger.info("OrchestratorGUIBridge initialisé")
|
|
|
|
def _connect_gui_to_orchestrator(self):
|
|
"""Connecte les signaux de la GUI à l'Orchestrator."""
|
|
# Boutons de contrôle
|
|
self.gui.start_requested.connect(self._on_start_requested)
|
|
self.gui.stop_requested.connect(self._on_stop_requested)
|
|
self.gui.pause_requested.connect(self._on_pause_requested)
|
|
|
|
self.logger.info("Signaux GUI → Orchestrator connectés")
|
|
|
|
def _inject_logging_into_orchestrator(self):
|
|
"""Injecte le système de logging dans l'Orchestrator."""
|
|
# Ajouter les attributs nécessaires à l'Orchestrator
|
|
self.orchestrator.human_logger = self.human_logger
|
|
self.orchestrator.gui_signals = self.signals
|
|
|
|
# Ajouter des méthodes helper à l'Orchestrator
|
|
self.orchestrator.log_to_gui = self.log_to_gui
|
|
self.orchestrator.update_gui_stats = self.update_gui_stats
|
|
self.orchestrator.change_mode_gui = self.change_mode_gui
|
|
|
|
self.logger.info("Logging injecté dans l'Orchestrator")
|
|
|
|
def _on_start_requested(self):
|
|
"""Gestionnaire de demande de démarrage."""
|
|
self.logger.info("Démarrage demandé depuis la GUI")
|
|
if hasattr(self.orchestrator, 'start'):
|
|
try:
|
|
self.orchestrator.start()
|
|
self.signals.emit_status_change(True)
|
|
self.log_to_gui("👀", "Système démarré en mode Observation", "success")
|
|
except Exception as e:
|
|
self.logger.error(f"Erreur au démarrage: {e}")
|
|
self.log_to_gui("❌", f"Erreur au démarrage: {str(e)}", "error")
|
|
|
|
def _on_stop_requested(self):
|
|
"""Gestionnaire de demande d'arrêt."""
|
|
self.logger.info("Arrêt demandé depuis la GUI")
|
|
if hasattr(self.orchestrator, 'stop'):
|
|
try:
|
|
self.orchestrator.stop()
|
|
self.signals.emit_status_change(False)
|
|
self.log_to_gui("⏹", "Système arrêté", "info")
|
|
except Exception as e:
|
|
self.logger.error(f"Erreur à l'arrêt: {e}")
|
|
self.log_to_gui("❌", f"Erreur à l'arrêt: {str(e)}", "error")
|
|
|
|
def _on_pause_requested(self):
|
|
"""Gestionnaire de demande de pause."""
|
|
self.logger.info("Pause demandée depuis la GUI")
|
|
if hasattr(self.orchestrator, 'pause'):
|
|
try:
|
|
self.orchestrator.pause()
|
|
is_paused = getattr(self.orchestrator, 'is_paused', False)
|
|
if is_paused:
|
|
self.log_to_gui("⏸", "Système en pause", "warning")
|
|
else:
|
|
self.log_to_gui("▶", "Système repris", "success")
|
|
except Exception as e:
|
|
self.logger.error(f"Erreur à la pause: {e}")
|
|
self.log_to_gui("❌", f"Erreur à la pause: {str(e)}", "error")
|
|
|
|
def log_to_gui(self, emoji: str, message: str, level: str = "info"):
|
|
"""
|
|
Envoie un log à la GUI.
|
|
|
|
Args:
|
|
emoji: Emoji à afficher
|
|
message: Message de log
|
|
level: Niveau du log ('info', 'success', 'warning', 'error')
|
|
|
|
Examples:
|
|
>>> bridge.log_to_gui("👀", "Action observée", "info")
|
|
"""
|
|
self.signals.emit_log(emoji, message, level)
|
|
|
|
def update_gui_stats(self, **stats):
|
|
"""
|
|
Met à jour les statistiques de la GUI.
|
|
|
|
Args:
|
|
**stats: Statistiques à mettre à jour
|
|
(actions_count, patterns_count, workflows_count, etc.)
|
|
|
|
Examples:
|
|
>>> bridge.update_gui_stats(
|
|
... actions_count=12,
|
|
... patterns_count=2,
|
|
... workflows_count=1
|
|
... )
|
|
"""
|
|
self.signals.emit_stats_update(stats)
|
|
|
|
def change_mode_gui(self, mode: str):
|
|
"""
|
|
Change le mode affiché dans la GUI.
|
|
|
|
Args:
|
|
mode: Nouveau mode ('shadow', 'assist', 'copilot', 'auto')
|
|
|
|
Examples:
|
|
>>> bridge.change_mode_gui("assist")
|
|
"""
|
|
self.signals.emit_mode_change(mode)
|
|
|
|
def show(self):
|
|
"""Affiche la GUI."""
|
|
self.gui.show()
|
|
|
|
def hide(self):
|
|
"""Masque la GUI."""
|
|
self.gui.hide()
|
|
|
|
|
|
# Fonctions helper pour faciliter l'intégration
|
|
|
|
def setup_gui_for_orchestrator(orchestrator) -> OrchestratorGUIBridge:
|
|
"""
|
|
Configure la GUI pour un Orchestrator.
|
|
|
|
Fonction helper qui crée et configure automatiquement
|
|
le pont entre l'Orchestrator et la GUI.
|
|
|
|
Args:
|
|
orchestrator: Instance de l'Orchestrator
|
|
|
|
Returns:
|
|
Instance du OrchestratorGUIBridge configuré
|
|
|
|
Examples:
|
|
>>> from geniusia2.core import Orchestrator
|
|
>>> from geniusia2.gui import setup_gui_for_orchestrator
|
|
>>>
|
|
>>> orchestrator = Orchestrator()
|
|
>>> bridge = setup_gui_for_orchestrator(orchestrator)
|
|
>>> bridge.show()
|
|
>>>
|
|
>>> # Dans l'Orchestrator, utiliser:
|
|
>>> orchestrator.log_to_gui("👀", "Message", "info")
|
|
>>> orchestrator.update_gui_stats(actions_count=12)
|
|
"""
|
|
bridge = OrchestratorGUIBridge(orchestrator)
|
|
return bridge
|
|
|
|
|
|
def add_gui_logging_to_orchestrator(orchestrator, signals: GUISignals):
|
|
"""
|
|
Ajoute le logging GUI à un Orchestrator existant.
|
|
|
|
Fonction helper pour ajouter uniquement le logging
|
|
sans créer de nouvelle GUI.
|
|
|
|
Args:
|
|
orchestrator: Instance de l'Orchestrator
|
|
signals: Signaux GUI à utiliser
|
|
|
|
Examples:
|
|
>>> orchestrator = Orchestrator()
|
|
>>> gui = ImprovedGUI(orchestrator)
|
|
>>> add_gui_logging_to_orchestrator(orchestrator, gui.signals)
|
|
>>>
|
|
>>> # Maintenant l'orchestrator peut logger:
|
|
>>> orchestrator.log_to_gui("👀", "Message", "info")
|
|
"""
|
|
human_logger = HumanLogger()
|
|
|
|
orchestrator.human_logger = human_logger
|
|
orchestrator.gui_signals = signals
|
|
|
|
# Méthodes helper
|
|
def log_to_gui(emoji: str, message: str, level: str = "info"):
|
|
signals.emit_log(emoji, message, level)
|
|
|
|
def update_gui_stats(**stats):
|
|
signals.emit_stats_update(stats)
|
|
|
|
def change_mode_gui(mode: str):
|
|
signals.emit_mode_change(mode)
|
|
|
|
orchestrator.log_to_gui = log_to_gui
|
|
orchestrator.update_gui_stats = update_gui_stats
|
|
orchestrator.change_mode_gui = change_mode_gui
|
|
|
|
|
|
if __name__ == "__main__":
|
|
"""Test de l'intégration Orchestrator-GUI"""
|
|
import sys
|
|
from PyQt5.QtWidgets import QApplication
|
|
from PyQt5.QtCore import QTimer
|
|
|
|
# Mock Orchestrator pour les tests
|
|
class MockOrchestrator:
|
|
def __init__(self):
|
|
self.is_running = False
|
|
self.is_paused = False
|
|
self.actions_count = 0
|
|
self.patterns_count = 0
|
|
self.workflows_count = 0
|
|
|
|
def start(self):
|
|
print("MockOrchestrator: start()")
|
|
self.is_running = True
|
|
|
|
def stop(self):
|
|
print("MockOrchestrator: stop()")
|
|
self.is_running = False
|
|
|
|
def pause(self):
|
|
print("MockOrchestrator: pause()")
|
|
self.is_paused = not self.is_paused
|
|
|
|
def simulate_action(self):
|
|
"""Simule une action observée"""
|
|
self.actions_count += 1
|
|
self.log_to_gui("👀", f"Action #{self.actions_count} observée", "info")
|
|
self.update_gui_stats(
|
|
actions_count=self.actions_count,
|
|
patterns_count=self.patterns_count,
|
|
workflows_count=self.workflows_count
|
|
)
|
|
|
|
app = QApplication(sys.argv)
|
|
|
|
print("=" * 60)
|
|
print("Test de l'intégration Orchestrator-GUI")
|
|
print("=" * 60)
|
|
|
|
# Créer un mock orchestrator
|
|
orchestrator = MockOrchestrator()
|
|
|
|
# Configurer la GUI
|
|
bridge = setup_gui_for_orchestrator(orchestrator)
|
|
bridge.show()
|
|
|
|
print("\n✓ GUI créée et affichée")
|
|
print("✓ Orchestrator connecté")
|
|
|
|
# Simuler des événements
|
|
def simulate_workflow():
|
|
print("\n📝 Simulation d'événements...")
|
|
|
|
# Démarrer
|
|
QTimer.singleShot(1000, lambda: [
|
|
print(" 1. Démarrage"),
|
|
orchestrator.start(),
|
|
bridge.signals.emit_status_change(True),
|
|
bridge.log_to_gui("✅", "Système démarré", "success")
|
|
])
|
|
|
|
# Actions
|
|
QTimer.singleShot(2000, lambda: [
|
|
print(" 2. Action 1"),
|
|
orchestrator.simulate_action()
|
|
])
|
|
|
|
QTimer.singleShot(3000, lambda: [
|
|
print(" 3. Action 2"),
|
|
orchestrator.simulate_action()
|
|
])
|
|
|
|
QTimer.singleShot(4000, lambda: [
|
|
print(" 4. Action 3"),
|
|
orchestrator.simulate_action()
|
|
])
|
|
|
|
# Pattern détecté
|
|
QTimer.singleShot(5000, lambda: [
|
|
print(" 5. Pattern détecté"),
|
|
setattr(orchestrator, 'patterns_count', 1),
|
|
bridge.log_to_gui("🎯", "Pattern détecté !", "success"),
|
|
bridge.update_gui_stats(
|
|
actions_count=orchestrator.actions_count,
|
|
patterns_count=1,
|
|
workflows_count=0
|
|
)
|
|
])
|
|
|
|
# Changement de mode
|
|
QTimer.singleShot(6000, lambda: [
|
|
print(" 6. Changement de mode"),
|
|
bridge.change_mode_gui("assist"),
|
|
bridge.log_to_gui("✅", "Mode Suggestions activé", "success")
|
|
])
|
|
|
|
QTimer.singleShot(500, simulate_workflow)
|
|
|
|
print("\nTestez les boutons de la GUI:")
|
|
print(" - Pause")
|
|
print(" - Arrêter")
|
|
print(" - System tray")
|
|
|
|
sys.exit(app.exec_())
|