Source code for curate_ipsum.rag.embedding_provider

"""
Embedding provider abstraction with local sentence-transformers backend.

sentence-transformers and all-MiniLM-L6-v2 are core dependencies (not optional).
Alternative/larger models can be installed via [embeddings-gpu] or [embeddings-large].

Decision: D-017
"""

from __future__ import annotations

import logging
from abc import ABC, abstractmethod

LOG = logging.getLogger("rag.embedding_provider")


[docs] class EmbeddingProvider(ABC): """Abstract interface for text → embedding vector conversion."""
[docs] @abstractmethod def embed(self, texts: list[str]) -> list[list[float]]: """ Convert a batch of texts into embedding vectors. Returns a list of float vectors, one per input text. """ ...
[docs] @abstractmethod def dimension(self) -> int: """Return the embedding dimensionality.""" ...
[docs] class LocalEmbeddingProvider(EmbeddingProvider): """ Local embedding via sentence-transformers. Default model: all-MiniLM-L6-v2 (384 dimensions, fast, good for code). Install [embeddings-gpu] for GPU acceleration or [embeddings-large] for InstructorEmbedding support. """ def __init__(self, model_name: str = "all-MiniLM-L6-v2") -> None: from sentence_transformers import SentenceTransformer self._model_name = model_name LOG.info("Loading embedding model: %s", model_name) self._model = SentenceTransformer(model_name) self._dim = self._model.get_sentence_embedding_dimension()
[docs] def embed(self, texts: list[str]) -> list[list[float]]: if not texts: return [] embeddings = self._model.encode(texts, show_progress_bar=False) return [e.tolist() for e in embeddings]
[docs] def dimension(self) -> int: return self._dim
[docs] class MockEmbeddingProvider(EmbeddingProvider): """Mock embedding provider for testing. Returns fixed-length zero vectors.""" def __init__(self, dim: int = 384) -> None: self._dim = dim
[docs] def embed(self, texts: list[str]) -> list[list[float]]: return [[0.0] * self._dim for _ in texts]
[docs] def dimension(self) -> int: return self._dim