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%
9.4 KB · 160 lines tsx
Raw Blame History
1import type { Metadata } from 'next';2import { ScrollX } from '@/components/models/scroll-x';3import Link from 'next/link';4import { CompareTrayBar } from '@/components/compare/compare-tray-bar';5import { FilterBar } from '@/components/listing/filters';6import { Chip, EntityBadge } from '@/components/ui/badges';7import { DataTable, EmptyRow, Td, Th } from '@/components/ui/data-table';8import { Hint } from '@/components/ui/hint';9import { Pagination, withParams } from '@/components/ui/pagination';10import { Container, Note, PageHeader } from '@/components/ui/section';11import { Unavailable } from '@/components/ui/unavailable';12import { apiD1, safe } from '@/lib/api';13import { fmtDate, fmtInt, fmtParams, num } from '@/lib/format';14import { routes, SITE_NAME, SITE_URL } from '@/lib/site';1516export const metadata: Metadata = {17  title: 'Model families — releases, parameter ranges, licences & benchmark ranks',18  description: 'Model families (Llama, Qwen, Claude, Gemma…) grouping canonical releases: member count, first and latest release, parameter range, modalities, licence mix and best benchmark ranks — every number from sourced claims.',19  alternates: { canonical: '/families' },20  openGraph: { title: `Model families | ${SITE_NAME}`, url: `${SITE_URL}/families`, type: 'website' },21};22export const revalidate = 600;2324type SP = Record<string, string | undefined>;25const LIMIT = 50;26const SORTS = [27  { value: 'models', label: 'Most models' },28  { value: 'last_release', label: 'Latest release' },29  { value: 'name', label: 'Name' },30];3132export default async function FamiliesPage({ searchParams }: { searchParams: Promise<SP> }) {33  const sp = await searchParams;34  const current: SP = {};35  for (const k of ['q', 'org', 'sort', 'offset']) if (sp[k]) current[k] = sp[k];36  const offset = Math.max(0, Number(current.offset) || 0);37  const sort = current.sort ?? 'models';38  const [page, bench] = await Promise.all([safe(apiD1.families({ q: current.q, org: current.org, sort, limit: LIMIT, offset })), safe(apiD1.benchmarks())]);39  const benchName = new Map((bench?.items ?? []).map((b) => [b.slug, b.name]));40  const href = (patch: Record<string, string | number | undefined | null>) => withParams('/families', current, patch);41  const nonCanonical = (page?.items ?? []).filter((f) => !f.canonical).length;42  const ld = { '@context': 'https://schema.org', '@type': 'CollectionPage', name: 'Model families', url: `${SITE_URL}/families`, description: metadata.description, ...(page ? { mainEntity: { '@type': 'ItemList', numberOfItems: page.total, itemListElement: page.items.slice(0, 10).map((f, i) => ({ '@type': 'ListItem', position: offset + i + 1, name: f.name, url: `${SITE_URL}${routes.family(f.slug)}` })) } } : {}) };4344  return (45    <Container wide>46      <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(ld) }} />47      <PageHeader eyebrow="Families" title="Model families" lede="Families group canonical releases (Llama 3.1, Qwen3, Claude…). Counts, releases and parameter ranges are aggregated from the members' sourced claims; benchmark ranks are the best rank of any member in the benchmark's primary group." aside={page ? <p className="tnum text-sm text-ink-3">{fmtInt(page.total)} families</p> : undefined}>48        <FilterBar action="/families" className="mt-6" resetHref="/families" fields={[{ kind: 'text', name: 'q', label: 'Name', value: current.q, placeholder: 'llama, qwen…' }, { kind: 'text', name: 'org', label: 'Organization slug', value: current.org, placeholder: 'meta-ai' }]} sort={{ value: sort, options: SORTS }} />49      </PageHeader>50      <div className="pb-16">51        {!page ? (52          <Unavailable what="Families" />53        ) : (54          <>55            {nonCanonical > 0 && (56              <p className="mb-2 flex items-center gap-1 text-xs text-ink-3">57                {fmtInt(nonCanonical)} row{nonCanonical === 1 ? '' : 's'} on this page are label-based families (not yet canonical entities)58                <Hint text={page.note ?? 'canonical: true = model_family entity; false = legacy attributes.family label awaiting canonicalisation.'} />59              </p>60            )}61            <ScrollX><DataTable caption="Model families" compact>62              <thead>63                <tr>64                  <Th>Family</Th>65                  <Th>Organization</Th>66                  <Th num>Models</Th>67                  <Th>First · latest release</Th>68                  <Th num>Parameters</Th>69                  <Th>Modalities</Th>70                  <Th>Licences</Th>71                  <Th>Best benchmark ranks</Th>72                </tr>73              </thead>74              <tbody>75                {page.items.length === 0 && <EmptyRow cols={8}>No family matches.</EmptyRow>}76                {page.items.map((f) => {77                  const ranks = Object.entries(f.benchmark_best ?? {})78                    .sort((a, b) => a[1].rank - b[1].rank)79                    .slice(0, 3);80                  const pmin = num(f.param_range?.min);81                  const pmax = num(f.param_range?.max);82                  return (83                    <tr key={f.slug}>84                      <Td primary>85                        <span className="flex flex-wrap items-center gap-x-2">86                          <Link href={routes.family(f.slug)} className="text-ink hover:text-accent hover:underline">87                            {f.name}88                          </Link>89                          {!f.canonical && (90                            <span className="inline-flex items-center gap-0.5 text-[10px] uppercase tracking-wide text-warning" title="Label-based family: grouped by the source's family label, not yet a canonical entity">91                              label92                            </span>93                          )}94                        </span>95                      </Td>96                      <Td label="Organization" className="text-ink-2">97                        {f.organization ? (98                          <Link href={routes.entity({ entity_type: 'company', slug: f.organization.slug })} className="hover:text-accent">99                            {f.organization.name}100                          </Link>101                        ) : (102                          '—'103                        )}104                      </Td>105                      <Td num label="Models" className="tnum">106                        {fmtInt(f.model_count)}107                      </Td>108                      <Td label="First · latest release" className="tnum text-ink-2 whitespace-nowrap">109                        {f.first_release ? fmtDate(f.first_release) : '—'} <span className="text-ink-3">·</span> {f.last_release ? fmtDate(f.last_release) : '—'}110                      </Td>111                      <Td num label="Parameters" className="tnum text-ink-2 whitespace-nowrap">112                        {pmin === null ? '—' : pmin === pmax ? fmtParams(pmin) : `${fmtParams(pmin)} – ${fmtParams(pmax)}`}113                      </Td>114                      <Td label="Modalities">115                        <span className="flex flex-wrap gap-1">{f.modalities?.length ? f.modalities.map((m) => <Chip key={m}>{m}</Chip>) : <span className="text-ink-3">—</span>}</span>116                      </Td>117                      <Td label="Licences" className="text-xs text-ink-2">118                        {f.licenses?.length ? (119                          <span className="flex flex-wrap gap-x-2 gap-y-0.5">120                            {f.licenses.slice(0, 3).map((l) => (121                              <Link key={l.key} href={`/licenses/${encodeURIComponent(l.key)}`} className="hover:text-accent" title={l.label}>122                                {l.key} <span className="tnum text-ink-3">{fmtInt(l.models)}</span>123                              </Link>124                            ))}125                            {f.licenses.length > 3 && <span className="text-ink-3">+{f.licenses.length - 3}</span>}126                          </span>127                        ) : (128                          <span className="text-ink-3">—</span>129                        )}130                      </Td>131                      <Td label="Best benchmark ranks" className="text-xs text-ink-2">132                        {ranks.length ? (133                          <span className="flex flex-wrap gap-x-2 gap-y-0.5">134                            {ranks.map(([slug, r]) => (135                              <Link key={slug} href={routes.benchmark(slug)} className="whitespace-nowrap hover:text-accent" title={`${benchName.get(slug) ?? slug}: rank ${r.rank} (${r.model})`}>136                                {(benchName.get(slug) ?? slug).replace('Artificial Analysis ', 'AA ')} <span className="tnum font-medium text-ink">#{fmtInt(r.rank)}</span>137                              </Link>138                            ))}139                          </span>140                        ) : (141                          <span className="text-ink-3">no results</span>142                        )}143                      </Td>144                    </tr>145                  );146                })}147              </tbody>148            </DataTable></ScrollX>149            <Pagination total={page.total} limit={LIMIT} offset={offset} makeHref={(o) => href({ offset: o || undefined })} className="mt-4" />150            <Note className="mt-3">151              <EntityBadge type="model_family" small /> {page.note ?? 'Families are canonical model_family entities; legacy labels appear as label-based rows until canonicalised.'}152            </Note>153          </>154        )}155      </div>156      <CompareTrayBar />157    </Container>158  );159}160