Add ikario_processual with David profile and embedding script
- david_profile_declared.json: David's declared profile values from questionnaire - scripts/embed_david.py: Python script to generate embeddings using BGE-M3 model - questionnaire_david.md: Questionnaire template for profile values Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
210
ikario_processual/tests/test_phase2_directions.py
Normal file
210
ikario_processual/tests/test_phase2_directions.py
Normal file
@@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Tests pour la Phase 2: Directions de Projection.
|
||||
|
||||
Usage:
|
||||
pytest tests/test_phase2_directions.py -v
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
import numpy as np
|
||||
|
||||
# Ajouter le parent au path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from state_vector import (
|
||||
check_weaviate_ready,
|
||||
get_state_vector,
|
||||
WEAVIATE_URL,
|
||||
)
|
||||
from projection_directions import (
|
||||
get_existing_classes,
|
||||
get_direction,
|
||||
get_all_directions,
|
||||
get_state_profile,
|
||||
project_state_on_direction,
|
||||
DIRECTIONS_CONFIG,
|
||||
)
|
||||
|
||||
|
||||
def weaviate_is_available() -> bool:
|
||||
"""Verifie si Weaviate est accessible."""
|
||||
return check_weaviate_ready()
|
||||
|
||||
|
||||
# Skip tous les tests si Weaviate n'est pas disponible
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not weaviate_is_available(),
|
||||
reason=f"Weaviate non disponible sur {WEAVIATE_URL}"
|
||||
)
|
||||
|
||||
|
||||
class TestProjectionDirectionCollection:
|
||||
"""Tests de la collection ProjectionDirection."""
|
||||
|
||||
def test_collection_exists(self):
|
||||
"""La collection ProjectionDirection doit exister."""
|
||||
classes = get_existing_classes()
|
||||
assert "ProjectionDirection" in classes
|
||||
|
||||
def test_all_directions_created(self):
|
||||
"""Toutes les directions configurees doivent exister."""
|
||||
directions = get_all_directions()
|
||||
direction_names = [d["name"] for d in directions]
|
||||
|
||||
for name in DIRECTIONS_CONFIG.keys():
|
||||
assert name in direction_names, f"Direction manquante: {name}"
|
||||
|
||||
def test_directions_count(self):
|
||||
"""Le nombre de directions doit correspondre a la config."""
|
||||
directions = get_all_directions()
|
||||
assert len(directions) == len(DIRECTIONS_CONFIG)
|
||||
|
||||
|
||||
class TestDirectionVectors:
|
||||
"""Tests des vecteurs de direction."""
|
||||
|
||||
def test_curiosity_direction_exists(self):
|
||||
"""La direction 'curiosity' doit exister."""
|
||||
direction = get_direction("curiosity")
|
||||
assert direction is not None
|
||||
assert direction["name"] == "curiosity"
|
||||
assert direction["category"] == "epistemic"
|
||||
|
||||
def test_direction_has_vector(self):
|
||||
"""Chaque direction doit avoir un vecteur."""
|
||||
direction = get_direction("curiosity")
|
||||
assert direction is not None
|
||||
|
||||
vector = direction.get("_additional", {}).get("vector")
|
||||
assert vector is not None
|
||||
assert len(vector) > 0
|
||||
|
||||
def test_direction_vector_is_1024_dim(self):
|
||||
"""Les vecteurs de direction doivent etre 1024-dim."""
|
||||
direction = get_direction("curiosity")
|
||||
assert direction is not None
|
||||
|
||||
vector = direction.get("_additional", {}).get("vector")
|
||||
assert len(vector) == 1024
|
||||
|
||||
def test_direction_vector_is_normalized(self):
|
||||
"""Les vecteurs de direction doivent etre normalises."""
|
||||
direction = get_direction("curiosity")
|
||||
assert direction is not None
|
||||
|
||||
vector = np.array(direction.get("_additional", {}).get("vector"))
|
||||
norm = np.linalg.norm(vector)
|
||||
|
||||
assert abs(norm - 1.0) < 0.01, f"Norme: {norm}"
|
||||
|
||||
def test_all_categories_present(self):
|
||||
"""Toutes les categories doivent etre representees."""
|
||||
directions = get_all_directions()
|
||||
categories = set(d["category"] for d in directions)
|
||||
|
||||
expected_categories = {"epistemic", "affective", "relational", "vital", "philosophical"}
|
||||
assert categories == expected_categories
|
||||
|
||||
|
||||
class TestProjection:
|
||||
"""Tests des fonctions de projection."""
|
||||
|
||||
def test_projection_in_range(self):
|
||||
"""Les projections doivent etre entre -1 et 1."""
|
||||
s0 = get_state_vector(0)
|
||||
assert s0 is not None
|
||||
|
||||
state_vec = np.array(s0.get("_additional", {}).get("vector"))
|
||||
profile = get_state_profile(state_vec)
|
||||
|
||||
for category, components in profile.items():
|
||||
for name, value in components.items():
|
||||
assert -1 <= value <= 1, f"{name} = {value} hors limites [-1, 1]"
|
||||
|
||||
def test_get_state_profile_structure(self):
|
||||
"""Le profil doit avoir la bonne structure."""
|
||||
s0 = get_state_vector(0)
|
||||
assert s0 is not None
|
||||
|
||||
state_vec = np.array(s0.get("_additional", {}).get("vector"))
|
||||
profile = get_state_profile(state_vec)
|
||||
|
||||
# Verifier que c'est un dict de dicts
|
||||
assert isinstance(profile, dict)
|
||||
for category, components in profile.items():
|
||||
assert isinstance(components, dict)
|
||||
for name, value in components.items():
|
||||
assert isinstance(value, float)
|
||||
|
||||
def test_projection_orthogonal_vectors(self):
|
||||
"""Test de projection avec des vecteurs orthogonaux."""
|
||||
# Deux vecteurs orthogonaux ont une projection de 0
|
||||
v1 = np.zeros(1024)
|
||||
v1[0] = 1.0
|
||||
|
||||
v2 = np.zeros(1024)
|
||||
v2[1] = 1.0
|
||||
|
||||
projection = project_state_on_direction(v1, v2)
|
||||
assert abs(projection) < 0.001
|
||||
|
||||
def test_projection_parallel_vectors(self):
|
||||
"""Test de projection avec des vecteurs paralleles."""
|
||||
v = np.random.randn(1024)
|
||||
v = v / np.linalg.norm(v)
|
||||
|
||||
projection = project_state_on_direction(v, v)
|
||||
assert abs(projection - 1.0) < 0.001
|
||||
|
||||
def test_projection_antiparallel_vectors(self):
|
||||
"""Test de projection avec des vecteurs antiparalleles."""
|
||||
v = np.random.randn(1024)
|
||||
v = v / np.linalg.norm(v)
|
||||
|
||||
projection = project_state_on_direction(v, -v)
|
||||
assert abs(projection + 1.0) < 0.001
|
||||
|
||||
|
||||
class TestS0Profile:
|
||||
"""Tests du profil de S(0)."""
|
||||
|
||||
def test_s0_has_profile(self):
|
||||
"""S(0) doit avoir un profil calculable."""
|
||||
s0 = get_state_vector(0)
|
||||
assert s0 is not None
|
||||
|
||||
state_vec = np.array(s0.get("_additional", {}).get("vector"))
|
||||
profile = get_state_profile(state_vec)
|
||||
|
||||
assert len(profile) > 0
|
||||
|
||||
def test_s0_profile_has_all_categories(self):
|
||||
"""Le profil de S(0) doit avoir toutes les categories."""
|
||||
s0 = get_state_vector(0)
|
||||
assert s0 is not None
|
||||
|
||||
state_vec = np.array(s0.get("_additional", {}).get("vector"))
|
||||
profile = get_state_profile(state_vec)
|
||||
|
||||
expected = {"epistemic", "affective", "relational", "vital", "philosophical"}
|
||||
assert set(profile.keys()) == expected
|
||||
|
||||
def test_s0_has_curiosity_component(self):
|
||||
"""S(0) doit avoir une composante curiosity."""
|
||||
s0 = get_state_vector(0)
|
||||
assert s0 is not None
|
||||
|
||||
state_vec = np.array(s0.get("_additional", {}).get("vector"))
|
||||
profile = get_state_profile(state_vec)
|
||||
|
||||
assert "curiosity" in profile.get("epistemic", {})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-v"])
|
||||
Reference in New Issue
Block a user