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%
14.3 KB · 313 lines tsx
Raw Blame History
1import { Chip, TierBadge } from '@/components/ui/badges';2import { DataTable, Td, Th } from '@/components/ui/data-table';3import { EntityLink } from '@/components/ui/entity';4import { Note } from '@/components/ui/section';5import { cn } from '@/lib/cn';6import { fmtAgo, fmtDate, fmtScore, fmtUsdPerM, fmtValue, num } from '@/lib/format';7import { routes } from '@/lib/site';8import type { BenchmarkResult, CompareDimension, ComparePayload, Price, ProvenanceEntry } from '@/lib/types';9import { CompareButton } from './compare-button';1011/* ------------------------------------------------------------------------------------------------------ helpers */1213const PRICE_KEYS = new Set(['best_input_per_mtok', 'best_output_per_mtok', 'min_input_per_mtok', 'min_output_per_mtok']);14/** Numeric dimensions where lower is better. */15function lowerIsBetter(key: string): boolean {16  return PRICE_KEYS.has(key) || /tdp|price|latency/.test(key);17}1819function host(url: string | null | undefined): string | null {20  if (!url) return null;21  try {22    return new URL(url).hostname.replace(/^www\./, '');23  } catch {24    return null;25  }26}2728/** Compact per-cell provenance: T1 · host · 3 h ago (full text in title). */29function CellProvenance({ p }: { p: ProvenanceEntry }) {30  const h = p.source_name ?? host(p.url) ?? 'source';31  return (32    <span className="mt-0.5 hidden items-center gap-1 text-[11px] leading-4 text-ink-3 md:flex">33      <TierBadge tier={p.tier} />34      {p.url ? (35        <a href={p.url} target="_blank" rel="noopener noreferrer" className="max-w-[10rem] truncate hover:text-accent">36          {h}37        </a>38      ) : (39        <span className="max-w-[10rem] truncate">{h}</span>40      )}41      <span>· {fmtAgo(p.observed_at)}</span>42    </span>43  );44}4546function CellValue({ v, dim }: { v: unknown; dim: CompareDimension }) {47  if (v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0)) return <span className="text-ink-3">Unavailable</span>;48  switch (dim.kind) {49    case 'date':50      return <>{fmtDate(String(v))}</>;51    case 'bool':52      return <>{v ? 'Yes' : 'No'}</>;53    case 'list': {54      const arr = Array.isArray(v) ? v : [v];55      return (56        <span className="flex flex-wrap gap-1">57          {arr.map((x, i) => (58            <Chip key={i}>{typeof x === 'object' && x ? JSON.stringify(x) : String(x)}</Chip>59          ))}60        </span>61      );62    }63    case 'number':64      if (PRICE_KEYS.has(dim.key)) return <span className="text-accent-2">{fmtUsdPerM(v)}</span>;65      return <>{fmtValue(v, dim.key)}</>;66    default:67      return <>{typeof v === 'string' ? v : fmtValue(v, dim.key)}</>;68  }69}7071const STICKY = 'sticky left-0 z-10 bg-canvas';72/** First-column width: table layout ignores max-width, so set width + min-width explicitly. */73const FIRST = 'w-[9rem] min-w-[9rem] md:w-[12rem] md:min-w-[12rem]';74/** `.table-scroll td { white-space: nowrap }` out-specifies utilities — wrap the first column inline. */75const WRAP = { whiteSpace: 'normal' } as const;7677/** Horizontal scroll wrapper without the negative page margins (so the sticky column pins at the very left edge). */78function ScrollTable({ children, caption, className }: { children: React.ReactNode; caption: string; className?: string }) {79  return (80    <div className="table-scroll">81      <DataTable stack={false} caption={caption} className={className}>82        {children}83      </DataTable>84    </div>85  );86}8788function EntityHead({ e }: { e: ComparePayload['items'][number]['entity'] }) {89  return (90    <span className="flex flex-col items-start gap-1 normal-case tracking-normal">91      <EntityLink e={e} className="text-sm font-semibold whitespace-normal" />92      {e.organization && <span className="text-[11px] font-normal text-ink-3">{e.organization.name}</span>}93      <CompareButton e={e} size="sm" label="Add" />94    </span>95  );96}9798/* ------------------------------------------------------------------------------------------------------ matrix */99100/** Dimension × entity matrix: sticky first column, horizontal scroll, kind-aware formatting, per-cell provenance. */101export function CompareMatrix({ res }: { res: ComparePayload }) {102  return (103    <>104      <ScrollTable caption="Comparison matrix" className="compare-matrix">105        <thead>106          <tr>107            <Th className={cn(STICKY, FIRST)} style={WRAP}>Dimension</Th>108            {res.items.map((it) => (109              <Th key={it.entity.id} className="min-w-[10rem] align-top">110                <EntityHead e={it.entity} />111              </Th>112            ))}113          </tr>114        </thead>115        <tbody>116          {res.dimensions.map((dim) => {117            const nums = res.items.map((it) => num(it.values[dim.key]));118            const present = nums.filter((n): n is number => n !== null);119            const best = dim.kind === 'number' && present.length > 1 ? (lowerIsBetter(dim.key) ? Math.min(...present) : Math.max(...present)) : null;120            return (121              <tr key={dim.key}>122                <Td className={cn(STICKY, FIRST, 'text-ink-2')} style={WRAP}>123                  {dim.label}124                  {dim.unit && <span className="block text-[11px] text-ink-3">{dim.unit}</span>}125                </Td>126                {res.items.map((it, i) => {127                  const v = it.values[dim.key];128                  const p = it.provenance?.[dim.key];129                  const isBest = best !== null && nums[i] === best;130                  return (131                    <Td key={it.entity.id} className={cn('align-top', dim.kind === 'number' && 'tnum', dim.kind === 'list' && 'whitespace-normal')} title={p ? `${p.source_name ?? host(p.url) ?? ''} · tier ${p.tier} · ${fmtDate(p.observed_at)}` : undefined}>132                      <span className={cn('block', isBest && 'font-semibold text-ink')}>133                        <CellValue v={v} dim={dim} />134                      </span>135                      {p && <CellProvenance p={p} />}136                    </Td>137                  );138                })}139              </tr>140            );141          })}142        </tbody>143      </ScrollTable>144      <Note className="mt-3">Bold marks the best number in a row (highest, or lowest for prices); it is not a verdict. Each value carries its own source and tier; hover a cell for the observation date. Missing values are shown as unavailable, never estimated.</Note>145    </>146  );147}148149/* ------------------------------------------------------------------------------------------------------ shared benchmarks */150151function configSummary(c: Record<string, unknown>): string {152  return Object.entries(c ?? {})153    .filter(([, v]) => v !== null && v !== undefined && v !== '')154    .slice(0, 4)155    .map(([k, v]) => `${k}=${typeof v === 'object' ? JSON.stringify(v) : String(v)}`)156    .join(' · ');157}158159/** Benchmarks with a current result for every compared model (best result per model per benchmark). */160export function SharedBenchmarks({ res }: { res: ComparePayload }) {161  const perItem = res.items.map((it) => {162    const m = new Map<string, BenchmarkResult>();163    for (const r of it.results ?? []) {164      const prev = m.get(r.benchmark.slug);165      if (!prev || (r.higher_is_better === false ? r.score < prev.score : r.score > prev.score)) m.set(r.benchmark.slug, r);166    }167    return m;168  });169  const first = perItem[0];170  const shared = first ? [...first.values()].filter((r) => perItem.every((m) => m.has(r.benchmark.slug))) : [];171  const anyResults = res.items.some((it) => (it.results?.length ?? 0) > 0);172  if (shared.length === 0)173    return (174      <p className="text-sm text-ink-3">175        {anyResults ? 'No benchmark has a published result for every compared model.' : 'No benchmark results recorded for these models.'} Per-model results are on each model page (Benchmarks tab).176      </p>177    );178  shared.sort((a, b) => a.benchmark.name.localeCompare(b.benchmark.name));179  return (180    <>181      <ScrollTable caption="Shared benchmark results">182        <thead>183          <tr>184            <Th className={cn(STICKY, FIRST)} style={WRAP}>Benchmark</Th>185            {res.items.map((it) => (186              <Th key={it.entity.id} className="min-w-[8rem]">187                <EntityLink e={it.entity} className="text-sm font-semibold normal-case tracking-normal whitespace-normal" />188              </Th>189            ))}190          </tr>191        </thead>192        <tbody>193          {shared.map((row) => {194            const cells = perItem.map((m) => m.get(row.benchmark.slug) ?? null);195            const scores = cells.map((c) => (c ? c.score : null)).filter((s): s is number => s !== null);196            const best = scores.length > 1 ? (row.higher_is_better === false ? Math.min(...scores) : Math.max(...scores)) : null;197            return (198              <tr key={row.benchmark.slug}>199                <Td className={cn(STICKY, FIRST, 'text-ink-2')} style={WRAP}>200                  <EntityLink e={row.benchmark} />201                  <span className="block text-[11px] text-ink-3">202                    {row.metric ?? '—'}203                    {row.higher_is_better === false ? ' · lower is better' : ''}204                  </span>205                </Td>206                {cells.map((c, i) => (207                  <Td key={res.items[i]!.entity.id} className="tnum align-top" title={c ? configSummary(c.config) || undefined : undefined}>208                    {c ? (209                      <>210                        <span className={cn('block', best !== null && c.score === best && 'font-semibold text-ink')}>211                          {fmtScore(c.score)}212                          {c.unit === '%' ? '%' : c.unit ? <span className="text-ink-3"> {c.unit}</span> : ''}213                        </span>214                        <span className="mt-0.5 hidden items-center gap-1 text-[11px] text-ink-3 md:flex">215                          <TierBadge tier={c.tier} />216                          <span className="max-w-[10rem] truncate">{configSummary(c.config) || (c.evaluated_at ? fmtDate(c.evaluated_at) : '')}</span>217                        </span>218                      </>219                    ) : (220                      <span className="text-ink-3">—</span>221                    )}222                  </Td>223                ))}224              </tr>225            );226          })}227        </tbody>228      </ScrollTable>229      <Note className="mt-3">Only benchmarks with a result for every compared model are shown (best current result per model). Configurations may differ — hover a score for its config; scores under different configs are not strictly comparable.</Note>230    </>231  );232}233234/* ------------------------------------------------------------------------------------------------------ prices */235236type Best = { input: number | null; output: number | null; observed: string; url: string | null; tier: number };237238/** Provider × entity: cheapest current input / output per provider for each compared model. */239export function ComparePrices({ res }: { res: ComparePayload }) {240  const providers = new Map<string, Price['provider']>();241  const perItem = res.items.map((it) => {242    const m = new Map<string, Best>();243    for (const p of it.prices ?? []) {244      providers.set(p.provider.slug, p.provider);245      const cur = m.get(p.provider.slug) ?? { input: null, output: null, observed: p.observed_at, url: p.source_url, tier: p.tier };246      const inp = num(p.input_per_mtok);247      const out = num(p.output_per_mtok);248      if (inp !== null && (cur.input === null || inp < cur.input)) cur.input = inp;249      if (out !== null && (cur.output === null || out < cur.output)) cur.output = out;250      if (p.observed_at > cur.observed) cur.observed = p.observed_at;251      m.set(p.provider.slug, cur);252    }253    return m;254  });255  if (providers.size === 0) return <p className="text-sm text-ink-3">No current prices recorded for these models.</p>;256  const rows = [...providers.values()].sort((a, b) => a.name.localeCompare(b.name));257  const bestOverall = res.items.map((_, i) => {258    let best: number | null = null;259    for (const b of perItem[i]!.values()) if (b.input !== null && (best === null || b.input < best)) best = b.input;260    return best;261  });262  return (263    <>264      <ScrollTable caption="Best current prices per provider (USD per 1M tokens)">265        <thead>266          <tr>267            <Th className={cn(STICKY, FIRST)} style={WRAP}>Provider</Th>268            {res.items.map((it) => (269              <Th key={it.entity.id} className="min-w-[9rem]">270                <EntityLink e={it.entity} className="text-sm font-semibold normal-case tracking-normal whitespace-normal" />271                <span className="block text-[10px] font-normal text-ink-3">in / out per 1M</span>272              </Th>273            ))}274          </tr>275        </thead>276        <tbody>277          {rows.map((prov) => (278            <tr key={prov.slug}>279              <Td className={cn(STICKY, FIRST)} style={WRAP}>280                <EntityLink e={prov} />281              </Td>282              {perItem.map((m, i) => {283                const b = m.get(prov.slug);284                if (!b) return <Td key={res.items[i]!.entity.id} className="text-ink-3">—</Td>;285                const cheapest = bestOverall[i] !== null && b.input === bestOverall[i];286                return (287                  <Td key={res.items[i]!.entity.id} className="tnum align-top" title={`observed ${fmtDate(b.observed)}`}>288                    <span className={cn('block text-accent-2', cheapest && 'font-semibold')}>289                      {fmtUsdPerM(b.input)} <span className="text-ink-3">/</span> {fmtUsdPerM(b.output)}290                    </span>291                    <span className="mt-0.5 hidden items-center gap-1 text-[11px] text-ink-3 md:flex">292                      <TierBadge tier={b.tier} />293                      {b.url ? (294                        <a href={b.url} target="_blank" rel="noopener noreferrer" className="max-w-[10rem] truncate hover:text-accent">295                          {host(b.url)}296                        </a>297                      ) : null}298                      <span>· {fmtAgo(b.observed)}</span>299                    </span>300                  </Td>301                );302              })}303            </tr>304          ))}305        </tbody>306      </ScrollTable>307      <Note className="mt-3">308        Cheapest current input / output price of each provider for each model, as published on the provider's pricing page (USD per 1M tokens). Bold = the model's cheapest provider. Full tables and history on each model page, or the <a href={routes.prices()} className="link">price index</a>.309      </Note>310    </>311  );312}313