fix(ORA): logger.info→print pour que les logs apparaissent dans nohup
Some checks failed
security-audit / Bandit (scan statique) (push) Successful in 12s
security-audit / pip-audit (CVE dépendances) (push) Successful in 12s
security-audit / Scan secrets (grep) (push) Successful in 8s
tests / Lint (ruff + black) (push) Successful in 14s
tests / Tests unitaires (sans GPU) (push) Failing after 15s
tests / Tests sécurité (critique) (push) Has been skipped
Some checks failed
security-audit / Bandit (scan statique) (push) Successful in 12s
security-audit / pip-audit (CVE dépendances) (push) Successful in 12s
security-audit / Scan secrets (grep) (push) Successful in 8s
tests / Lint (ruff + black) (push) Successful in 14s
tests / Tests unitaires (sans GPU) (push) Failing after 15s
tests / Tests sécurité (critique) (push) Has been skipped
Le logging Python ne traverse pas le nohup de Flask. Tous les autres modules (execute.py, intelligent_executor.py) utilisent print(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,15 +14,6 @@ import logging
|
|||||||
import time
|
import time
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# Forcer les logs ORA dans stdout (visible dans nohup)
|
|
||||||
logging.basicConfig(level=logging.INFO, stream=sys.stdout,
|
|
||||||
format='%(message)s', force=False)
|
|
||||||
if not logging.getLogger(__name__).handlers:
|
|
||||||
handler = logging.StreamHandler(sys.stdout)
|
|
||||||
handler.setFormatter(logging.Formatter('%(message)s'))
|
|
||||||
logging.getLogger(__name__).addHandler(handler)
|
|
||||||
logging.getLogger(__name__).setLevel(logging.INFO)
|
|
||||||
import base64
|
import base64
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
@@ -171,7 +162,7 @@ class ORALoop:
|
|||||||
window_title = self._get_active_window_title()
|
window_title = self._get_active_window_title()
|
||||||
ts = time.time()
|
ts = time.time()
|
||||||
|
|
||||||
logger.info(f"👁 [ORA/observe] titre='{window_title}' phash={phash}")
|
print(f"👁 [ORA/observe] titre='{window_title}' phash={phash}")
|
||||||
return Observation(
|
return Observation(
|
||||||
screenshot=screenshot,
|
screenshot=screenshot,
|
||||||
phash=phash,
|
phash=phash,
|
||||||
@@ -284,7 +275,7 @@ class ORALoop:
|
|||||||
expected_after=expected,
|
expected_after=expected,
|
||||||
confidence=confidence,
|
confidence=confidence,
|
||||||
)
|
)
|
||||||
logger.info(f"🧠 [ORA/reason] {decision.action} target='{decision.target}' value='{decision.value[:50]}'")
|
print(f"🧠 [ORA/reason] {decision.action} target='{decision.target}' value='{decision.value[:50]}'")
|
||||||
return decision
|
return decision
|
||||||
|
|
||||||
# ─── Phase 2b : RAISONNE (mode instruction) ─────────
|
# ─── Phase 2b : RAISONNE (mode instruction) ─────────
|
||||||
@@ -363,7 +354,7 @@ Règles:
|
|||||||
ollama_url = os.environ.get("OLLAMA_URL", "http://localhost:11434")
|
ollama_url = os.environ.get("OLLAMA_URL", "http://localhost:11434")
|
||||||
model = os.environ.get("RPA_REASONING_MODEL", "qwen2.5vl:7b")
|
model = os.environ.get("RPA_REASONING_MODEL", "qwen2.5vl:7b")
|
||||||
|
|
||||||
logger.info(f"🧠 [ORA/reason_instruction] Appel VLM {model}...")
|
print(f"🧠 [ORA/reason_instruction] Appel VLM {model}...")
|
||||||
|
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
f"{ollama_url}/api/generate",
|
f"{ollama_url}/api/generate",
|
||||||
@@ -452,7 +443,7 @@ Règles:
|
|||||||
Returns:
|
Returns:
|
||||||
LoopResult.
|
LoopResult.
|
||||||
"""
|
"""
|
||||||
logger.info(f"🚀 [ORA/instruction] Démarrage: '{instruction}' (max {self.max_steps} étapes)")
|
print(f"🚀 [ORA/instruction] Démarrage: '{instruction}' (max {self.max_steps} étapes)")
|
||||||
|
|
||||||
# --- Initialiser le contexte cognitif ---
|
# --- Initialiser le contexte cognitif ---
|
||||||
if COGNITIVE_AVAILABLE and CognitiveContext is not None:
|
if COGNITIVE_AVAILABLE and CognitiveContext is not None:
|
||||||
@@ -467,8 +458,8 @@ Règles:
|
|||||||
return LoopResult(success=False, steps_completed=step_num,
|
return LoopResult(success=False, steps_completed=step_num,
|
||||||
total_steps=self.max_steps, reason="stopped")
|
total_steps=self.max_steps, reason="stopped")
|
||||||
|
|
||||||
logger.info(f"\n{'='*60}")
|
print(f"\n{'='*60}")
|
||||||
logger.info(f"📋 [ORA/instruction] Étape {step_num + 1}/{self.max_steps}")
|
print(f"📋 [ORA/instruction] Étape {step_num + 1}/{self.max_steps}")
|
||||||
|
|
||||||
# --- 1. Observer ---
|
# --- 1. Observer ---
|
||||||
pre = self.observe()
|
pre = self.observe()
|
||||||
@@ -478,7 +469,7 @@ Règles:
|
|||||||
|
|
||||||
# --- Objectif atteint ---
|
# --- Objectif atteint ---
|
||||||
if decision.done:
|
if decision.done:
|
||||||
logger.info(f"✅ [ORA/instruction] Objectif atteint en {step_num + 1} étapes: {decision.reasoning}")
|
print(f"✅ [ORA/instruction] Objectif atteint en {step_num + 1} étapes: {decision.reasoning}")
|
||||||
if self.ctx:
|
if self.ctx:
|
||||||
self.ctx.record_action('done', decision.target, result='Objectif atteint', success=True)
|
self.ctx.record_action('done', decision.target, result='Objectif atteint', success=True)
|
||||||
return LoopResult(
|
return LoopResult(
|
||||||
@@ -555,7 +546,7 @@ Règles:
|
|||||||
if not verification.success:
|
if not verification.success:
|
||||||
retried = False
|
retried = False
|
||||||
for retry in range(self.max_retries):
|
for retry in range(self.max_retries):
|
||||||
logger.info(f"🔄 [ORA/instruction] Retry {retry + 1}/{self.max_retries}")
|
print(f"🔄 [ORA/instruction] Retry {retry + 1}/{self.max_retries}")
|
||||||
pre_retry = self.observe()
|
pre_retry = self.observe()
|
||||||
self.act(decision)
|
self.act(decision)
|
||||||
time.sleep(0.3)
|
time.sleep(0.3)
|
||||||
@@ -563,7 +554,7 @@ Règles:
|
|||||||
verification = self.verify(pre_retry, post_retry, decision)
|
verification = self.verify(pre_retry, post_retry, decision)
|
||||||
if verification.success:
|
if verification.success:
|
||||||
retried = True
|
retried = True
|
||||||
logger.info(f"✅ [ORA/instruction] Retry {retry + 1} réussi")
|
print(f"✅ [ORA/instruction] Retry {retry + 1} réussi")
|
||||||
if self.ctx:
|
if self.ctx:
|
||||||
self.ctx.record_action(
|
self.ctx.record_action(
|
||||||
decision.action, decision.target,
|
decision.action, decision.target,
|
||||||
@@ -615,7 +606,7 @@ Règles:
|
|||||||
if step_params is None:
|
if step_params is None:
|
||||||
step_params = {}
|
step_params = {}
|
||||||
|
|
||||||
logger.info(f"🎯 [ORA/act] {decision.action} target='{decision.target}' value='{decision.value[:50]}'")
|
print(f"🎯 [ORA/act] {decision.action} target='{decision.target}' value='{decision.value[:50]}'")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if decision.action == 'click':
|
if decision.action == 'click':
|
||||||
@@ -686,7 +677,7 @@ Règles:
|
|||||||
distance = self._phash_distance(pre.phash, post.phash)
|
distance = self._phash_distance(pre.phash, post.phash)
|
||||||
change_level = self._classify_change(distance)
|
change_level = self._classify_change(distance)
|
||||||
|
|
||||||
logger.info(f"🔍 [ORA/verify] pHash distance={distance} → {change_level}")
|
print(f"🔍 [ORA/verify] pHash distance={distance} → {change_level}")
|
||||||
|
|
||||||
# Déterminer le succès selon le niveau de changement
|
# Déterminer le succès selon le niveau de changement
|
||||||
if change_level == 'same':
|
if change_level == 'same':
|
||||||
@@ -720,10 +711,10 @@ Règles:
|
|||||||
detail += f" | VLM: matches={matches_expected}, état='{actual_state[:80]}'"
|
detail += f" | VLM: matches={matches_expected}, état='{actual_state[:80]}'"
|
||||||
# Le VLM a le dernier mot
|
# Le VLM a le dernier mot
|
||||||
success = matches_expected
|
success = matches_expected
|
||||||
logger.info(f"🔍 [ORA/verify/VLM] matches={matches_expected} état='{actual_state[:60]}'")
|
print(f"🔍 [ORA/verify/VLM] matches={matches_expected} état='{actual_state[:60]}'")
|
||||||
|
|
||||||
emoji = "✅" if success else "❌"
|
emoji = "✅" if success else "❌"
|
||||||
logger.info(f"{emoji} [ORA/verify] success={success} level={change_level} — {detail[:100]}")
|
print(f"{emoji} [ORA/verify] success={success} level={change_level} — {detail[:100]}")
|
||||||
|
|
||||||
return VerificationResult(
|
return VerificationResult(
|
||||||
success=success,
|
success=success,
|
||||||
@@ -762,15 +753,15 @@ Règles:
|
|||||||
reason=f"Trop d'étapes ({total} > max {self.max_steps})"
|
reason=f"Trop d'étapes ({total} > max {self.max_steps})"
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"🚀 [ORA] Démarrage workflow: {total} étapes, verify={self.verify_level}, retries={self.max_retries}")
|
print(f"🚀 [ORA] Démarrage workflow: {total} étapes, verify={self.verify_level}, retries={self.max_retries}")
|
||||||
|
|
||||||
for i, step in enumerate(steps):
|
for i, step in enumerate(steps):
|
||||||
if not self._should_continue():
|
if not self._should_continue():
|
||||||
logger.info("⛔ [ORA] Arrêt demandé")
|
logger.info("⛔ [ORA] Arrêt demandé")
|
||||||
return LoopResult(success=False, steps_completed=i, total_steps=total, reason="stopped")
|
return LoopResult(success=False, steps_completed=i, total_steps=total, reason="stopped")
|
||||||
|
|
||||||
logger.info(f"\n{'='*60}")
|
print(f"\n{'='*60}")
|
||||||
logger.info(f"📋 [ORA] Étape {i+1}/{total}: {step.get('action_type', '?')} — {step.get('label', '')}")
|
print(f"📋 [ORA] Étape {i+1}/{total}: {step.get('action_type', '?')} — {step.get('label', '')}")
|
||||||
|
|
||||||
# --- 1. Observer l'état pré-action ---
|
# --- 1. Observer l'état pré-action ---
|
||||||
pre = self.observe()
|
pre = self.observe()
|
||||||
@@ -820,7 +811,7 @@ Règles:
|
|||||||
# Réessayer
|
# Réessayer
|
||||||
retried = False
|
retried = False
|
||||||
for retry in range(self.max_retries):
|
for retry in range(self.max_retries):
|
||||||
logger.info(f"🔄 [ORA] Retry {retry+1}/{self.max_retries} pour étape {i+1}")
|
print(f"🔄 [ORA] Retry {retry+1}/{self.max_retries} pour étape {i+1}")
|
||||||
pre_retry = self.observe()
|
pre_retry = self.observe()
|
||||||
act_success = self.act(decision, step)
|
act_success = self.act(decision, step)
|
||||||
time.sleep(0.3)
|
time.sleep(0.3)
|
||||||
@@ -828,7 +819,7 @@ Règles:
|
|||||||
verification = self.verify(pre_retry, post_retry, decision)
|
verification = self.verify(pre_retry, post_retry, decision)
|
||||||
if verification.success:
|
if verification.success:
|
||||||
retried = True
|
retried = True
|
||||||
logger.info(f"✅ [ORA] Retry {retry+1} réussi")
|
print(f"✅ [ORA] Retry {retry+1} réussi")
|
||||||
break
|
break
|
||||||
if not retried and not verification.success:
|
if not retried and not verification.success:
|
||||||
logger.warning(f"❌ [ORA] Étape {i+1} échouée après {self.max_retries} retries")
|
logger.warning(f"❌ [ORA] Étape {i+1} échouée après {self.max_retries} retries")
|
||||||
@@ -841,7 +832,7 @@ Règles:
|
|||||||
if on_progress:
|
if on_progress:
|
||||||
on_progress(i + 1, total, verification)
|
on_progress(i + 1, total, verification)
|
||||||
|
|
||||||
logger.info(f"✅ [ORA] Workflow terminé avec succès: {total}/{total} étapes")
|
print(f"✅ [ORA] Workflow terminé avec succès: {total}/{total} étapes")
|
||||||
return LoopResult(success=True, steps_completed=total, total_steps=total)
|
return LoopResult(success=True, steps_completed=total, total_steps=total)
|
||||||
|
|
||||||
# ═══════════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════════
|
||||||
@@ -872,12 +863,12 @@ Règles:
|
|||||||
try:
|
try:
|
||||||
from core.execution.input_handler import _grounding_ui_tars
|
from core.execution.input_handler import _grounding_ui_tars
|
||||||
click_label = target_desc or target_text
|
click_label = target_desc or target_text
|
||||||
logger.info(f"🎯 [ORA/UI-TARS] Recherche: '{click_label}'")
|
print(f"🎯 [ORA/UI-TARS] Recherche: '{click_label}'")
|
||||||
result = _grounding_ui_tars(target_text, target_desc)
|
result = _grounding_ui_tars(target_text, target_desc)
|
||||||
if result:
|
if result:
|
||||||
x, y = result['x'], result['y']
|
x, y = result['x'], result['y']
|
||||||
method_used = 'ui_tars'
|
method_used = 'ui_tars'
|
||||||
logger.info(f"✅ [ORA/UI-TARS] Trouvé à ({x}, {y})")
|
print(f"✅ [ORA/UI-TARS] Trouvé à ({x}, {y})")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug(f"⚠️ [ORA/UI-TARS] Erreur: {e}")
|
logger.debug(f"⚠️ [ORA/UI-TARS] Erreur: {e}")
|
||||||
|
|
||||||
@@ -902,7 +893,7 @@ Règles:
|
|||||||
result_tm = cv2.matchTemplate(screen_cv, anchor_cv, cv2.TM_CCOEFF_NORMED)
|
result_tm = cv2.matchTemplate(screen_cv, anchor_cv, cv2.TM_CCOEFF_NORMED)
|
||||||
_, max_val, _, max_loc = cv2.minMaxLoc(result_tm)
|
_, max_val, _, max_loc = cv2.minMaxLoc(result_tm)
|
||||||
elapsed_ms = (time.time() - t0) * 1000
|
elapsed_ms = (time.time() - t0) * 1000
|
||||||
logger.info(f"⚡ [ORA/template] score={max_val:.3f} pos={max_loc} ({elapsed_ms:.0f}ms)")
|
print(f"⚡ [ORA/template] score={max_val:.3f} pos={max_loc} ({elapsed_ms:.0f}ms)")
|
||||||
if max_val > 0.75:
|
if max_val > 0.75:
|
||||||
x = max_loc[0] + anchor_cv.shape[1] // 2
|
x = max_loc[0] + anchor_cv.shape[1] // 2
|
||||||
y = max_loc[1] + anchor_cv.shape[0] // 2
|
y = max_loc[1] + anchor_cv.shape[0] // 2
|
||||||
@@ -918,7 +909,7 @@ Règles:
|
|||||||
if result:
|
if result:
|
||||||
x, y = result['x'], result['y']
|
x, y = result['x'], result['y']
|
||||||
method_used = 'ocr'
|
method_used = 'ocr'
|
||||||
logger.info(f"🔍 [ORA/OCR] Trouvé à ({x}, {y})")
|
print(f"🔍 [ORA/OCR] Trouvé à ({x}, {y})")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug(f"⚠️ [ORA/OCR] Erreur: {e}")
|
logger.debug(f"⚠️ [ORA/OCR] Erreur: {e}")
|
||||||
|
|
||||||
@@ -934,7 +925,7 @@ Règles:
|
|||||||
logger.error(f"❌ [ORA/click] Impossible de localiser '{target_text}' — aucune méthode n'a fonctionné")
|
logger.error(f"❌ [ORA/click] Impossible de localiser '{target_text}' — aucune méthode n'a fonctionné")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.info(f"🖱️ [ORA/click] {decision.value} à ({x}, {y}) via {method_used}")
|
print(f"🖱️ [ORA/click] {decision.value} à ({x}, {y}) via {method_used}")
|
||||||
|
|
||||||
if decision.value == 'double':
|
if decision.value == 'double':
|
||||||
pyautogui.doubleClick(x, y)
|
pyautogui.doubleClick(x, y)
|
||||||
@@ -999,7 +990,7 @@ Règles:
|
|||||||
|
|
||||||
# Raccourci clavier normal
|
# Raccourci clavier normal
|
||||||
keys = value.split('+')
|
keys = value.split('+')
|
||||||
logger.info(f"⌨️ [ORA/hotkey] {'+'.join(keys)}")
|
print(f"⌨️ [ORA/hotkey] {'+'.join(keys)}")
|
||||||
pyautogui.hotkey(*keys)
|
pyautogui.hotkey(*keys)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -1010,7 +1001,7 @@ Règles:
|
|||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
timeout_ms = 5000
|
timeout_ms = 5000
|
||||||
|
|
||||||
logger.info(f"⏳ [ORA/wait] {timeout_ms}ms")
|
print(f"⏳ [ORA/wait] {timeout_ms}ms")
|
||||||
time.sleep(timeout_ms / 1000)
|
time.sleep(timeout_ms / 1000)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -1036,7 +1027,7 @@ Règles:
|
|||||||
amount = int(nums[0])
|
amount = int(nums[0])
|
||||||
|
|
||||||
scroll_value = amount if direction in ('up', 'left') else -amount
|
scroll_value = amount if direction in ('up', 'left') else -amount
|
||||||
logger.info(f"📜 [ORA/scroll] {direction} x{amount}")
|
print(f"📜 [ORA/scroll] {direction} x{amount}")
|
||||||
|
|
||||||
if direction in ('left', 'right'):
|
if direction in ('left', 'right'):
|
||||||
pyautogui.hscroll(scroll_value)
|
pyautogui.hscroll(scroll_value)
|
||||||
|
|||||||
Reference in New Issue
Block a user