aristotle-api / app /services /model.py
Bukunmi2108's picture
Deploy API
cb6dcf8 verified
Raw
History Blame Contribute Delete
3.33 kB
from time import perf_counter
import httpx
from app.config import ApiSettings
from app.model_health import get_provider_unavailable
from app.models import ServiceStatus
class ModelClient:
def __init__(self, http: httpx.AsyncClient, settings: ApiSettings):
self.http = http
self.settings = settings
async def status(self) -> ServiceStatus:
primary_unavailable = get_provider_unavailable("primary")
primary = None
if primary_unavailable is None:
primary = await self._provider_status(
base_url=self.settings.primary_model_base_url,
model_name=self.settings.primary_model_name,
api_key=self.settings.primary_model_api_key,
)
if primary.ok:
return primary
if self.settings.model_fallback_enabled:
fallback = await self._provider_status(
base_url=self.settings.fallback_model_base_url,
model_name=self.settings.fallback_model_name,
api_key=self.settings.fallback_model_api_key,
)
if fallback.ok:
return fallback
return ServiceStatus(
ok=False,
service="model",
url=self.settings.primary_model_base_url,
error=primary_unavailable.reason
if primary_unavailable is not None
else primary.error
if primary is not None
else "Primary model is unavailable.",
)
async def is_ready(self) -> bool:
return (await self.status()).ok
async def _provider_status(
self,
*,
base_url: str,
model_name: str,
api_key: str | None,
) -> ServiceStatus:
started = perf_counter()
if not api_key:
return ServiceStatus(
ok=False,
service="model",
url=base_url,
model=model_name,
error="API key is not configured.",
)
try:
response = await self.http.get(
f"{base_url}/models",
timeout=20,
headers={"Authorization": f"Bearer {api_key}"},
)
response.raise_for_status()
self._verify_model_available(response.json(), model_name)
except Exception as exc:
return ServiceStatus(
ok=False,
service="model",
url=base_url,
model=model_name,
error=str(exc),
)
return ServiceStatus(
ok=True,
service="model",
url=base_url,
model=model_name,
latency_ms=int((perf_counter() - started) * 1000),
)
def _verify_model_available(self, payload: object, model_name: str) -> None:
if not isinstance(payload, dict):
return
models = payload.get("data")
if not isinstance(models, list):
return
ids = {
model.get("id")
for model in models
if isinstance(model, dict) and isinstance(model.get("id"), str)
}
if ids and model_name not in ids:
raise ValueError(f"Model {model_name!r} is not listed by provider.")