diff --git a/app/services/embeddings_client.py b/app/services/embeddings_client.py new file mode 100644 index 0000000..4f8636f --- /dev/null +++ b/app/services/embeddings_client.py @@ -0,0 +1,46 @@ +""" +app/services/embeddings_client.py — Text→Embedding (WP-04) + +Zweck: + Liefert 384-d Embeddings für Textqueries (lazy load, einmal pro Prozess). + Standard: Sentence-Transformers (MODEL_NAME aus app.config.Settings). + Hinweis: Kein Netz-Zugriff; nutzt lokal installierte Modelle. +Kompatibilität: + Python 3.12+, sentence-transformers 5.x +Version: + 0.1.0 (Erstanlage) +Stand: + 2025-10-07 +Bezug: + - app/core/retriever.py (nutzt embed_text_if_needed) + - app/config.py (MODEL_NAME, VECTOR_SIZE) +Nutzung: + from app.services.embeddings_client import embed_text +Änderungsverlauf: + 0.1.0 (2025-10-07) – Erstanlage. +""" + +from __future__ import annotations +from typing import List +from functools import lru_cache +from app.config import get_settings + +# Lazy import, damit Testläufe ohne Modell-Laden schnell sind +def _load_model(): + from sentence_transformers import SentenceTransformer # import hier, nicht top-level + s = get_settings() + return SentenceTransformer(s.MODEL_NAME, device="cpu") + +@lru_cache(maxsize=1) +def _cached_model(): + return _load_model() + +def embed_text(text: str) -> List[float]: + """ + Erzeugt einen 384-d Vektor (oder laut Settings.VECTOR_SIZE) für den gegebenen Text. + """ + if not text or not text.strip(): + raise ValueError("embed_text: leerer Text") + model = _cached_model() + vec = model.encode([text], normalize_embeddings=True)[0] + return vec.astype(float).tolist()