fix: worker séparé, VLM-first direct Ollama, popup handler hybride, serveur léger

Worker VLM séparé :
- run_worker.py : process distinct du serveur HTTP
- Communication par fichiers (_worker_queue.txt + _replay_active.lock)
- Service systemd rpa-worker.service
- Le serveur HTTP ne charge plus CLIP/VLM (mode léger)
- StreamProcessor._ensure_initialized() désactivé dans le serveur

VLM direct depuis l'agent :
- L'agent appelle Ollama directement (port 11434, LAN)
- Ollama configuré sur 0.0.0.0 (OLLAMA_HOST)
- Pas de passage par le serveur streaming (évite le blocage GIL)
- Fallback serveur supprimé (VLM direct ou STOP)

Popup handler hybride :
- VLM identifie le bouton ("Oui", "OK") — pas de coordonnées
- Template matching localise le texte sur l'écran (PIL + cv2)
- _find_text_on_screen() : rend le texte en image, matchTemplate
- _vlm_identify_popup_button() : prompt simple, prefill texte

Resolve visuel hybride :
- Cascade : template anchor → VLM+template texte → VLM direct (legacy)
- _hybrid_vlm_resolve() : VLM identifie + template localise
- _template_match_anchor() : match direct crop, seuil 0.80
- Seuil strict 0.90 pour template matching en mode replay

Analyse VLM temps réel désactivée :
- process_screenshot() ne fait plus de VLM (stockage uniquement)
- L'analyse est différée au worker séparé
- Le serveur HTTP reste réactif en permanence

VLM prefill fix :
- num_ctx augmenté (2048 → 8192 pour images 1080p)
- bbox_2d au lieu de click_point (plus fiable)
- Coordonnées 0-1000 (format natif qwen3-vl)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-03-26 12:52:40 +01:00
parent d5deac3029
commit c2dc8f8fe4
3 changed files with 590 additions and 57 deletions

View File

@@ -951,9 +951,19 @@ class StreamProcessor:
return waited
def _ensure_initialized(self):
"""Charger les composants core GPU si pas encore fait."""
"""Charger les composants core GPU si pas encore fait.
DÉSACTIVÉ dans le serveur HTTP : les composants GPU (ScreenAnalyzer,
CLIP, FAISS) bloquent le GIL Python et rendent le serveur non-réactif.
Ces composants sont chargés uniquement par le worker séparé (run_worker.py).
Le serveur HTTP ne fait que stocker les screenshots et distribuer les replays.
"""
if self._initialized:
return
# Marquer comme initialisé SANS charger les composants GPU
self._initialized = True
logger.info("StreamProcessor initialisé en mode LÉGER (pas de GPU, pas de VLM)")
return
with self._lock:
if self._initialized: