406 lines
11 KiB
Python
406 lines
11 KiB
Python
"""
|
|
Tests pour le gestionnaire d'apprentissage.
|
|
"""
|
|
|
|
import pytest
|
|
import numpy as np
|
|
import tempfile
|
|
import shutil
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from unittest.mock import Mock, MagicMock
|
|
|
|
from geniusia2.core.learning_manager import LearningManager
|
|
from geniusia2.core.models import Action, TaskProfile
|
|
from geniusia2.core.embeddings_manager import EmbeddingsManager
|
|
from geniusia2.core.logger import Logger
|
|
|
|
|
|
@pytest.fixture
|
|
def temp_dirs():
|
|
"""Crée des répertoires temporaires pour les tests."""
|
|
temp_dir = tempfile.mkdtemp()
|
|
profiles_dir = Path(temp_dir) / "profiles"
|
|
logs_dir = Path(temp_dir) / "logs"
|
|
index_dir = Path(temp_dir) / "index"
|
|
keys_dir = Path(temp_dir) / "keys"
|
|
|
|
profiles_dir.mkdir(parents=True, exist_ok=True)
|
|
logs_dir.mkdir(parents=True, exist_ok=True)
|
|
index_dir.mkdir(parents=True, exist_ok=True)
|
|
keys_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
yield {
|
|
"profiles": str(profiles_dir),
|
|
"logs": str(logs_dir),
|
|
"index": str(index_dir),
|
|
"keys": str(keys_dir)
|
|
}
|
|
|
|
shutil.rmtree(temp_dir)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_embeddings_manager(temp_dirs):
|
|
"""Crée un gestionnaire d'embeddings mocké."""
|
|
return EmbeddingsManager(
|
|
model_name="ViT-B-32",
|
|
index_path=temp_dirs["index"],
|
|
device="cpu"
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_logger(temp_dirs):
|
|
"""Crée un logger mocké."""
|
|
return Logger(
|
|
log_dir=temp_dirs["logs"],
|
|
key_path=temp_dirs["keys"]
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def learning_manager(mock_embeddings_manager, mock_logger, temp_dirs):
|
|
"""Crée une instance du gestionnaire d'apprentissage pour les tests."""
|
|
config = {
|
|
"thresholds": {
|
|
"autopilot_observations": 20,
|
|
"autopilot_concordance": 0.95,
|
|
"confidence_min": 0.90,
|
|
"rollback_confidence": 0.85
|
|
}
|
|
}
|
|
|
|
return LearningManager(
|
|
embeddings_manager=mock_embeddings_manager,
|
|
logger=mock_logger,
|
|
config=config,
|
|
profiles_path=temp_dirs["profiles"]
|
|
)
|
|
|
|
|
|
def test_initialization(learning_manager):
|
|
"""Test l'initialisation du gestionnaire."""
|
|
assert learning_manager.mode == "shadow"
|
|
assert len(learning_manager.tasks) == 0
|
|
assert learning_manager.current_task_id is None
|
|
|
|
|
|
def test_observe_action(learning_manager):
|
|
"""Test l'enregistrement d'une observation."""
|
|
action = Action(
|
|
action_type="click",
|
|
target_element="valider_button",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test Window"
|
|
)
|
|
|
|
learning_manager.observe(action)
|
|
|
|
# Vérifier qu'une tâche a été créée
|
|
assert len(learning_manager.tasks) == 1
|
|
|
|
# Vérifier les propriétés de la tâche
|
|
task_id = list(learning_manager.tasks.keys())[0]
|
|
task = learning_manager.tasks[task_id]
|
|
|
|
assert task.observation_count == 1
|
|
assert task.mode == "shadow"
|
|
assert len(task.action_sequence) == 1
|
|
assert task.window_whitelist == ["Test Window"]
|
|
|
|
|
|
def test_mode_transition_shadow_to_assist(learning_manager):
|
|
"""Test la transition de Shadow vers Assisté."""
|
|
action = Action(
|
|
action_type="click",
|
|
target_element="button",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test"
|
|
)
|
|
|
|
# Observer 5 fois pour déclencher la transition
|
|
for _ in range(5):
|
|
learning_manager.observe(action)
|
|
|
|
task_id = list(learning_manager.tasks.keys())[0]
|
|
task = learning_manager.tasks[task_id]
|
|
|
|
# Devrait être passé en mode Assisté
|
|
assert task.mode == "assist"
|
|
assert task.observation_count == 5
|
|
|
|
|
|
def test_calculate_confidence(learning_manager):
|
|
"""Test le calcul du score de confiance."""
|
|
# Créer une tâche de test
|
|
action = Action(
|
|
action_type="click",
|
|
target_element="button",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test"
|
|
)
|
|
|
|
learning_manager.observe(action)
|
|
task_id = list(learning_manager.tasks.keys())[0]
|
|
|
|
# Calculer la confiance
|
|
confidence = learning_manager.calculate_confidence(
|
|
vision_conf=0.9,
|
|
llm_score=0.8,
|
|
task_id=task_id
|
|
)
|
|
|
|
# Vérifier la formule : 0.6 * 0.9 + 0.3 * 0.8 + 0.1 * 0.0 = 0.78
|
|
assert 0.77 <= confidence <= 0.79
|
|
|
|
|
|
def test_confirm_action_accept(learning_manager):
|
|
"""Test la confirmation d'une action acceptée."""
|
|
action = Action(
|
|
action_type="click",
|
|
target_element="button",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test"
|
|
)
|
|
|
|
learning_manager.observe(action)
|
|
task_id = list(learning_manager.tasks.keys())[0]
|
|
|
|
# Accepter l'action
|
|
learning_manager.confirm_action({
|
|
"type": "accept",
|
|
"task_id": task_id
|
|
})
|
|
|
|
task = learning_manager.tasks[task_id]
|
|
assert task.concordance_rate == 1.0
|
|
|
|
|
|
def test_confirm_action_reject(learning_manager):
|
|
"""Test la confirmation d'une action rejetée."""
|
|
action = Action(
|
|
action_type="click",
|
|
target_element="button",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test"
|
|
)
|
|
|
|
learning_manager.observe(action)
|
|
task_id = list(learning_manager.tasks.keys())[0]
|
|
|
|
# Rejeter l'action
|
|
learning_manager.confirm_action({
|
|
"type": "reject",
|
|
"task_id": task_id
|
|
})
|
|
|
|
task = learning_manager.tasks[task_id]
|
|
assert task.concordance_rate == 0.0
|
|
|
|
|
|
def test_confirm_action_correct(learning_manager):
|
|
"""Test la correction d'une action."""
|
|
action = Action(
|
|
action_type="click",
|
|
target_element="wrong_button",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test"
|
|
)
|
|
|
|
learning_manager.observe(action)
|
|
task_id = list(learning_manager.tasks.keys())[0]
|
|
|
|
# Corriger l'action
|
|
corrected_action = Action(
|
|
action_type="click",
|
|
target_element="correct_button",
|
|
bbox=(200, 100, 50, 30),
|
|
confidence=0.95,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test"
|
|
)
|
|
|
|
learning_manager.confirm_action({
|
|
"type": "correct",
|
|
"task_id": task_id,
|
|
"corrected_action": corrected_action
|
|
})
|
|
|
|
task = learning_manager.tasks[task_id]
|
|
assert task.correction_count == 1
|
|
assert len(task.action_sequence) == 2
|
|
|
|
|
|
def test_should_transition_to_auto(learning_manager):
|
|
"""Test la vérification des critères pour passer en Autopilot."""
|
|
action = Action(
|
|
action_type="click",
|
|
target_element="button",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test"
|
|
)
|
|
|
|
# Observer 20 fois
|
|
for _ in range(20):
|
|
learning_manager.observe(action)
|
|
|
|
task_id = list(learning_manager.tasks.keys())[0]
|
|
task = learning_manager.tasks[task_id]
|
|
|
|
# Définir une concordance élevée
|
|
task.concordance_rate = 0.96
|
|
|
|
# Devrait être éligible pour Autopilot
|
|
assert learning_manager.should_transition_to_auto(task_id)
|
|
|
|
|
|
def test_rollback_if_low_confidence(learning_manager):
|
|
"""Test la rétrogradation en cas de confiance faible."""
|
|
action = Action(
|
|
action_type="click",
|
|
target_element="button",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test"
|
|
)
|
|
|
|
learning_manager.observe(action)
|
|
task_id = list(learning_manager.tasks.keys())[0]
|
|
task = learning_manager.tasks[task_id]
|
|
|
|
# Forcer le mode Auto avec confiance faible
|
|
task.mode = "auto"
|
|
task.confidence_score = 0.85 # En dessous du seuil de 0.90
|
|
|
|
learning_manager.rollback_if_low_confidence(task_id)
|
|
|
|
# Devrait être rétrogradé en Assisté
|
|
assert task.mode == "assist"
|
|
|
|
|
|
def test_evaluate_task(learning_manager):
|
|
"""Test l'évaluation d'une tâche."""
|
|
action = Action(
|
|
action_type="click",
|
|
target_element="button",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test"
|
|
)
|
|
|
|
learning_manager.observe(action)
|
|
task_id = list(learning_manager.tasks.keys())[0]
|
|
|
|
metrics = learning_manager.evaluate_task(task_id)
|
|
|
|
assert "task_id" in metrics
|
|
assert "task_name" in metrics
|
|
assert "mode" in metrics
|
|
assert "observation_count" in metrics
|
|
assert "concordance_rate" in metrics
|
|
assert "confidence_score" in metrics
|
|
assert "correction_count" in metrics
|
|
assert metrics["observation_count"] == 1
|
|
|
|
|
|
def test_get_all_tasks(learning_manager):
|
|
"""Test la récupération de toutes les tâches."""
|
|
# Créer plusieurs tâches
|
|
for i in range(3):
|
|
action = Action(
|
|
action_type="click",
|
|
target_element=f"button_{i}",
|
|
bbox=(100 + i*50, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title=f"Test_{i}"
|
|
)
|
|
learning_manager.observe(action)
|
|
|
|
all_tasks = learning_manager.get_all_tasks()
|
|
|
|
assert len(all_tasks) == 3
|
|
assert all(isinstance(task, dict) for task in all_tasks)
|
|
|
|
|
|
def test_get_task_stats(learning_manager):
|
|
"""Test les statistiques globales."""
|
|
# Créer des tâches dans différents modes
|
|
for i in range(3):
|
|
action = Action(
|
|
action_type="click",
|
|
target_element=f"button_{i}",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title=f"Test_{i}"
|
|
)
|
|
learning_manager.observe(action)
|
|
|
|
stats = learning_manager.get_task_stats()
|
|
|
|
assert "total_tasks" in stats
|
|
assert "shadow_tasks" in stats
|
|
assert "assist_tasks" in stats
|
|
assert "auto_tasks" in stats
|
|
assert stats["total_tasks"] == 3
|
|
|
|
|
|
def test_record_execution(learning_manager):
|
|
"""Test l'enregistrement d'une exécution."""
|
|
action = Action(
|
|
action_type="click",
|
|
target_element="button",
|
|
bbox=(100, 100, 50, 30),
|
|
confidence=0.9,
|
|
embedding=np.random.rand(512).astype(np.float32),
|
|
timestamp=datetime.now(),
|
|
window_title="Test"
|
|
)
|
|
|
|
learning_manager.observe(action)
|
|
task_id = list(learning_manager.tasks.keys())[0]
|
|
|
|
# Enregistrer une exécution
|
|
learning_manager.record_execution({
|
|
"task_id": task_id,
|
|
"confidence": 0.92
|
|
})
|
|
|
|
task = learning_manager.tasks[task_id]
|
|
assert task.confidence_score == 0.92
|
|
assert task.last_execution is not None
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v"])
|