SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%
20.1 KB · 362 lines tsx
Raw Blame History
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&apos;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&apos;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