HTML 77.2%
TypeScript 10.5%
Python 9.6%
JavaScript 2.5%
1"""/prices · /prices/history · /prices/index — append-only pricing table (`valid_to` closes a row).23API 1.1: `/prices` gains `family=`, `org=`, `modality=` filters and `sort=cheapest_frontier`; `/prices/index` becomes the AI Price Index4(daily medians for all / frontier / open / embedding offers, cheapest frontier offer, current distribution, listings and delistings)."""5from __future__ import annotations67from typing import Any89from fastapi import APIRouter, Query, Request1011from aiatlas.api.common import (12 EVENT_COLS,13 EVENT_FROM,14 OPEN_CATEGORIES,15 PAGINATION,16 PRICE_COLS,17 PRICE_FROM,18 ApiError,19 Pagination,20 cached,21 change_event,22 deployment_row,23 page,24 price_row,25 resolve_id,26)27from aiatlas.db import connection, fetch_all, fetch_one, fetch_val28from aiatlas.services.frontier import FRONTIER_METHODOLOGY, frontier_model_ids2930router = APIRouter(prefix="/api/v1/prices", tags=["prices"])31SORTS = {"input": "p.input_per_mtok asc nulls last", "output": "p.output_per_mtok asc nulls last", "model": "m.canonical_name asc", "provider": "pv.canonical_name asc",32 "observed": "p.observed_at desc", "valid_from": "p.valid_from desc", "cheapest_frontier": "p.output_per_mtok asc nulls last"}33BUCKETS = [(0, 0.1), (0.1, 0.5), (0.5, 1), (1, 2), (2, 5), (5, 10), (10, 20), (20, 50), (50, None)]343536@router.get("")37@cached(300)38async def list_prices(request: Request, p: Pagination = PAGINATION, model: str | None = None, provider: str | None = None, sort: str = "model", order: str = "",39 current: int = Query(1, ge=0, le=1), family: str | None = None, org: str | None = None, modality: str | None = None) -> dict[str, Any]:40 if sort not in SORTS:41 raise ApiError(400, f"sort must be one of {', '.join(SORTS)}")42 order_sql = SORTS[sort]43 if order == "desc" and " asc" in order_sql:44 order_sql = order_sql.replace(" asc", " desc")45 elif order == "asc" and " desc" in order_sql:46 order_sql = order_sql.replace(" desc", " asc")47 where = ["p.valid_to is null"] if current else ["true"]48 where.append("m.entity_type in ('model','artifact')")49 params: dict[str, Any] = {}50 frontier_note = None51 async with connection() as conn:52 if model:53 where.append("p.model_id = :model")54 params["model"] = await resolve_id(conn, model)55 if provider:56 where.append("p.provider_id = :provider")57 params["provider"] = await resolve_id(conn, provider)58 if family:59 where.append("(exists (select 1 from entities f where f.id = m.family_id and (f.slug = :family or f.id = :family or f.canonical_name ilike :family)) or m.attributes->>'family' ilike :family)")60 params["family"] = family61 if org:62 where.append("(mo.slug = :org or mo.id = :org or mo.canonical_name ilike :org)")63 params["org"] = org64 if modality:65 where.append("(m.attributes->'modalities' ? :modality or m.attributes->'modalities_input' ? :modality or m.attributes->'modalities_output' ? :modality)")66 params["modality"] = modality67 if sort == "cheapest_frontier":68 ids, _ = await frontier_model_ids(conn)69 where.append("p.model_id = any(cast(:frontier as text[]))")70 where.append("p.output_per_mtok > 0")71 params["frontier"] = sorted(ids)72 frontier_note = FRONTIER_METHODOLOGY73 where_sql = " and ".join(where)74 rows = await fetch_all(conn, f"select {PRICE_COLS} from {PRICE_FROM} where {where_sql} order by {order_sql}, p.id limit :lim offset :off", lim=p.limit, off=p.offset, **params)75 total = await fetch_val(conn, f"select count(*) from {PRICE_FROM} where {where_sql}", **params)76 out = page([price_row(r) for r in rows], int(total or 0), p)77 if frontier_note:78 out["methodology"] = frontier_note79 return out808182@router.get("/history")83@cached(300)84async def price_history(request: Request, model: str | None = None, provider: str | None = None, limit: int = Query(2000, ge=1, le=5000)) -> dict[str, Any]:85 if not model and not provider:86 raise ApiError(400, "model or provider is required")87 where = ["true"]88 params: dict[str, Any] = {"lim": limit}89 async with connection() as conn:90 if model:91 where.append("p.model_id = :model")92 params["model"] = await resolve_id(conn, model)93 if provider:94 where.append("p.provider_id = :provider")95 params["provider"] = await resolve_id(conn, provider)96 rows = await fetch_all(conn, f"select {PRICE_COLS} from {PRICE_FROM} where {' and '.join(where)} order by p.valid_from asc, p.id limit :lim", **params)97 return {"items": [price_row(r) for r in rows]}9899100@router.get("/index")101@cached(600)102async def price_index(request: Request, days: int = Query(180, ge=7, le=1825)) -> dict[str, Any]:103 """AI Price Index: daily medians of live USD-per-1M-token prices, by universe (all offers / frontier / open-weight / embeddings)."""104 async with connection() as conn:105 frontier, composition = await frontier_model_ids(conn)106 open_ids = [r["id"] for r in await fetch_all(conn, "select id from entities where entity_type = 'model' and merged_into is null and attributes->>'openness' = any(cast(:o as text[]))", o=list(OPEN_CATEGORIES))]107 emb_ids = [r["id"] for r in await fetch_all(conn, """select id from entities where entity_type = 'model' and merged_into is null and (attributes->'modalities' ? 'embedding'108 or attributes->'modalities_output' ? 'embedding' or attributes->>'pipeline_tag' ilike '%embedding%')""")]109 series = await fetch_all(conn, """110 with days as (select generate_series(((now() at time zone 'UTC') - make_interval(days => :d))::date::timestamp, (now() at time zone 'UTC')::date::timestamp, interval '1 day')::date as day),111 live as (select p.model_id, p.provider_id, p.input_per_mtok, p.output_per_mtok, p.valid_from, p.valid_to,112 p.model_id = any(cast(:frontier as text[])) as is_frontier, p.model_id = any(cast(:open as text[])) as is_open, p.model_id = any(cast(:emb as text[])) as is_emb113 from prices p join entities m on m.id = p.model_id114 where m.entity_type in ('model','artifact') and m.merged_into is null and ((p.input_per_mtok is not null and p.input_per_mtok > 0) or (p.output_per_mtok is not null and p.output_per_mtok > 0)) and p.valid_from < now())115 select d.day,116 percentile_cont(0.5) within group (order by l.input_per_mtok) filter (where l.input_per_mtok > 0) as median_input,117 percentile_cont(0.5) within group (order by l.output_per_mtok) filter (where l.output_per_mtok > 0) as median_output,118 percentile_cont(0.5) within group (order by l.output_per_mtok) filter (where l.output_per_mtok > 0 and l.is_frontier) as median_frontier_output,119 percentile_cont(0.5) within group (order by l.input_per_mtok) filter (where l.input_per_mtok > 0 and l.is_frontier) as median_frontier_input,120 percentile_cont(0.5) within group (order by l.output_per_mtok) filter (where l.output_per_mtok > 0 and l.is_open) as median_open_output,121 percentile_cont(0.5) within group (order by l.input_per_mtok) filter (where l.input_per_mtok > 0 and l.is_emb) as median_embedding_input,122 min(l.input_per_mtok) filter (where l.input_per_mtok > 0) as min_input, max(l.input_per_mtok) as max_input,123 min(l.output_per_mtok) filter (where l.output_per_mtok > 0 and l.is_frontier) as min_frontier_output,124 count(distinct l.model_id) as models, count(l.model_id) as offers,125 count(distinct l.model_id) filter (where l.is_frontier) as frontier_models, count(l.model_id) filter (where l.is_frontier) as frontier_offers,126 count(distinct l.model_id) filter (where l.is_open) as open_models, count(distinct l.model_id) filter (where l.is_emb) as embedding_models127 from days d left join live l on l.valid_from < (d.day + 1)::timestamp at time zone 'UTC' and (l.valid_to is null or l.valid_to >= (d.day + 1)::timestamp at time zone 'UTC')128 group by d.day order by d.day""", d=days, frontier=sorted(frontier), open=open_ids, emb=emb_ids)129 movers = await fetch_all(conn, f"select {EVENT_COLS} from {EVENT_FROM} where ev.category = 'price' and ev.is_backfill = false and ev.occurred_at > now() - make_interval(days => :d) "130 f"order by ev.importance desc, ev.occurred_at desc limit 30", d=days)131 cheapest = await fetch_one(conn, f"select {PRICE_COLS} from {PRICE_FROM} where p.valid_to is null and p.output_per_mtok > 0 and p.model_id = any(cast(:ids as text[])) "132 f"order by p.output_per_mtok asc, p.input_per_mtok asc nulls last limit 1", ids=sorted(frontier))133 cheapest_1m = await fetch_one(conn, f"""select {PRICE_COLS} from {PRICE_FROM} where p.valid_to is null and p.output_per_mtok > 0 and p.model_id = any(cast(:ids as text[]))134 and coalesce(p.context_length, case when m.attributes->>'context_length' ~ '^[0-9]+$' then (m.attributes->>'context_length')::bigint end) >= 1000000135 order by p.output_per_mtok asc limit 1""", ids=sorted(frontier))136 current_outputs = await fetch_all(conn, "select p.output_per_mtok as v from prices p join entities m on m.id = p.model_id where p.valid_to is null and p.output_per_mtok > 0 and m.merged_into is null")137 new_where = ("p.valid_from > now() - interval '30 days' and not exists (select 1 from prices q where q.model_id = p.model_id and q.provider_id = p.provider_id and q.valid_from < p.valid_from) "138 "and m.entity_type in ('model','artifact') and m.merged_into is null")139 gone_where = "p.valid_to > now() - interval '30 days' and not exists (select 1 from prices q where q.model_id = p.model_id and q.provider_id = p.provider_id and q.valid_to is null)"140 new_rows = await fetch_all(conn, f"select {PRICE_COLS} from {PRICE_FROM} where {new_where} order by p.valid_from desc limit 50")141 new_n = await fetch_val(conn, f"select count(*) from {PRICE_FROM} where {new_where}")142 gone_rows = await fetch_all(conn, f"select {PRICE_COLS} from {PRICE_FROM} where {gone_where} order by p.valid_to desc limit 50")143 gone_n = await fetch_val(conn, f"select count(*) from {PRICE_FROM} where {gone_where}")144 chg_rows = await fetch_all(conn, f"select {EVENT_COLS}, ev.occurred_at from {EVENT_FROM} where ev.category = 'price' and ev.is_backfill = false and ev.occurred_at > now() - interval '30 days' "145 f"order by ev.occurred_at desc limit 50")146 chg_n = await fetch_val(conn, "select count(*) from change_events where category = 'price' and is_backfill = false and occurred_at > now() - interval '30 days'")147 dist = []148 vals = [float(r["v"]) for r in current_outputs]149 for lo, hi in BUCKETS:150 n = sum(1 for v in vals if v >= lo and (hi is None or v < hi))151 dist.append({"from": lo, "to": hi, "label": f"${lo:g}–${hi:g}" if hi is not None else f"≥ ${lo:g}", "offers": n})152 out_series = []153 for r in series:154 out_series.append({"day": r["day"].isoformat(), "median_input": r["median_input"], "median_output": r["median_output"], "median_frontier_output": r["median_frontier_output"],155 "median_frontier_input": r["median_frontier_input"], "median_open_output": r["median_open_output"], "median_embedding_input": r["median_embedding_input"],156 "min_input": r["min_input"], "max_input": r["max_input"], "min_frontier_output": r["min_frontier_output"], "models": int(r["models"] or 0), "offers": int(r["offers"] or 0),157 "sample": {"models": int(r["models"] or 0), "offers": int(r["offers"] or 0), "frontier_models": int(r["frontier_models"] or 0), "frontier_offers": int(r["frontier_offers"] or 0),158 "open_models": int(r["open_models"] or 0), "embedding_models": int(r["embedding_models"] or 0)}})159 return {"days": days, "series": out_series, "movers": [change_event(r) for r in movers],160 "cheapest_frontier": _cheap(cheapest), "cheapest_frontier_1m_context": _cheap(cheapest_1m),161 "distribution": {"metric": "output_per_mtok", "unit": "USD per 1M tokens", "buckets": dist, "offers": len(vals)},162 "new_listings_30d": {"count": int(new_n or 0), "items": [deployment_row(r) for r in new_rows], "definition": "offers whose first row for (model, provider) opened in the last 30 days"},163 "delistings_30d": {"count": int(gone_n or 0), "items": [deployment_row(r) for r in gone_rows], "definition": "offers closed in the last 30 days with no live successor for (model, provider)"},164 "price_changes_30d": {"count": int(chg_n or 0), "items": [_price_event(r) for r in chg_rows], "definition": "price events (not back-filled) that occurred in the last 30 days"},165 "frontier": {"composition": composition, "methodology": FRONTIER_METHODOLOGY},166 "methodology": "Daily medians of live USD-per-1M-token prices across every provider offer valid at the end of each UTC day (offers with a zero or missing price are excluded "167 "from that median). `median_open_output` covers models with openness open-weights/open-source; `median_embedding_input` covers models whose modalities include "168 "embedding. Sample sizes are returned per day; a null median means no offer in that universe on that day. " + FRONTIER_METHODOLOGY,169 "note": "Daily medians of live USD-per-1M-token input/output prices across all provider offers valid at the end of each UTC day."}170171172def _price_event(r: dict[str, Any]) -> dict[str, Any]:173 from aiatlas.api.routers.intelligence import price_delta174175 ev = change_event(r)176 d = price_delta(ev.get("old_value"), ev.get("new_value"))177 ev["occurred_at"] = r.get("occurred_at")178 ev["percent_change"] = d["percent"] if d else None179 ev["price_delta"] = d180 ev["provider"] = (ev.get("meta") or {}).get("provider")181 return ev182183184def _cheap(row: dict[str, Any] | None) -> dict[str, Any] | None:185 if not row:186 return None187 pr = price_row(row)188 return {"model": pr["model"], "provider": pr["provider"], "output": pr["output_per_mtok"], "input": pr["input_per_mtok"], "context_length": pr["context_length"], "price_id": pr["id"]}189190191__all__ = ["BUCKETS", "router"]192