feat: popup VLM double-appel, auth Bearer partout, texte AZERTY corrigé

- Popup handling via double appel VLM (détection + localisation précise du bouton)
- Reconstruction texte depuis raw_keys (numpad /, @ AltGr fusionné)
- Clipboard paste pour texte riche, raw_keys pour commandes simples (Win+R)
- Skip des release orphelins dans raw_keys (fix menu Démarrer parasite)
- Auth Bearer sur toutes les requêtes agent → streaming server
- Endpoints /replay/next et /stream/image publics (agent Rust legacy)
- alt_gr ajouté dans _MODIFIER_ONLY_KEYS
- _key_combo_printable_char détecte ctrl+@ comme caractère imprimable
- start.bat tue les anciens process (python + rpa-agent) au démarrage
- Heartbeat avec token Bearer dans main.py et deploy/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-03-30 16:45:09 +02:00
parent c2dc8f8fe4
commit 647aa610fd
10 changed files with 307 additions and 56 deletions

View File

@@ -91,11 +91,24 @@ class LeaServerClient:
# Session de chat
self._chat_session_id: Optional[str] = None
# Token API pour le serveur streaming (auth Bearer)
self._api_token = os.environ.get("RPA_API_TOKEN", "")
logger.info(
"LeaServerClient initialise : chat=%s, stream=%s",
self._chat_base, self._stream_base,
)
# ---------------------------------------------------------------------------
# Auth
# ---------------------------------------------------------------------------
def _auth_headers(self) -> Dict[str, str]:
"""Headers d'authentification pour le serveur streaming."""
if self._api_token:
return {"Authorization": f"Bearer {self._api_token}"}
return {}
# ---------------------------------------------------------------------------
# Proprietes
# ---------------------------------------------------------------------------
@@ -133,11 +146,12 @@ class LeaServerClient:
# ---------------------------------------------------------------------------
def check_connection(self) -> bool:
"""Tester la connexion au serveur chat."""
"""Tester la connexion au serveur streaming (port 5005)."""
try:
import requests
resp = requests.get(
f"{self._chat_base}/api/workflows",
f"{self._stream_base}/health",
headers=self._auth_headers(),
timeout=5,
)
was_connected = self._connected
@@ -200,11 +214,13 @@ class LeaServerClient:
return None
def list_workflows(self) -> List[Dict[str, Any]]:
"""Recuperer la liste des workflows depuis le serveur chat."""
"""Recuperer la liste des workflows depuis le serveur streaming."""
try:
import requests
headers = self._auth_headers()
resp = requests.get(
f"{self._chat_base}/api/workflows",
f"{self._stream_base}/api/v1/traces/stream/workflows",
headers=headers,
timeout=10,
)
if resp.ok:
@@ -221,22 +237,10 @@ class LeaServerClient:
return []
def list_gestures(self) -> List[Dict[str, Any]]:
"""Recuperer la liste des gestes depuis le serveur chat."""
try:
import requests
resp = requests.get(
f"{self._chat_base}/api/gestures",
timeout=10,
)
if resp.ok:
data = resp.json()
if isinstance(data, list):
return data
return data.get("gestures", [])
return []
except Exception as e:
logger.error("List gestures erreur : %s", e)
return []
"""Recuperer la liste des gestes (non disponible sur streaming server)."""
# Les gestes etaient sur le chat server (5004) qui n'est plus utilise.
# Retourner une liste vide silencieusement.
return []
# ---------------------------------------------------------------------------
# Replay Polling (port 5005)
@@ -274,6 +278,7 @@ class LeaServerClient:
resp = req_lib.get(
f"{self._stream_base}/api/v1/traces/stream/replay/next",
params={"session_id": self._poll_session_id},
headers=self._auth_headers(),
timeout=5,
)
@@ -306,6 +311,7 @@ class LeaServerClient:
import requests
resp = requests.get(
f"{self._stream_base}/api/v1/traces/stream/replays",
headers=self._auth_headers(),
timeout=5,
)
if resp.ok:
@@ -340,6 +346,7 @@ class LeaServerClient:
"error": error,
"screenshot": screenshot,
},
headers=self._auth_headers(),
timeout=5,
)
except Exception as e: