Le grounding par texte (OCR → UI-TARS) est maintenant la méthode
PRINCIPALE. CLIP n'est appelé que si le grounding échoue.
Avant : CLIP (faux positifs confiants) → cascade grounding (rarement atteinte)
Après : OCR 1s → UI-TARS 3s → CLIP (fallback visuel pur)
C'est comme ça que font UI-TARS, Agent-S3 et AppAgent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cause racine : max-width/max-height CSS ne font pas GRANDIR une image.
Fix : calcul explicite width/height en JS via Math.min(ratio).
min-height:0 sur le conteneur flex.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le fichier CSS avait max-height:100% sur .fullscreen-content img
qui écrasait le style inline calc(100vh-70px). 100% d'un conteneur
flex sans hauteur explicite = taille naturelle de l'image = minuscule.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le useEffect(saveLibrary) se déclenchait avec library=[] avant que
loadLibraryAsync ait fini → écrasait le fichier serveur avec un
tableau vide. Ajout d'un flag libraryLoaded pour ne sauvegarder
qu'après le chargement initial.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Quand l'utilisateur sélectionne une ancre dans le VWB :
1. OCR docTR extrait le texte du crop → target_text
2. Si texte < 3 chars → VLM qwen2.5vl:3b décrit en 5 mots
3. Stocké en BDD (VisualAnchor.target_text + ocr_description)
4. Injecté automatiquement dans les params à l'exécution
L'exécution sait maintenant QUOI chercher dès le départ :
- CLIP vérifie par OCR que le texte correspond
- Le grounding cascade a un vrai target_text
- Plus besoin de deviner à chaque run
Migration SQLite gracieuse (ALTER TABLE si colonnes absentes).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Quand CLIP dit "trouvé", on vérifie par OCR que le texte à cette
position correspond au target. Si CLIP clique sur "Ce PC" au lieu
de "CR_patient_demo", l'OCR le rejette → fallback sur la cascade.
Description VLM de l'ancre AVANT le CLIP quand le label est un
type d'action (double_click_anchor → "text file icon CR_patient").
Le target_text enrichi sert à la vérification croisée ET au grounding.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
La capture VWB utilisait monitors[0] (composite) mais l'exécution
utilisait monitors[1] (premier écran). Images incompatibles → CLIP
retournait 0.00 sur un écran identique.
Tous les fichiers alignés sur monitors[0].
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le seuil 0.20 faisait que CLIP cliquait sur Chrome au lieu du dossier
Demo (score 0.25 accepté = faux positif). Le seuil 0.45 rejette les
matchs faibles et la cascade OCR/UI-TARS prend le relais proprement.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Seuil CLIP abaissé pour les icônes génériques (dossier, fichier)
qui obtenaient 0.25 au lieu de 0.45.
IntelligentExecutor en singleton — CLIP et RF-DETR chargés une
seule fois et réutilisés entre les étapes. Élimine le rechargement
de ~40s par étape.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
L'orchestrateur VRAM redémarrait Ollama en pleine exécution → timeout.
Désactivé pendant le workflow. L'orchestrateur reste disponible pour
bascule manuelle avant/après.
Description ancre via qwen2.5vl:3b (3 Go) au lieu de 7b — tient en VRAM
sans décharger CLIP ni RF-DETR.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SeeClick supprimé : modèle HF incompatible (QWenConfig non reconnu),
crashait à chaque exécution et polluait les logs.
Remplacé par UI-TARS via la chaîne de grounding.
Log warning visible quand la description VLM de l'ancre échoue
(pour diagnostiquer les problèmes de VRAM).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Quand le target_text est vide ou identique au type d'action
(click_anchor, double_click_anchor...), le VLM décrit l'image
de l'ancre en 5 mots ("folder icon named Demo").
Cette description est ensuite passée à UI-TARS pour le grounding
("click on folder icon named Demo") et à l'OCR pour la recherche.
Chaîne complète : VLM décrit → OCR cherche → UI-TARS grounding → VLM raisonne.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Grounding en cascade quand CLIP/template échouent :
1. OCR (docTR) → cherche le texte exact sur l'écran (~1s)
2. UI-TARS grounding → "click on X" → coordonnées (~3s, 94% ScreenSpot)
3. VLM reasoning → raisonnement complet + confirmation OCR (~10s)
find_element_on_screen() dans input_handler.py (partagé VWB + Léa).
Câblé dans find_and_click() et execute_action() comme fallback.
Refonte capture écran :
- mss.monitors[0] (composite) pour capturer la VM en plein écran
- FullscreenSelector réécrit : overlay via getBoundingClientRect()
- Bboxes et sélection alignées avec l'image (calcul JS, pas CSS)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FullscreenSelector réécrit :
- Overlay unique positionné via getBoundingClientRect()
- Recalcul auto au resize
- Coordonnées souris relatives à l'image
- Plus de décalage bboxes/sélection
Capture backend :
- mss.monitors[0] (écran composite) au lieu de pyautogui.screenshot()
- Capture la VM en plein écran correctement
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
VRAMOrchestrator : bascule automatique entre modes SHADOW et REPLAY.
- SHADOW : streaming server + agent_chat actifs
- REPLAY : VLM qwen2.5vl:7b chargé, services non-essentiels stoppés
vlm_reason_about_screen() appelle ensure_reasoning_ready() avant
chaque raisonnement — libère la VRAM si nécessaire.
Benchmark : qwen2.5vl:7b en 10s (warm) vs 44s quand VRAM saturée.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CognitiveContext : bloc-notes interne réinjecté à chaque décision.
- objective : ce que Léa essaie de faire
- current_step : progression dans le plan
- action_history : les N dernières actions (succès/échec)
- learned_facts : faits appris pendant l'exécution
- confidence : auto-évaluation (baisse sur échec)
- needs_help : demande d'aide à l'humain
- to_prompt_context() : génère le texte pour le VLM
Module standalone, pas encore câblé dans l'executor.
Testé sur scénario de facturation OSIRIS.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
vlm_reason_about_screen() : capture l'écran, envoie au VLM local
(gemma4/Ollama) avec l'objectif et le contexte, retourne une action
en JSON (click/type/wait/nothing + target + reasoning).
Chaîne de décision :
1. Réflexes (UIPatternLibrary) → instantané
2. OCR bouton (docTR) → rapide
3. VLM reasoning (Ollama) → intelligent, ~2-5s
Le VLM intervient UNIQUEMENT quand 1 et 2 échouent — pas de latence
ajoutée quand les réflexes suffisent.
UIPatternLibrary enrichie : charge builtin + GUI-R1 + learned patterns.
save_learned_pattern() persiste les patterns appris par Shadow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Les images générées par PM4Py étaient trop petites et illisibles.
- DPI 150, taille 40x20 pouces, layout vertical (TB)
- La modale plein écran permet le défilement (scroll)
- Fallback sur pm4py.save_vis si le rendu Graphviz échoue
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Modale fullscreen au clic sur les diagrammes BPMN/DFG.
Fermeture par clic ou Échap. Les images sont illisibles en miniature.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Point de sauvegarde incluant les fichiers non committés des sessions
précédentes (systemd, docs, agents, GPU manager).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Les triggers ≤3 chars (ok, no) utilisent maintenant des frontières
de mots (\b) pour éviter les faux positifs (ok dans cookies).
Trigger "utilise des cookies" ajouté pour le pattern cookie_accept.
7/7 patterns validés en test terrain simulé.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Après la dernière étape, Léa vérifie l'écran et gère les dialogues
restants (jusqu'à 3 vérifications en cascade). Le workflow laisse
l'écran propre à la fin.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le filtre len<3 bloquait les boutons "OK" (2 chars) et "No" (2 chars).
Seuil abaissé à 2 — filtre les lettres isolées mais laisse passer
les boutons courts courants des dialogues Windows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
UIPatternLibrary câblée dans l'executor et le stream processor.
Pendant un wait_for_anchor, Léa surveille l'écran toutes les secondes :
1. OCR plein écran (docTR)
2. Pattern matching (dialogues Save, OK, Cancel, cookies...)
3. OCR ciblé pour trouver le bouton par son texte réel
4. Clic sur le match le plus bas (bouton, pas titre)
Fix : seuil ratio supprimé (trigger trouvé = match, quelle que soit
la longueur du texte OCR). Matching strict mot exact ≥3 chars
(évite les faux positifs sur lettres isolées). Fallback recherche
partielle pour les lettres soulignées (E_nregistrer).
Plus aucune coordonnée hardcodée — 100% vision.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
VWB Executor :
- _check_screen_for_patterns() : capture écran + OCR + pattern matching
- _handle_detected_pattern() : clic automatique sur dialogues connus
- Vérifie entre chaque étape en mode intelligent/debug
- Si un dialogue bloque (OK, Save, Cancel), Léa le gère seule
Stream Processor :
- Enrichit les ScreenState avec ui_pattern/ui_pattern_action/ui_pattern_target
- Les patterns détectés sont loggés et stockés dans les résultats
- Permet au GraphBuilder de savoir quels écrans sont des dialogues
Phase 2 du plan "connaissance native de l'environnement".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
UIPatternLibrary : 16 patterns builtin (dialogues, menus, formulaires,
popups, raccourcis) qui donnent à Léa des réflexes immédiats.
Quand Léa reconnaît "Voulez-vous enregistrer ?" elle sait cliquer
sur "Enregistrer" sans apprentissage préalable.
- core/knowledge/ui_patterns.py : bibliothèque avec find_pattern(),
get_dialog_handler(), add_pattern() pour patterns appris
- Métadonnées GUI-R1 (3K exemples) extraites dans data/ (gitignored)
Phase 1 du plan "connaissance native de l'environnement".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le conteneur .fullscreen-content avait height:0 + min-height:0
qui écrasait la hauteur du flex child → image minuscule.
Le wrapper inline-block limitait aussi le dimensionnement.
Fix : overflow:hidden sans height forcée, wrapper en flex 100%.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CSS : le dropdown héritait color:white du header → forcé #212121
sur .workflow-dropdown et .dropdown-item .item-name
Bibliothèque : migration localStorage → backend (capture_library.json)
- GET/POST /api/v3/capture/library (max 50 captures)
- loadLibraryAsync() charge depuis backend, fallback localStorage
- saveLibrary() écrit dans les deux (localStorage + backend)
- capture_library.json gitignored
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le refresh du layout X11 juste avant xdotool type force le bon keymap.
Sans ça, xdotool envoie des keycodes décalés (: → M, / → !, etc.)
dans les VM spice/QEMU.
Solution trouvée via askubuntu.com/questions/914718.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remet xclip+Ctrl+V comme méthode prioritaire. Les spice tools sont
installés dans la VM → le presse-papier est partagé → pas de problème
de mapping clavier. xdotool envoie des événements synthétiques X11
que spice/QEMU traite différemment des vraies frappes (: → M).
Citrix partage aussi le clipboard nativement → même méthode en prod.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
xdotool type pour les segments alphanumériques (un seul appel, rapide),
xdotool key avec keysym uniquement pour les caractères spéciaux
(:, /, @, etc.) qui cassent en AZERTY dans les VM.
Évite le subprocess par caractère (trop lent, effet visuel désagréable).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
xdotool type envoie des scancodes QWERTY — dans une VM AZERTY,
':' devient 'M', '/' devient '!', etc.
Nouvelle approche : xdotool key avec les noms de keysym X11
(colon, slash, period, etc.) qui sont indépendants du layout.
Chaque caractère est envoyé individuellement — plus lent mais
100% fiable en AZERTY/QWERTY, local ou VM.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
safe_type_text() : xdotool type en priorité au lieu du presse-papier.
Le clipboard xclip ne traverse pas les VM (QEMU) ni Citrix/RDP.
xdotool envoie des frappes X11 réelles que les VM capturent.
Délai 20ms entre caractères pour fiabilité.
Cosmétique : couleur texte forcée sur les items workflow du sidebar
(color: var(--text-primary)) — était blanc sur blanc.
Logs diagnostic ajoutés dans execute_workflow_thread et execute_action.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MAX_TEMPLATE_DISTANCE dans zoned_template_match était encore à 150px.
Tous les seuils de distance sont maintenant alignés à 500px :
- MAX_DISTANCE_PX (CLIP) : 500
- MAX_GLOBAL_DISTANCE (template global) : 500
- MAX_SEECLICK_DISTANCE : 500
- MAX_TEMPLATE_DISTANCE (template zonée) : 500
Commentaires périmés corrigés (plus de références aux anciennes valeurs).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Le template matching global trouvait l'icône Chrome à 0.99 de confiance
mais la rejetait car elle avait bougé de >150px. Même problème pour
SeeClick (>200px). Aligné tous les seuils de distance à 500px
pour supporter les workflows VWB cross-résolution.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MAX_DISTANCE_PX 120→500 (ancre peut être loin si résolution différente)
MIN_CLIP_SCORE 0.55→0.50 (tolérance basique suffisante)
MIN_COMBINED_SCORE 0.5→0.45 (accepter les matchs raisonnables)
L'icône Chrome à 81% de confiance était rejetée à cause de la distance.
Les workflows VWB manuels capturent sur un écran et s'exécutent
potentiellement sur un autre — la tolérance de distance doit être large.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Corrige les src={{b64ImgSrc(...)}} → src={b64ImgSrc(...)} causés par
le replace_all sur les template literals. Corrige aussi l'appel
b64ImgSrc dans du code JS pur (pas de {} autour).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CSS fullscreen-content : height:0 + min-height:0 pour forcer flex fill
- Image fullscreen : max-height calc(100vh - 60px) + object-fit contain
- Fonction b64ImgSrc() détecte automatiquement PNG vs JPEG depuis le base64
- Corrige l'affichage des thumbnails compressés JPEG dans la bibliothèque
- Appliqué dans CapturePanel + CaptureLibrary (toutes les occurrences)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>