feat: vérification CLIP avant chaque clic (filet de sécurité app)
Avant la résolution visuelle, compare l'embedding CLIP de l'écran actuel (fenêtre) avec l'embedding de référence (enregistrement). Si similarité < 0.75 → mauvaise application → STOP. CLIP sur fenêtre = insensible au fond d'écran. CLIP ne distingue pas les états fins (texte différent) → le titre de fenêtre reste la vérification principale. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5182,10 +5182,51 @@ def _resolve_target_sync(
|
||||
if by_text_strict or by_role:
|
||||
vlm_description = _build_target_description(target_spec)
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# Étape -1 : Vérification CLIP (si embedding de référence fourni)
|
||||
# Vérifie qu'on est dans la bonne application avant de chercher
|
||||
# l'élément. Filet de sécurité contre les clics au mauvais endroit.
|
||||
# ---------------------------------------------------------------
|
||||
clip_embedding = target_spec.get("clip_embedding")
|
||||
if clip_embedding:
|
||||
try:
|
||||
from core.embedding.clip_embedder import CLIPEmbedder
|
||||
from PIL import Image as _PILImage
|
||||
import numpy as _np
|
||||
|
||||
_clip = CLIPEmbedder()
|
||||
# Embedding de l'écran actuel (fenêtre si possible)
|
||||
window_capture = target_spec.get("window_capture", {})
|
||||
window_rect = window_capture.get("rect")
|
||||
current_img = _PILImage.open(screenshot_path)
|
||||
if window_rect:
|
||||
current_img = current_img.crop(tuple(window_rect))
|
||||
|
||||
current_emb = _np.array(_clip.embed_image(current_img), dtype=_np.float32).flatten()
|
||||
ref_emb = _np.array(clip_embedding, dtype=_np.float32).flatten()
|
||||
|
||||
clip_sim = float(_np.dot(current_emb, ref_emb) / (
|
||||
_np.linalg.norm(current_emb) * _np.linalg.norm(ref_emb)
|
||||
))
|
||||
logger.info(f"CLIP vérification : similarité={clip_sim:.3f}")
|
||||
|
||||
if clip_sim < 0.75:
|
||||
logger.warning(
|
||||
f"CLIP MISMATCH : sim={clip_sim:.3f} < 0.75 — "
|
||||
f"écran actuel trop différent de l'enregistrement"
|
||||
)
|
||||
return {
|
||||
"resolved": False,
|
||||
"method": "clip_mismatch",
|
||||
"reason": f"clip_similarity_{clip_sim:.3f}",
|
||||
"x_pct": fallback_x_pct,
|
||||
"y_pct": fallback_y_pct,
|
||||
}
|
||||
except Exception as e:
|
||||
logger.debug(f"CLIP vérification erreur (non-bloquant) : {e}")
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# Étape 0 : Choisir la stratégie selon le type d'élément
|
||||
# - Texte OCR fiable → grounding VLM (description textuelle)
|
||||
# - Icône sans texte → template matching (crop 80x80)
|
||||
# ---------------------------------------------------------------
|
||||
by_text_source = target_spec.get("by_text_source", "")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user