""" Self-hosted text embeddings (fastembed - ONNX runtime, CPU, no API key, no external network call at runtime) for document RAG: turning uploaded text into vectors stored in MongoDB Atlas, and turning the user's question into a vector to search against them. Same reasoning as Piper for voice: a self-hosted model has no external service to be rate-limited or blocked by, which matters on a cloud host. """ import asyncio from functools import lru_cache EMBEDDING_MODEL_NAME = "BAAI/bge-small-en-v1.5" # 384 dimensions, small, fast on CPU @lru_cache(maxsize=1) def _get_model(): from fastembed import TextEmbedding return TextEmbedding(model_name=EMBEDDING_MODEL_NAME) def _embed_sync(texts: list[str]) -> list[list[float]]: model = _get_model() return [vec.tolist() for vec in model.embed(texts)] async def embed_texts(texts: list[str]) -> list[list[float]]: return await asyncio.get_event_loop().run_in_executor(None, _embed_sync, texts) async def embed_text(text: str) -> list[float]: vectors = await embed_texts([text]) return vectors[0]