"""Embedding provider abstraction for RAG. Uses Voyage AI (voyage-3.5, 1024 dims) as the embedding provider. Supports document and query input types for asymmetric search. """ import logging from typing import Optional from app.core.config import settings logger = logging.getLogger(__name__) async def get_embedding( text: str, input_type: str = "document", ) -> Optional[list[float]]: """Get embedding vector for text using Voyage AI. Args: text: The text to embed. input_type: "document" for indexing, "query" for search queries. Returns: List of floats (1024 dims) or None if embedding service unavailable. """ if not settings.VOYAGE_API_KEY: logger.warning("VOYAGE_API_KEY not set — embedding service unavailable") return None try: import voyageai client = voyageai.AsyncClient(api_key=settings.VOYAGE_API_KEY) result = await client.embed( texts=[text], model=settings.EMBEDDING_MODEL, input_type=input_type, ) return result.embeddings[0] except Exception as e: logger.error("Embedding failed: %s", e) return None async def get_embeddings_batch( texts: list[str], input_type: str = "document", ) -> Optional[list[list[float]]]: """Get embedding vectors for multiple texts in a single API call. Args: texts: List of texts to embed. input_type: "document" for indexing, "query" for search queries. Returns: List of embedding vectors or None if service unavailable. """ if not texts: return [] if not settings.VOYAGE_API_KEY: logger.warning("VOYAGE_API_KEY not set — embedding service unavailable") return None try: import voyageai client = voyageai.AsyncClient(api_key=settings.VOYAGE_API_KEY) result = await client.embed( texts=texts, model=settings.EMBEDDING_MODEL, input_type=input_type, ) return result.embeddings except Exception as e: logger.error("Batch embedding failed: %s", e) return None