File size: 2,704 Bytes
d5ef46f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | """
Embedding Service
Handles single embedding operations and serves as the facade for batch processing.
"""
from ...config.logfire_config import search_logger
from ..llm_provider_service import get_llm_client
from .batch_processor import create_embeddings_batch
from .embedding_exceptions import (
EmbeddingAPIError,
EmbeddingError,
EmbeddingQuotaExhaustedError,
EmbeddingRateLimitError,
)
# Provider-aware client factory
get_openai_client = get_llm_client
async def create_embedding(text: str) -> list[float]:
"""
Create an embedding for a single text using the configured provider with failover.
Args:
text: Text to create an embedding for
Returns:
List of floats representing the embedding
Raises:
EmbeddingQuotaExhaustedError: When OpenAI quota is exhausted
EmbeddingRateLimitError: When rate limited
EmbeddingAPIError: For other API errors
"""
try:
result = await create_embeddings_batch([text])
if not result.embeddings:
# Check if there were failures
if result.has_failures and result.failed_items:
# Re-raise the original error for single embeddings
error_info = result.failed_items[0]
error_msg = error_info.get("error", "Unknown error")
if "quota" in error_msg.lower():
raise EmbeddingQuotaExhaustedError(f"OpenAI quota exhausted: {error_msg}", text_preview=text)
elif "rate" in error_msg.lower():
raise EmbeddingRateLimitError(f"Rate limit hit: {error_msg}", text_preview=text)
else:
raise EmbeddingAPIError(f"Failed to create embedding: {error_msg}", text_preview=text)
else:
raise EmbeddingAPIError("No embeddings returned from batch creation", text_preview=text)
return result.embeddings[0]
except EmbeddingError:
# Re-raise our custom exceptions
raise
except Exception as e:
# Convert to appropriate exception type
error_msg = str(e)
search_logger.error(f"Embedding creation failed: {error_msg}", exc_info=True)
search_logger.error(f"Failed text preview: {text[:100]}...")
if "insufficient_quota" in error_msg:
raise EmbeddingQuotaExhaustedError(f"OpenAI quota exhausted: {error_msg}", text_preview=text) from e
elif "rate_limit" in error_msg.lower():
raise EmbeddingRateLimitError(f"Rate limit hit: {error_msg}", text_preview=text) from e
else:
raise EmbeddingAPIError(f"Embedding error: {error_msg}", text_preview=text, original_error=e) from e
|