ai-talent-finder-backend / scripts /phase2_phase3_smoke.py
ilyass yani
Deploiement backend dans HF Spaces
9df97a2
Raw
History Blame
5.1 kB
from pathlib import Path
import sys
backend_root = Path(__file__).resolve().parents[1]
if str(backend_root) not in sys.path:
sys.path.insert(0, str(backend_root))
from ai_module.chatbot.conversation_memory import ConversationMemory
from ai_module.nlp.multilingual_skill_extractor import MultilingualSkillExtractor
from scripts.prepare_ner_annotations import prepare_annotations, normalize_spans, spans_to_bio
from datetime import datetime
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from app.core.database import Base
from app.models.models import User, Candidate, JobCriteria, RecruiterFeedback
from ai_module.feedback.recruiter_feedback import RecruiterFeedbackEngine
class FakeRedisClient:
def __init__(self):
self.lists = {}
self.hashes = {}
def ping(self):
return True
def rpush(self, key, value):
self.lists.setdefault(key, []).append(value)
def ltrim(self, key, start, end):
self.lists[key] = self.lists.get(key, [])[start : end + 1 if end != -1 else None]
def expire(self, key, ttl):
return None
def hset(self, key, mapping):
self.hashes.setdefault(key, {}).update(mapping)
def hget(self, key, field):
return self.hashes.get(key, {}).get(field)
def delete(self, *keys):
for key in keys:
self.lists.pop(key, None)
self.hashes.pop(key, None)
def lrange(self, key, start, end):
return self.lists.get(key, [])[start : end + 1 if end != -1 else None]
def keys(self, pattern):
prefix = pattern[:-1] if pattern.endswith("*") else pattern
return [key for key in self.lists if key.startswith(prefix)]
if __name__ == "__main__":
memory = ConversationMemory(client=FakeRedisClient())
memory.add_message("a", "user", "bonjour")
memory.add_message("a", "assistant", "salut")
memory.add_message("b", "user", "hola")
assert [item["content"] for item in memory.get_history("a")] == ["bonjour", "salut"]
assert [item["content"] for item in memory.get_history("b")] == ["hola"]
assert set(memory.list_sessions()) == {"a", "b"}
extractor = MultilingualSkillExtractor()
french = extractor.extract_skills(
"Développeur Python avec expérience en apprentissage automatique, Docker, communication et français courant."
)
assert {"Python", "Machine Learning", "Docker", "Communication", "French"}.issubset({item["name"] for item in french})
spanish = extractor.extract_skills("Ingeniero de datos con aprendizaje automático, SQL, Docker y español fluido.")
assert {"Machine Learning", "SQL", "Docker", "Spanish"}.issubset({item["name"] for item in spanish})
template = prepare_annotations([{"text": "Python developer at ACME"}], mode="template")
assert template[0]["tokens"] == ["Python", "developer", "at", "ACME"]
assert template[0]["ner_tags"] == ["O", "O", "O", "O"]
spans = normalize_spans([
{"start": 7, "end": 13, "label": "SKILL"},
{"start": 27, "end": 31, "label": "ORG"},
])
bio = spans_to_bio("Senior Python developer at ACME", spans)
assert bio["ner_tags"][1] == "B-SKILL"
assert bio["ner_tags"][4] == "B-ORG"
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(bind=engine)
session = sessionmaker(bind=engine)()
recruiter = User(email="recruiter@example.com", hashed_password="x", full_name="Recruiter")
candidate = Candidate(full_name="Alice Smith", email="alice@example.com", raw_text="Python FastAPI Docker")
criteria = JobCriteria(recruiter_id=1, title="Senior Python Developer", description="Need Python and Docker")
session.add_all([recruiter, candidate, criteria])
session.flush()
session.add_all([
RecruiterFeedback(
criteria_id=criteria.id,
candidate_id=candidate.id,
recruiter_id=recruiter.id,
model_predicted_score=62.0,
model_predicted_decision="review",
recruiter_decision="accepted",
recruiter_score_override=85.0,
feedback_reason="Strong interview",
is_override=True,
created_at=datetime.utcnow(),
),
RecruiterFeedback(
criteria_id=criteria.id,
candidate_id=candidate.id,
recruiter_id=recruiter.id,
model_predicted_score=45.0,
model_predicted_decision="rejected",
recruiter_decision="rejected",
is_override=False,
created_at=datetime.utcnow(),
),
])
session.commit()
feedback = RecruiterFeedbackEngine(session)
stats = feedback.get_override_statistics()
assert stats["total_feedback"] == 2
assert stats["override_count"] == 1
assert stats["override_rate"] == 50.0
assert feedback.get_retraining_readiness(min_samples=2, min_override_rate=25.0)["ready"] is True
assert feedback.summarize_by_criteria()[criteria.id]["total"] == 2
assert feedback.prepare_retraining_dataset(min_samples=2)
print("phase2 smoke ok")