SPB Git

spb/ai-atlas

Public
6.1 KB · 102 lines tsx
1import type { Metadata } from 'next';2import Link from 'next/link';3import { DataTable, EmptyRow, Td, Th } from '@/components/ui/data-table';4import { EntityLink } from '@/components/ui/entity';5import { Container, Note, PageHeader } from '@/components/ui/section';6import { EmptyState, Unavailable } from '@/components/ui/unavailable';7import { api, safe } from '@/lib/api';8import { cn } from '@/lib/cn';9import { fmtAgo, fmtInt, fmtScore, num } from '@/lib/format';10import { routes } from '@/lib/site';1112export const metadata: Metadata = { title: 'AI benchmarks & leaderboards', description: 'Benchmarks with their published results, evaluation configs and current leaders — never compared blindly across configs.', alternates: { canonical: '/benchmarks' } };13export const revalidate = 300;1415export default async function BenchmarksPage({ searchParams }: { searchParams: Promise<{ category?: string }> }) {16  const { category } = await searchParams;17  const res = await safe(api.benchmarks());18  const all = (res?.items ?? []).slice().sort((a, b) => (num(b.result_count) ?? 0) - (num(a.result_count) ?? 0));19  const cats = new Map<string, number>();20  for (const b of all) {21    const c = typeof b.attributes?.category === 'string' ? b.attributes.category : null;22    if (c) cats.set(c, (cats.get(c) ?? 0) + 1);23  }24  const catList = [...cats.entries()].sort((x, y) => y[1] - x[1] || x[0].localeCompare(y[0]));25  const items = category ? all.filter((b) => b.attributes?.category === category) : all;26  const chip = (active: boolean) => cn('inline-flex h-8 items-center gap-1.5 border px-2.5 text-xs whitespace-nowrap', active ? 'border-ink bg-ink text-canvas' : 'border-rule text-ink-2 hover:border-rule-strong hover:text-ink');27  return (28    <Container>29      <PageHeader eyebrow="Benchmarks" title="Benchmarks" lede="Evaluation suites and the results published for them. Each result carries its configuration; leaders are shown per benchmark, not as a composite." aside={res ? <p className="tnum text-sm text-ink-3">{fmtInt(items.length)}{category ? ` of ${fmtInt(all.length)}` : ''} benchmarks</p> : undefined}>30        {catList.length > 0 && (31          <nav aria-label="Category" className="no-scrollbar -mx-4 mt-6 flex gap-1.5 overflow-x-auto px-4 md:mx-0 md:flex-wrap md:px-0">32            <Link href={routes.benchmarks()} className={chip(!category)} aria-current={!category ? 'true' : undefined}>33              All <span className="tnum opacity-70">{fmtInt(all.length)}</span>34            </Link>35            {catList.map(([c, n]) => (36              <Link key={c} href={`/benchmarks?category=${encodeURIComponent(c)}`} className={chip(category === c)} aria-current={category === c ? 'true' : undefined}>37                {c} <span className="tnum opacity-70">{fmtInt(n)}</span>38              </Link>39            ))}40          </nav>41        )}42      </PageHeader>43      <div className="pb-16">44        {!res ? (45          <Unavailable what="Benchmarks" />46        ) : items.length === 0 ? (47          <EmptyState title={category ? `No benchmark in “${category}”` : 'No benchmarks recorded yet'}>{category && <Link href={routes.benchmarks()} className="link">Show all benchmarks</Link>}</EmptyState>48        ) : (49          <>50            <DataTable caption="Benchmarks">51              <thead>52                <tr>53                  <Th>Benchmark</Th>54                  <Th>Category</Th>55                  <Th>Metric</Th>56                  <Th num>Results</Th>57                  <Th num>Models</Th>58                  <Th>Current leader</Th>59                  <Th>Updated</Th>60                </tr>61              </thead>62              <tbody>63                {items.length === 0 && <EmptyRow cols={7}>No benchmarks recorded yet.</EmptyRow>}64                {items.map((b) => {65                  const a = b.attributes ?? {};66                  return (67                    <tr key={b.id}>68                      <Td primary>69                        <Link href={routes.benchmark(b.slug)} className="text-ink hover:text-accent hover:underline">{b.name}</Link>70                        {(b.description || typeof a.task === 'string') && <span className="block max-w-md truncate text-xs text-ink-3">{b.description ?? (a.task as string)}</span>}71                      </Td>72                      <Td label="Category" className="text-ink-2">{typeof a.category === 'string' ? <Link href={`/benchmarks?category=${encodeURIComponent(a.category)}`} className="hover:text-accent">{a.category}</Link> : <span className="text-ink-3">—</span>}</Td>73                      <Td label="Metric" className="text-ink-2">74                        {typeof a.metric === 'string' ? a.metric : <span className="text-ink-3">—</span>}75                        {typeof a.unit === 'string' && a.unit && <span className="text-ink-3"> ({a.unit})</span>}76                      </Td>77                      <Td num label="Results" className="tnum">{fmtInt(b.result_count)}</Td>78                      <Td num label="Models" className="tnum text-ink-2">{fmtInt(b.model_count)}</Td>79                      <Td label="Current leader">80                        {b.top ? (81                          <span>82                            <EntityLink e={b.top.model} className="font-medium" /> <span className="tnum text-ink-2">{fmtScore(b.top.score)}{a.unit === '%' ? '%' : ''}</span>83                            {b.top.model.organization && <span className="block text-xs text-ink-3">{b.top.model.organization.name}</span>}84                          </span>85                        ) : (86                          <span className="text-ink-3">—</span>87                        )}88                      </Td>89                      <Td label="Updated" className="text-ink-2" title={b.updated_at}>{fmtAgo(b.updated_at)}</Td>90                    </tr>91                  );92                })}93              </tbody>94            </DataTable>95            <Note className="mt-3">Leader = best current result under the benchmark's default direction (higher or lower is better). Configs differ; open a benchmark for its leaderboard, config filter and per-model history.</Note>96          </>97        )}98      </div>99    </Container>100  );101}102
Files · 9f1db171c786cf4a3b99436329f29b145c02aeec
Menu

Theme