Spaces:
Sleeping
Sleeping
| """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 | |