1"""/providers listing (with pricing aggregates) and /providers/{slug} alias."""2from __future__ import annotations34from typing import Any56from fastapi import APIRouter, Request78from aiatlas.api.common import ENTITY_COLS, ENTITY_FROM, cached, entity_summary9from aiatlas.api.routers.entities import detail_for_type10from aiatlas.db import connection, fetch_all1112router = APIRouter(prefix="/api/v1/providers", tags=["providers"])131415@router.get("")16@cached(300)17async def list_providers(request: Request) -> dict[str, Any]:18 async with connection() as conn:19 rows = await fetch_all(conn, f"""20 select {ENTITY_COLS},21 (select count(distinct p.model_id) from prices p where p.provider_id = e.id and p.valid_to is null) as priced_models,22 (select count(*) from relations r where r.object_id = e.id and r.predicate = 'available_through' and r.valid_to is null) as listed_models,23 (select count(*) from prices p where p.provider_id = e.id and p.valid_to is null) as price_count,24 (select min(p.input_per_mtok) from prices p where p.provider_id = e.id and p.valid_to is null and p.input_per_mtok > 0) as min_input_per_mtok,25 (select min(p.output_per_mtok) from prices p where p.provider_id = e.id and p.valid_to is null and p.output_per_mtok > 0) as min_output_per_mtok26 from {ENTITY_FROM} where e.entity_type = 'provider' and e.merged_into is null27 order by price_count desc, listed_models desc, e.canonical_name""")28 return {"items": [{**(entity_summary(r) or {}), "model_count": int(max(r["priced_models"] or 0, r["listed_models"] or 0)), "price_count": int(r["price_count"] or 0),29 "min_input_per_mtok": r["min_input_per_mtok"], "min_output_per_mtok": r["min_output_per_mtok"]} for r in rows]}303132@router.get("/{slug}")33@cached(300)34async def get_provider(request: Request, slug: str) -> dict[str, Any]:35 return await detail_for_type(slug, ("provider",))36