fix(poc-agent): ouvrir le chat Lea DGX si Tk est indisponible
This commit is contained in:
@@ -5,6 +5,9 @@ Fenetre de chat Lea integree au systray — version tkinter native.
|
|||||||
Remplace l'approche Edge browser par une vraie fenetre tkinter integree.
|
Remplace l'approche Edge browser par une vraie fenetre tkinter integree.
|
||||||
Design professionnel, theme clair, ancree en bas a droite de l'ecran.
|
Design professionnel, theme clair, ancree en bas a droite de l'ecran.
|
||||||
Tourne dans son propre thread daemon pour ne pas bloquer pystray.
|
Tourne dans son propre thread daemon pour ne pas bloquer pystray.
|
||||||
|
|
||||||
|
Le runtime Python embedded Windows ne contient pas toujours Tcl/Tk. Dans ce
|
||||||
|
cas, le menu "Discuter avec Lea" ouvre le chat DGX dans le navigateur.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@@ -13,6 +16,8 @@ import math
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
from urllib.parse import urlparse
|
||||||
from typing import Any, Callable, Dict, Optional
|
from typing import Any, Callable, Dict, Optional
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -219,7 +224,10 @@ class ChatWindow:
|
|||||||
|
|
||||||
def toggle(self) -> None:
|
def toggle(self) -> None:
|
||||||
"""Afficher/masquer la fenetre de chat."""
|
"""Afficher/masquer la fenetre de chat."""
|
||||||
if self._destroyed or self._root is None:
|
if self._destroyed:
|
||||||
|
return
|
||||||
|
if self._root is None:
|
||||||
|
self._open_browser_fallback()
|
||||||
return
|
return
|
||||||
if self._visible:
|
if self._visible:
|
||||||
self.hide()
|
self.hide()
|
||||||
@@ -228,7 +236,10 @@ class ChatWindow:
|
|||||||
|
|
||||||
def show(self) -> None:
|
def show(self) -> None:
|
||||||
"""Afficher la fenetre."""
|
"""Afficher la fenetre."""
|
||||||
if self._destroyed or self._root is None:
|
if self._destroyed:
|
||||||
|
return
|
||||||
|
if self._root is None:
|
||||||
|
self._open_browser_fallback()
|
||||||
return
|
return
|
||||||
self._root.after(0, self._do_show)
|
self._root.after(0, self._do_show)
|
||||||
|
|
||||||
@@ -257,6 +268,79 @@ class ChatWindow:
|
|||||||
"""Mettre a jour le client serveur (appele si cree apres la fenetre)."""
|
"""Mettre a jour le client serveur (appele si cree apres la fenetre)."""
|
||||||
self._server_client = server_client
|
self._server_client = server_client
|
||||||
|
|
||||||
|
def _chat_url(self) -> str:
|
||||||
|
"""Retourne l'URL web du chat, derivee de la config serveur."""
|
||||||
|
configured_url = self._chat_url_from_server_url(self._configured_server_url())
|
||||||
|
if self._server_client is not None:
|
||||||
|
chat_base = getattr(self._server_client, "_chat_base", None)
|
||||||
|
if chat_base:
|
||||||
|
chat_base = str(chat_base).rstrip("/")
|
||||||
|
if not self._is_local_url(chat_base):
|
||||||
|
return chat_base
|
||||||
|
if configured_url:
|
||||||
|
return configured_url
|
||||||
|
|
||||||
|
if configured_url:
|
||||||
|
return configured_url
|
||||||
|
|
||||||
|
host = (self._server_host or "localhost").strip()
|
||||||
|
if host.startswith(("http://", "https://")):
|
||||||
|
parsed = urlparse(host)
|
||||||
|
scheme = parsed.scheme or "http"
|
||||||
|
hostname = parsed.hostname or "localhost"
|
||||||
|
return f"{scheme}://{hostname}:{self._chat_port}"
|
||||||
|
|
||||||
|
return f"http://{host}:{self._chat_port}"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_local_url(url: str) -> bool:
|
||||||
|
try:
|
||||||
|
host = urlparse(url).hostname
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return host in {"localhost", "127.0.0.1", "::1"}
|
||||||
|
|
||||||
|
def _chat_url_from_server_url(self, server_url: Optional[str]) -> Optional[str]:
|
||||||
|
if not server_url:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
parsed = urlparse(server_url.strip())
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
if not parsed.hostname or parsed.hostname in {"localhost", "127.0.0.1", "::1"}:
|
||||||
|
return None
|
||||||
|
scheme = parsed.scheme or "http"
|
||||||
|
return f"{scheme}://{parsed.hostname}:{self._chat_port}"
|
||||||
|
|
||||||
|
def _configured_server_url(self) -> Optional[str]:
|
||||||
|
env_url = os.environ.get("RPA_SERVER_URL", "").strip()
|
||||||
|
if env_url:
|
||||||
|
return env_url
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Installed layout: <app>/agent_v1/ui/chat_window.py.
|
||||||
|
for parent in Path(__file__).resolve().parents:
|
||||||
|
cfg = parent / "config.txt"
|
||||||
|
if cfg.exists():
|
||||||
|
for line in cfg.read_text(encoding="utf-8", errors="ignore").splitlines():
|
||||||
|
if line.startswith("RPA_SERVER_URL="):
|
||||||
|
return line.split("=", 1)[1].strip()
|
||||||
|
except Exception:
|
||||||
|
logger.debug("Lecture config.txt pour chat_url impossible", exc_info=True)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _open_browser_fallback(self) -> None:
|
||||||
|
"""Fallback POC quand tkinter est absent du Python embedded."""
|
||||||
|
url = self._chat_url()
|
||||||
|
try:
|
||||||
|
import webbrowser
|
||||||
|
if webbrowser.open(url, new=1):
|
||||||
|
logger.info("ChatWindow indisponible, chat ouvert dans le navigateur: %s", url)
|
||||||
|
else:
|
||||||
|
logger.warning("ChatWindow indisponible, ouverture navigateur refusee: %s", url)
|
||||||
|
except Exception as exc:
|
||||||
|
logger.error("Impossible d'ouvrir le chat dans le navigateur (%s): %s", url, exc)
|
||||||
|
|
||||||
def _on_shared_state_change(self, state) -> None:
|
def _on_shared_state_change(self, state) -> None:
|
||||||
"""Callback appele quand l'etat partage change (depuis le systray ou ailleurs).
|
"""Callback appele quand l'etat partage change (depuis le systray ou ailleurs).
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user