perf: boucle fermée pHash (2s→150ms) + batch CLIP (90 appels→1)
Some checks failed
security-audit / Bandit (scan statique) (push) Successful in 13s
security-audit / pip-audit (CVE dépendances) (push) Successful in 10s
security-audit / Scan secrets (grep) (push) Successful in 9s
tests / Lint (ruff + black) (push) Successful in 14s
tests / Tests unitaires (sans GPU) (push) Failing after 14s
tests / Tests sécurité (critique) (push) Has been skipped
Some checks failed
security-audit / Bandit (scan statique) (push) Successful in 13s
security-audit / pip-audit (CVE dépendances) (push) Successful in 10s
security-audit / Scan secrets (grep) (push) Successful in 9s
tests / Lint (ruff + black) (push) Successful in 14s
tests / Tests unitaires (sans GPU) (push) Failing after 14s
tests / Tests sécurité (critique) (push) Has been skipped
Boucle fermée : time.sleep(2.0) remplacé par _wait_for_screen_change() qui poll le pHash toutes les 150ms. Sort dès que l'écran change. 4 occurrences remplacées. Batch CLIP : filtre par distance AVANT le CLIP (90→~20 éléments), puis embed_image_batch() en un seul appel GPU + np.dot vectorisé. Estimé : 42s→~20s total workflow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,48 @@ from . import api_v3_bp
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _wait_for_screen_change(pre_screen, max_wait=2.0, poll_interval=0.15):
|
||||
"""
|
||||
Attend que l'écran change après un clic, au lieu d'un sleep fixe.
|
||||
Compare le pHash de l'écran actuel avec le screenshot pré-clic.
|
||||
Sort dès que la distance de Hamming >= 5 (changement détecté).
|
||||
Fallback: sort après max_wait secondes si aucun changement.
|
||||
|
||||
Args:
|
||||
pre_screen: PIL Image du screenshot avant le clic (peut être None)
|
||||
max_wait: Temps max d'attente en secondes (défaut 2.0)
|
||||
poll_interval: Intervalle de polling en secondes (défaut 0.15)
|
||||
"""
|
||||
if pre_screen is None:
|
||||
# Pas de screenshot pré-clic, fallback sur sleep classique
|
||||
time.sleep(max_wait)
|
||||
return
|
||||
|
||||
try:
|
||||
from core.analytics.screen_change_detector import compute_phash
|
||||
import mss as _mss
|
||||
from PIL import Image as _PILImage
|
||||
|
||||
_pre_hash = compute_phash(pre_screen)
|
||||
_start = time.time()
|
||||
|
||||
while time.time() - _start < max_wait:
|
||||
time.sleep(poll_interval)
|
||||
try:
|
||||
with _mss.mss() as _sct:
|
||||
_grab = _sct.grab(_sct.monitors[0])
|
||||
_post_screen = _PILImage.frombytes('RGB', _grab.size, _grab.bgra, 'raw', 'BGRX')
|
||||
_post_hash = compute_phash(_post_screen)
|
||||
_dist = _pre_hash - _post_hash
|
||||
if _dist >= 5: # Écran a changé
|
||||
break
|
||||
except Exception:
|
||||
break
|
||||
except Exception:
|
||||
# Si pHash/mss non disponible, fallback sur sleep
|
||||
time.sleep(max_wait)
|
||||
|
||||
|
||||
from core.execution.input_handler import (
|
||||
safe_type_text as _shared_safe_type_text,
|
||||
check_screen_for_patterns as _shared_check_patterns,
|
||||
@@ -722,6 +764,17 @@ def execute_action_with_coords(action_type: str, params: dict, coords: dict) ->
|
||||
x, y = coords['x'], coords['y']
|
||||
print(f"🖱️ [Self-Healing] Clic aux coordonnées choisies: ({x}, {y})")
|
||||
|
||||
# Capture pré-clic pour détection de changement
|
||||
_pre_screen = None
|
||||
try:
|
||||
import mss as _mss
|
||||
from PIL import Image as _PILImage
|
||||
with _mss.mss() as _sct:
|
||||
_grab = _sct.grab(_sct.monitors[0])
|
||||
_pre_screen = _PILImage.frombytes('RGB', _grab.size, _grab.bgra, 'raw', 'BGRX')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if action_type in ['double_click_anchor']:
|
||||
pyautogui.doubleClick(x, y)
|
||||
elif action_type in ['right_click_anchor']:
|
||||
@@ -729,7 +782,7 @@ def execute_action_with_coords(action_type: str, params: dict, coords: dict) ->
|
||||
else:
|
||||
pyautogui.click(x, y)
|
||||
|
||||
time.sleep(2.0) # Délai après le clic
|
||||
_wait_for_screen_change(_pre_screen)
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
@@ -759,6 +812,17 @@ def execute_action_with_static_coords(action_type: str, params: dict) -> dict:
|
||||
|
||||
print(f"🖱️ [Self-Healing] Clic aux coordonnées statiques: ({x}, {y})")
|
||||
|
||||
# Capture pré-clic pour détection de changement
|
||||
_pre_screen = None
|
||||
try:
|
||||
import mss as _mss
|
||||
from PIL import Image as _PILImage
|
||||
with _mss.mss() as _sct:
|
||||
_grab = _sct.grab(_sct.monitors[0])
|
||||
_pre_screen = _PILImage.frombytes('RGB', _grab.size, _grab.bgra, 'raw', 'BGRX')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if action_type in ['double_click_anchor']:
|
||||
pyautogui.doubleClick(x, y)
|
||||
elif action_type in ['right_click_anchor']:
|
||||
@@ -766,7 +830,7 @@ def execute_action_with_static_coords(action_type: str, params: dict) -> dict:
|
||||
else:
|
||||
pyautogui.click(x, y)
|
||||
|
||||
time.sleep(2.0)
|
||||
_wait_for_screen_change(_pre_screen)
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
@@ -844,6 +908,7 @@ def execute_action(action_type: str, params: dict) -> dict:
|
||||
_fc_target_desc = params.get('visual_anchor', {}).get('description', '')
|
||||
|
||||
x, y, confidence, method_used = None, None, 0, ''
|
||||
screen_img = None # Screenshot pré-clic pour détection de changement
|
||||
|
||||
# === MÉTHODE 1 : Template matching direct (~1-10ms) ===
|
||||
try:
|
||||
@@ -922,7 +987,7 @@ def execute_action(action_type: str, params: dict) -> dict:
|
||||
else:
|
||||
pyautogui.click(x, y)
|
||||
|
||||
time.sleep(2.0)
|
||||
_wait_for_screen_change(screen_img)
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
@@ -969,7 +1034,7 @@ def execute_action(action_type: str, params: dict) -> dict:
|
||||
else:
|
||||
pyautogui.click(gx, gy)
|
||||
|
||||
time.sleep(2.0)
|
||||
_wait_for_screen_change(screen_img)
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
|
||||
Reference in New Issue
Block a user