"""Encodage des requêtes en texte libre avec all-MiniLM-L6-v2 (optionnel, chargé paresseusement).""" from __future__ import annotations import os import threading MODEL_NAME = os.environ.get("EMBED_MODEL", "all-MiniLM-L6-v2") _model = None _state = "idle" _lock = threading.Lock() class Unavailable(Exception): pass def state() -> str: return _state def _load(): global _model, _state with _lock: if _model is not None: return _model try: _state = "loading" from sentence_transformers import SentenceTransformer # type: ignore _model = SentenceTransformer(MODEL_NAME) _state = "ready" except Exception as e: # noqa: BLE001 _state = f"unavailable: {type(e).__name__}" raise Unavailable("Recherche sémantique indisponible sur ce serveur (paquet sentence-transformers absent ou modèle non téléchargé). " "Utilisez /projects?q= ou /projects/{id}/similar.") from e return _model def encode(text: str): m = _load() return m.encode([text], normalize_embeddings=True)[0] def preload(): threading.Thread(target=lambda: _safe(_load), daemon=True).start() def _safe(f): try: f() except Exception: pass if os.environ.get("SEMANTIC_PRELOAD", "1") == "1": preload()