import type { Metadata } from 'next'; import Link from 'next/link'; import { CompareTrayBar } from '@/components/compare/compare-tray-bar'; import { type Current, MODEL_PARAM_KEYS, MODEL_SORTS, ModelsFilterRail, modelsHref, UnderstoodChips } from '@/components/models/models-filters'; import { ModelsTable, ModelsTerminal } from '@/components/models/models-terminal'; import { parseScale } from '@/components/models/shared'; import { Hint } from '@/components/ui/hint'; import { Pagination } from '@/components/ui/pagination'; import { Container, Note } from '@/components/ui/section'; import { Unavailable } from '@/components/ui/unavailable'; import { api, apiD1, safe } from '@/lib/api'; import { fmtInt } from '@/lib/format'; import { routes, SITE_NAME, SITE_URL } from '@/lib/site'; export const metadata: Metadata = { title: 'AI models — parameters, context, openness, licences & pricing', description: 'Every canonical AI model release in the atlas: parameters, context window, openness, canonical licence, release date and data quality — filterable, sortable and shareable, with provenance on every value.', alternates: { canonical: '/models' }, openGraph: { title: `AI models — parameters, context, openness, licences & pricing | ${SITE_NAME}`, url: `${SITE_URL}/models`, type: 'website' }, }; export const revalidate = 120; type SP = Record; const LIMIT = 50; export default async function ModelsPage({ searchParams }: { searchParams: Promise }) { const sp = await searchParams; const current: Current = {}; for (const k of MODEL_PARAM_KEYS) if (sp[k]) current[k] = sp[k]; const offset = Math.max(0, Number(current.offset) || 0); const sort = current.sort ?? 'updated'; const order = current.order; const [page, stats] = await Promise.all([ safe( apiD1.models({ q: current.q, org: current.org, family: current.family, openness: current.openness, modality: current.modality, status: current.status, license: current.license, trust: current.trust, reasoning: current.reasoning, include: current.include, min_params: parseScale(current.min_params), max_params: parseScale(current.max_params), min_context: parseScale(current.min_context), year_from: current.year_from, year_to: current.year_to, sort, order, limit: LIMIT, offset, facets: 1, }), ), safe(api.stats()), ]); const href = (patch: Record) => modelsHref(current, patch); const sortHref: Record = {}; for (const s of [...MODEL_SORTS.map((x) => x.value)]) sortHref[s] = href({ sort: s, order: sort === s && order !== 'asc' ? 'asc' : undefined, offset: undefined }); const filterCount = Object.keys(current).filter((k) => !['sort', 'order', 'offset'].includes(k)).length; const artifacts = current.include === 'artifacts'; const definition = stats?.definitions?.models ?? page?.facets?.definitions?.models ?? 'Canonical model releases; artifacts, quantisations, conversions and folded evaluation variants are excluded.'; const artifactsDef = stats?.definitions?.artifacts; const ld = { '@context': 'https://schema.org', '@type': 'CollectionPage', name: 'AI models', url: `${SITE_URL}/models`, description: metadata.description, isPartOf: { '@type': 'WebSite', name: SITE_NAME, url: SITE_URL }, ...(page ? { mainEntity: { '@type': 'ItemList', numberOfItems: page.total, itemListElement: page.items.slice(0, 10).map((m, i) => ({ '@type': 'ListItem', position: offset + i + 1, url: `${SITE_URL}${routes.entity(m)}`, name: m.name })) } } : {}) }; return ( <>