HTML 77.2%
TypeScript 10.5%
Python 9.6%
JavaScript 2.5%
1import type { Metadata } from 'next';2import Link from 'next/link';3import { CompareButton } from '@/components/compare/compare-button';4import { CompareTrayBar } from '@/components/compare/compare-tray-bar';5import { BTN_GHOST, CTRL, Field, FitCell, LicenceLegend, LicencePerms, Methodology, RankChips, SortTh } from '@/components/intelligence/bits';6import { DataStrip, type StripItem, TerminalLayout } from '@/components/layout/terminal';7import { Chip, Estimated, OpennessBadge } from '@/components/ui/badges';8import { DataTable, EmptyRow, Td, Th } from '@/components/ui/data-table';9import { EntityLink } from '@/components/ui/entity';10import { Pagination, withParams } from '@/components/ui/pagination';11import { Note, PageHeader, Section } from '@/components/ui/section';12import { EmptyState, Unavailable } from '@/components/ui/unavailable';13import { WatchButton } from '@/components/watchlist/watch-button';14import { intel, safe } from '@/lib/api';15import { fmtDate, fmtInt, fmtParams, fmtTokens, fmtUsdPerM, num } from '@/lib/format';16import { OPENNESS_LABELS, routes, SITE_NAME, SITE_URL } from '@/lib/site';17import type { OpenItem } from '@/lib/types';1819export const revalidate = 300;20type SP = Record<string, string | undefined>;21const LIMIT = 50;22const SORTS = ['rank', 'release', 'params', 'context', 'downloads', 'name'] as const;23type Sort = (typeof SORTS)[number];24const SORT_LABELS: Record<Sort, string> = { rank: 'Best benchmark rank', release: 'Release date', params: 'Parameters', context: 'Context window', downloads: 'Downloads', name: 'Name' };25const KEYS = ['sort', 'license', 'min_params', 'max_params', 'min_context', 'modality', 'days', 'openness', 'offset'] as const;26const CATS = ['open-source', 'open-weights', 'restricted-weights'] as const;27const CAT_COLOR: Record<string, string> = { 'open-source': 'var(--positive)', 'open-weights': 'var(--series-1)', 'restricted-weights': 'var(--warning)', proprietary: 'var(--ink-3)' };2829function parseScale(v: string | undefined): number | undefined {30 if (!v) return undefined;31 const m = /^\s*([\d.]+)\s*([kmbt])?\s*$/i.exec(v);32 if (!m) return undefined;33 const mult = { k: 1e3, m: 1e6, b: 1e9, t: 1e12 }[(m[2] ?? '').toLowerCase() as 'k' | 'm' | 'b' | 't'] ?? 1;34 const n = Number(m[1]);35 return Number.isFinite(n) ? Math.round(n * mult) : undefined;36}37function pick(sp: SP) {38 const cur: Record<string, string | undefined> = {};39 for (const k of KEYS) if (sp[k]) cur[k] = sp[k];40 const sort: Sort = (SORTS as readonly string[]).includes(cur.sort ?? '') ? (cur.sort as Sort) : 'rank';41 return { cur, sort, offset: Math.max(0, Number(cur.offset) || 0) };42}4344const TITLE = 'Open Model Frontier — downloadable AI models by licence, size, context and rank';45const DESC = 'Every canonical model whose weights can be downloaded — open source, open weights, restricted weights — with its licence permissions (commercial use, redistribution, derivatives, hosting), parameters, context, release date, best benchmark ranks, providers and an estimated fit on 64 GB / 128 GB machines. Measurable openness dimensions, no ideological score.';46export async function generateMetadata({ searchParams }: { searchParams: Promise<SP> }): Promise<Metadata> {47 const { cur } = pick(await searchParams);48 const filtered = Object.keys(cur).some((k) => k !== 'sort');49 return { title: TITLE, description: DESC, alternates: { canonical: routes.open() }, openGraph: { title: `${TITLE} | ${SITE_NAME}`, description: DESC, url: `${SITE_URL}${routes.open()}`, type: 'website', siteName: SITE_NAME }, twitter: { card: 'summary_large_image', title: TITLE, description: DESC }, robots: filtered ? { index: false, follow: true } : undefined };50}5152export default async function OpenPage({ searchParams }: { searchParams: Promise<SP> }) {53 const sp = await searchParams;54 const { cur, sort, offset } = pick(sp);55 const [res, meth] = await Promise.all([safe(intel.open({ sort, license: cur.license, min_params: parseScale(cur.min_params), max_params: parseScale(cur.max_params), min_context: parseScale(cur.min_context), modality: cur.modality, days: cur.days, openness: cur.openness, limit: LIMIT, offset })), safe(intel.methodology())]);56 const href = (patch: Record<string, string | number | undefined | null>) => withParams('/open', cur, patch);57 const defs = meth?.openness?.definitions ?? {};58 const labels: Record<string, string> = { ...OPENNESS_LABELS, 'restricted-weights': 'Restricted weights', ...(meth?.openness?.labels ?? {}) };59 const byCat = res?.summary?.by_category ?? {};60 const catTotal = Object.values(byCat).reduce<number>((n, v) => n + (num(v) ?? 0), 0);61 const items: OpenItem[] = res?.items ?? [];62 const filterCount = Object.keys(cur).filter((k) => k !== 'sort' && k !== 'offset').length;63 const licences = res?.summary?.by_license_top ?? [];6465 const strip: StripItem[] = [66 ...CATS.map((c) => ({ label: labels[c] ?? c, value: fmtInt(byCat[c] ?? 0), definition: defs[c], href: href({ openness: c, offset: undefined }) })),67 { label: 'Downloadable total', value: fmtInt(res?.total), definition: res?.note ?? 'Universe = canonical models whose weights can be downloaded.' },68 { label: 'New in 30 days', value: fmtInt(res?.summary?.new_30d), definition: 'Downloadable models with a release date inside the last 30 days (release_date claim; models without one are not counted).', href: href({ days: 30, offset: undefined }) },69 ];7071 // licence permission matrix over the rows on this page (measurable: each licence's stated permissions)72 const PERMS: { key: 'commercial_use' | 'redistribution' | 'derivatives' | 'hosting'; label: string }[] = [73 { key: 'commercial_use', label: 'Commercial use' },74 { key: 'redistribution', label: 'Redistribution' },75 { key: 'derivatives', label: 'Derivatives' },76 { key: 'hosting', label: 'Hosting' },77 ];78 const matrix = CATS.map((c) => {79 const rows = items.filter((it) => it.dimensions?.openness === c);80 return {81 cat: c,82 n: rows.length,83 cells: PERMS.map((p) => {84 let yes = 0;85 let no = 0;86 let unk = 0;87 for (const it of rows) {88 const l = it.licence;89 if (!l || l.key === null) {90 unk++;91 continue;92 }93 const v = p.key === 'hosting' ? (l.hosting_restrictions === null || l.hosting_restrictions === undefined ? null : !l.hosting_restrictions) : l[p.key];94 if (v === true) yes++;95 else if (v === false) no++;96 else unk++;97 }98 return { yes, no, unk };99 }),100 };101 });102103 const filters = (104 <form action="/open" method="get" className="space-y-3" data-open-filters>105 <Field label="Openness category">106 <select name="openness" defaultValue={cur.openness ?? ''} className={CTRL}>107 <option value="">All downloadable</option>108 {CATS.map((c) => (109 <option key={c} value={c}>110 {labels[c] ?? c}111 </option>112 ))}113 </select>114 </Field>115 <Field label="Licence">116 <select name="license" defaultValue={cur.license ?? ''} className={CTRL}>117 <option value="">Any licence</option>118 {licences.map((l) => (119 <option key={l.key} value={l.key}>120 {l.label} ({fmtInt(l.models)})121 </option>122 ))}123 {cur.license && !licences.some((l) => l.key === cur.license) && <option value={cur.license}>{cur.license}</option>}124 </select>125 </Field>126 <div className="grid grid-cols-2 gap-2">127 <Field label="Params ≥">128 <input name="min_params" defaultValue={cur.min_params ?? ''} placeholder="7B" className={CTRL} />129 </Field>130 <Field label="Params ≤">131 <input name="max_params" defaultValue={cur.max_params ?? ''} placeholder="70B" className={CTRL} />132 </Field>133 </div>134 <Field label="Context ≥">135 <input name="min_context" defaultValue={cur.min_context ?? ''} placeholder="128k" className={CTRL} />136 </Field>137 <Field label="Modality">138 <select name="modality" defaultValue={cur.modality ?? ''} className={CTRL}>139 <option value="">Any</option>140 {['text', 'image', 'audio', 'video', 'embedding'].map((m) => (141 <option key={m} value={m}>142 {m}143 </option>144 ))}145 </select>146 </Field>147 <Field label="Released within">148 <select name="days" defaultValue={cur.days ?? ''} className={CTRL}>149 <option value="">Any date</option>150 <option value="30">30 days</option>151 <option value="90">90 days</option>152 <option value="365">1 year</option>153 </select>154 </Field>155 <Field label="Sort">156 <select name="sort" defaultValue={sort} className={CTRL}>157 {SORTS.map((s) => (158 <option key={s} value={s}>159 {SORT_LABELS[s]}160 </option>161 ))}162 </select>163 </Field>164 <div className="flex gap-2">165 <button type="submit" className="inline-flex h-11 flex-1 items-center justify-center bg-ink lg:h-10 px-3 text-sm font-medium text-canvas hover:opacity-90">166 Apply167 </button>168 <Link href="/open" className={BTN_GHOST}>169 Reset170 </Link>171 </div>172 </form>173 );174175 const inspector = (176 <div className="space-y-4 text-xs leading-relaxed text-ink-2">177 <div>178 <p className="eyebrow mb-1">Openness categories</p>179 <dl className="space-y-1.5">180 {(meth?.openness?.categories ?? [...CATS, 'proprietary']).map((c) => (181 <div key={c}>182 <dt className="font-medium text-ink">{labels[c] ?? c}</dt>183 <dd>{defs[c] ?? '—'}</dd>184 </div>185 ))}186 </dl>187 {meth?.openness?.note && <p className="mt-1.5 text-ink-3">{meth.openness.note}</p>}188 </div>189 <div>190 <p className="eyebrow mb-1">Measured dimensions</p>191 <ul className="mono flex flex-wrap gap-1">192 {(meth?.openness?.dimensions ?? []).map((d) => (193 <li key={d} className="rounded-[3px] bg-surface-2 px-1.5 py-[1px] text-[10px]">194 {d}195 </li>196 ))}197 </ul>198 <p className="mt-1 text-ink-3">Each model page states these booleans with their source; the category is derived from them and the licence ontology.</p>199 </div>200 <p>201 <Link href={routes.licenses()} className="link">Licence ontology</Link> · <Link href="/methodology" className="link">/methodology</Link>202 </p>203 </div>204 );205206 return (207 <TerminalLayout filters={filters} inspector={inspector} filtersTitle="Filters" inspectorTitle="Definitions" storageKey="aia-inspector-open" filterCount={filterCount}>208 <PageHeader eyebrow="Open model frontier" title="Open models" lede="Every canonical model whose weights can be downloaded, described by measurable properties — licence permissions, parameters, context, release, benchmark ranks, providers, estimated local fit. Openness is a set of observed dimensions here, never a score." className="pt-4 md:pt-6" aside={res ? <p className="tnum text-sm text-ink-3">{fmtInt(res.total)} downloadable models</p> : undefined} />209 {!res ? (210 <Unavailable what="Open models" />211 ) : (212 <>213 <DataStrip items={strip} dense />214215 {/* ------------------------------------------------------------------------------- openness explorer */}216 <Section eyebrow="Openness explorer" title="Categories and licence permissions" lede="Left: the downloadable universe by openness category. Right: what the licences on this page allow, counted per category — allowed · restricted · unknown." hairline={false}>217 <div className="grid grid-cols-[minmax(0,1fr)] gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]">218 <div>219 <div className="flex h-5 w-full overflow-hidden rounded-[3px] bg-surface-2" role="img" aria-label="Downloadable models by openness category">220 {CATS.map((c) => {221 const n = num(byCat[c]) ?? 0;222 return n > 0 ? <span key={c} style={{ width: `${(100 * n) / Math.max(1, catTotal)}%`, background: CAT_COLOR[c] }} title={`${labels[c] ?? c}: ${fmtInt(n)}`} /> : null;223 })}224 </div>225 <ul className="mt-2 space-y-1 text-sm">226 {CATS.map((c) => (227 <li key={c} className="flex items-baseline gap-2">228 <span className="inline-block size-2.5 shrink-0 rounded-[2px]" style={{ background: CAT_COLOR[c] }} aria-hidden />229 <Link href={href({ openness: c, offset: undefined })} className="text-ink hover:text-accent">230 {labels[c] ?? c}231 </Link>232 <span className="tnum ml-auto text-ink-2">233 {fmtInt(byCat[c] ?? 0)} <span className="text-ink-3">{catTotal ? `${Math.round((100 * (num(byCat[c]) ?? 0)) / catTotal)}%` : ''}</span>234 </span>235 </li>236 ))}237 </ul>238 <p className="mt-3 text-xs text-ink-3">Top licences: {licences.slice(0, 6).map((l) => `${l.label ?? l.key} (${fmtInt(l.models)})`).join(' · ') || '—'}</p>239 </div>240 <div className="table-scroll">241 <table className="data-table compact" aria-label="Licence permissions by openness category (models on this page)">242 <thead>243 <tr>244 <th scope="col">Category · this page</th>245 {PERMS.map((p) => (246 <th key={p.key} scope="col" className="num">247 {p.label}248 </th>249 ))}250 </tr>251 </thead>252 <tbody>253 {matrix.map((r) => (254 <tr key={r.cat}>255 <th scope="row" className="text-left font-normal">256 <OpennessBadge openness={r.cat} /> <span className="tnum text-xs text-ink-3">n={r.n}</span>257 </th>258 {r.cells.map((c, i) => (259 <td key={PERMS[i]?.key} className="num tnum text-xs">260 {r.n === 0 ? (261 <span className="text-ink-3">—</span>262 ) : (263 <span className="inline-flex items-center gap-1.5">264 <span className="text-positive">{c.yes}</span>265 <span className="text-danger">{c.no}</span>266 <span className="text-ink-3">{c.unk}</span>267 </span>268 )}269 </td>270 ))}271 </tr>272 ))}273 </tbody>274 </table>275 <p className="mt-1.5 text-[11px] text-ink-3">276 Counts read: <span className="text-positive">allowed</span> · <span className="text-danger">restricted</span> · <span>unknown / unclassified</span> — over the {fmtInt(items.length)} models on this page, from each licence's stated terms (ontology).277 </p>278 </div>279 </div>280 </Section>281282 {/* --------------------------------------------------------------------------------------- table */}283 <Section eyebrow="Downloadable models" title={`${fmtInt(res.total)} models · sorted by ${SORT_LABELS[sort].toLowerCase()}`} lede={<LicenceLegend />}>284 <DataTable scroll compact>285 <thead>286 <tr>287 <SortTh active={sort === 'name'} href={href({ sort: 'name', offset: undefined })}>Model</SortTh>288 <Th>Licence · permissions</Th>289 <SortTh active={sort === 'params'} href={href({ sort: 'params', offset: undefined })} num dir="desc">Params</SortTh>290 <SortTh active={sort === 'context'} href={href({ sort: 'context', offset: undefined })} num dir="desc">Context</SortTh>291 <SortTh active={sort === 'release'} href={href({ sort: 'release', offset: undefined })} dir="desc">Release</SortTh>292 <SortTh active={sort === 'rank'} href={href({ sort: undefined, offset: undefined })}>Best results</SortTh>293 <Th num>Providers</Th>294 <Th>295 Fit 64 GB @4bit · 128 GB @8bit <Estimated className="ml-1 align-middle" />296 </Th>297 <Th className="w-40" aria-label="Actions" />298 </tr>299 </thead>300 <tbody>301 {items.length === 0 && <EmptyRow cols={9}>No downloadable model matches these filters.</EmptyRow>}302 {items.map((it) => {303 const d = it.dimensions ?? {};304 const mods = Array.isArray(d.modalities) ? (d.modalities as string[]) : [];305 return (306 <tr key={it.model.id} data-open-row>307 <Td primary>308 <span className="flex flex-wrap items-center gap-x-2 gap-y-0.5">309 <EntityLink e={it.model} />310 {typeof d.openness === 'string' && <OpennessBadge openness={d.openness} />}311 </span>312 <span className="block text-xs text-ink-3">313 {it.model.organization?.name ?? '—'}314 {mods.length ? ` · ${mods.join(', ')}` : ''}315 </span>316 </Td>317 <Td label="Licence">318 <LicencePerms l={it.licence} />319 </Td>320 <Td num label="Params" className="tnum">321 {fmtParams(d.parameter_count)}322 {num(d.active_parameter_count) !== null && num(d.active_parameter_count) !== num(d.parameter_count) && <span className="block text-[10px] text-ink-3">{fmtParams(d.active_parameter_count)} active</span>}323 </Td>324 <Td num label="Context" className="tnum">{fmtTokens(d.context_length)}</Td>325 <Td label="Release" className="tnum text-ink-2 whitespace-nowrap">{typeof d.release_date === 'string' ? fmtDate(d.release_date) : '—'}</Td>326 <Td label="Best results">327 <RankChips ranks={it.best_results} max={3} />328 </Td>329 <Td num label="Providers" className="tnum">330 {fmtInt(it.providers)}331 {num(it.cheapest_output_per_mtok) !== null && <span className="block text-[10px] text-accent-2">from {fmtUsdPerM(it.cheapest_output_per_mtok)} out</span>}332 </Td>333 <Td label="Fit (estimated)" className="text-xs">334 <span className="flex flex-col gap-0.5">335 <FitCell fit={it.hardware_fit?.['4bit_64gb']} compact />336 <FitCell fit={it.hardware_fit?.['8bit_128gb']} compact />337 </span>338 </Td>339 <Td className="text-right">340 <span className="inline-flex flex-wrap justify-end gap-1">341 <CompareButton e={it.model} size="sm" />342 <WatchButton e={it.model} size="sm" />343 </span>344 </Td>345 </tr>346 );347 })}348 </tbody>349 </DataTable>350 <Pagination total={res.total} limit={LIMIT} offset={offset} makeHref={(o) => href({ offset: o || undefined })} className="mt-4" />351 <Note className="mt-3">352 Best results = rank inside each benchmark's primary comparability group; several dimensions are shown side by side and never combined. Fit columns are estimates (64 GB device at 4-bit, 128 GB at 8-bit, 8K context) — method on <Link href="/methodology#estimates" className="link">/methodology</Link>. <Chip>unclassified</Chip> = the raw licence label is not yet mapped in the ontology.353 </Note>354 <Methodology text={res.note} />355 </Section>356 </>357 )}358 <CompareTrayBar />359 </TerminalLayout>360 );361}362