chore: ajouter agent_v0/ au tracking git (était un repo embarqué)
Suppression du .git embarqué dans agent_v0/ — le code est maintenant tracké normalement dans le repo principal. Inclut : agent_v1 (client), server_v1 (streaming), lea_ui (chat client) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
218
agent_v0/lea_ui/launcher.py
Normal file
218
agent_v0/lea_ui/launcher.py
Normal file
@@ -0,0 +1,218 @@
|
||||
# agent_v0/lea_ui/launcher.py
|
||||
"""
|
||||
Point d'entree pour le panneau Lea.
|
||||
|
||||
Lancement autonome :
|
||||
python -m agent_v0.lea_ui.launcher
|
||||
|
||||
Ou integre dans agent_v0/agent_v1/main.py avec flag --ui lea.
|
||||
|
||||
Ce module :
|
||||
1. Cree l'application Qt
|
||||
2. Instancie LeaServerClient
|
||||
3. Instancie LeaMainWindow
|
||||
4. Enregistre un raccourci global (Ctrl+Shift+L) via keyboard hook
|
||||
5. Lance la boucle Qt
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
logger = logging.getLogger("lea_ui.launcher")
|
||||
|
||||
|
||||
def _setup_logging(verbose: bool = False) -> None:
|
||||
"""Configurer le logging pour le panneau Lea."""
|
||||
level = logging.DEBUG if verbose else logging.INFO
|
||||
logging.basicConfig(
|
||||
level=level,
|
||||
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
||||
datefmt="%H:%M:%S",
|
||||
)
|
||||
|
||||
|
||||
def _setup_global_hotkey(window) -> Optional[object]:
|
||||
"""Enregistrer le raccourci global Ctrl+Shift+L pour afficher/cacher le panneau.
|
||||
|
||||
Utilise la librairie keyboard si disponible (Windows/Linux).
|
||||
Retourne le hook pour pouvoir le desinscrire a l'arret.
|
||||
"""
|
||||
try:
|
||||
import keyboard
|
||||
|
||||
def on_hotkey():
|
||||
# Appeler toggle_visibility dans le thread Qt
|
||||
from PyQt5.QtCore import QTimer
|
||||
QTimer.singleShot(0, window.toggle_visibility)
|
||||
|
||||
keyboard.add_hotkey("ctrl+shift+l", on_hotkey)
|
||||
logger.info("Raccourci global Ctrl+Shift+L enregistre")
|
||||
return True
|
||||
except ImportError:
|
||||
logger.info(
|
||||
"Librairie 'keyboard' non disponible — "
|
||||
"raccourci global Ctrl+Shift+L non enregistre. "
|
||||
"Installez-la avec: pip install keyboard"
|
||||
)
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.warning("Impossible d'enregistrer le raccourci global : %s", e)
|
||||
return None
|
||||
|
||||
|
||||
def _load_environment() -> None:
|
||||
"""Charger les variables d'environnement depuis .env.local."""
|
||||
env_paths = [
|
||||
os.path.join(os.path.dirname(__file__), "..", "..", ".env.local"),
|
||||
os.path.join(os.path.dirname(__file__), "..", ".env.local"),
|
||||
]
|
||||
for env_path in env_paths:
|
||||
env_path = os.path.abspath(env_path)
|
||||
if os.path.exists(env_path):
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv(env_path)
|
||||
logger.info("Variables d'environnement chargees depuis %s", env_path)
|
||||
return
|
||||
except ImportError:
|
||||
# Fallback : chargement manuel
|
||||
with open(env_path, "r", encoding="utf-8") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line and not line.startswith("#") and "=" in line:
|
||||
key, value = line.split("=", 1)
|
||||
value = value.strip("\"'")
|
||||
os.environ[key.strip()] = value
|
||||
logger.info("Variables chargees manuellement depuis %s", env_path)
|
||||
return
|
||||
|
||||
|
||||
def launch_lea(
|
||||
server_host: Optional[str] = None,
|
||||
chat_port: int = 5004,
|
||||
stream_port: int = 5005,
|
||||
verbose: bool = False,
|
||||
session_id: Optional[str] = None,
|
||||
) -> None:
|
||||
"""Lancer le panneau Lea.
|
||||
|
||||
Args:
|
||||
server_host: adresse du serveur Linux (None = auto-detection)
|
||||
chat_port: port du serveur chat
|
||||
stream_port: port du serveur streaming
|
||||
verbose: mode debug
|
||||
session_id: identifiant de session pour le polling replay
|
||||
"""
|
||||
_setup_logging(verbose)
|
||||
_load_environment()
|
||||
|
||||
# Import PyQt5 ici pour un message d'erreur clair si absent
|
||||
try:
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
from PyQt5.QtCore import Qt
|
||||
except ImportError:
|
||||
logger.error(
|
||||
"PyQt5 n'est pas installe. Installez-le avec :\n"
|
||||
" pip install PyQt5"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
from .server_client import LeaServerClient
|
||||
from .main_window import LeaMainWindow
|
||||
|
||||
# Creer ou recuperer l'application Qt
|
||||
app = QApplication.instance()
|
||||
if app is None:
|
||||
app = QApplication(sys.argv)
|
||||
app.setQuitOnLastWindowClosed(False)
|
||||
|
||||
# Client serveur
|
||||
client = LeaServerClient(
|
||||
server_host=server_host,
|
||||
chat_port=chat_port,
|
||||
stream_port=stream_port,
|
||||
)
|
||||
|
||||
# Fenetre principale
|
||||
window = LeaMainWindow(server_client=client)
|
||||
window.show()
|
||||
|
||||
# Raccourci global
|
||||
hotkey = _setup_global_hotkey(window)
|
||||
|
||||
# Polling replay (si session_id fourni)
|
||||
if session_id:
|
||||
client.start_polling(session_id)
|
||||
|
||||
logger.info(
|
||||
"Panneau Lea demarre — serveur=%s, chat_port=%d, stream_port=%d",
|
||||
client.server_host, chat_port, stream_port,
|
||||
)
|
||||
|
||||
# Boucle Qt
|
||||
try:
|
||||
exit_code = app.exec_()
|
||||
finally:
|
||||
window.shutdown()
|
||||
if hotkey:
|
||||
try:
|
||||
import keyboard
|
||||
keyboard.unhook_all()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Point d'entree CLI."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Panneau Lea — Interface utilisateur RPA Vision V3",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--server", "-s",
|
||||
dest="server_host",
|
||||
default=None,
|
||||
help="Adresse du serveur Linux (defaut: RPA_SERVER_HOST ou localhost)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--chat-port",
|
||||
type=int,
|
||||
default=5004,
|
||||
help="Port du serveur chat (defaut: 5004)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--stream-port",
|
||||
type=int,
|
||||
default=5005,
|
||||
help="Port du serveur streaming (defaut: 5005)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--session-id",
|
||||
default=None,
|
||||
help="Identifiant de session pour le polling replay",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose", "-v",
|
||||
action="store_true",
|
||||
help="Mode debug (logs verbeux)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
launch_lea(
|
||||
server_host=args.server_host,
|
||||
chat_port=args.chat_port,
|
||||
stream_port=args.stream_port,
|
||||
verbose=args.verbose,
|
||||
session_id=args.session_id,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user