voice-agent / src /app /services /agent /rag /embeddings.py
Sbboss's picture
RAG, language updates
0b2d478
"""Azure OpenAI embeddings client."""
from __future__ import annotations
from typing import Any
import httpx
import numpy as np
from ....core.config import get_settings
from ....core.errors import LLMError
class AzureEmbeddingClient:
def __init__(self) -> None:
self._settings = get_settings()
def embed(self, texts: list[str]) -> np.ndarray:
if not texts:
return np.zeros((0, 0), dtype=np.float32)
endpoint = self._settings.azure_openai_embeddings_endpoint or self._settings.azure_openai_endpoint
deployment = self._settings.azure_openai_embeddings_deployment
if not endpoint or not deployment:
raise LLMError(
code="llm_config",
message="Azure OpenAI embeddings deployment is not configured.",
)
url = (
f"{endpoint}/openai/deployments/{deployment}/embeddings"
f"?api-version={self._settings.azure_openai_embeddings_api_version}"
)
api_key = (
self._settings.azure_openai_embeddings_api_key
or self._settings.azure_openai_api_key
)
headers = {"api-key": api_key}
payload = {"input": texts}
try:
with httpx.Client(timeout=30.0) as client:
response = client.post(url, json=payload, headers=headers)
response.raise_for_status()
data: dict[str, Any] = response.json()
except httpx.HTTPStatusError as exc:
raise LLMError(
code="llm_http",
message=f"Embeddings request failed with status {exc.response.status_code}.",
details={"body": exc.response.text},
) from exc
except httpx.HTTPError as exc:
raise LLMError(code="llm_http", message="Embeddings request failed.") from exc
try:
vectors = [item["embedding"] for item in data["data"]]
except (KeyError, TypeError) as exc:
raise LLMError(code="llm_response", message="Invalid embeddings response.") from exc
return np.asarray(vectors, dtype=np.float32)
def _normalize_endpoint(self, endpoint: str) -> str:
cleaned = endpoint.rstrip("/")
marker = "/openai/"
if marker in cleaned:
cleaned = cleaned.split(marker, 1)[0]
return cleaned