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%
13.9 KB · 307 lines tsx
Raw Blame History
1import { ExternalLink } from 'lucide-react';2import Link from 'next/link';3import type { ReactNode } from 'react';4import { ChangeRow } from '@/components/changes/change-row';5import { EntityBadge, ImportanceMark, OpennessBadge } from '@/components/ui/badges';6import { DataTable, EmptyRow, Td, Th } from '@/components/ui/data-table';7import { EntityLink } from '@/components/ui/entity';8import { Note, Section } from '@/components/ui/section';9import { EmptyState } from '@/components/ui/unavailable';10import { fmtDate, fmtDeltaPct, fmtInt, fmtParams, fmtScore, fmtTokens, fmtUsdPerM, hostOf, num } from '@/lib/format';11import { routes } from '@/lib/site';12import type { ChangeEvent, DiffPayload11, EntitySummary } from '@/lib/types';1314/* Diff sections (server). Dense rows with typed deltas; every row keeps its source link and a History link. */1516export function Capped({ shown, total, what }: { shown: number; total: number | null; what: string }) {17  if (total === null || total <= shown) return null;18  return <Note className="mt-2">Showing the first {fmtInt(shown)} of {fmtInt(total)} {what}. Narrow the scope or the dates to see everything.</Note>;19}2021function SectionTitle({ title, n }: { title: string; n: number | null }) {22  return (23    <>24      {title} <span className="tnum text-base font-normal text-ink-3">{fmtInt(n)}</span>25    </>26  );27}2829function Src({ url }: { url: string | null }) {30  if (!url) return <span className="text-ink-3">—</span>;31  return (32    <a href={url} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1 text-xs text-ink-3 hover:text-accent">33      {hostOf(url) ?? 'source'} <ExternalLink className="size-3" aria-hidden />34    </a>35  );36}37function When({ e }: { e: ChangeEvent }) {38  const at = e.occurred_at ?? e.effective_at ?? e.observed_at;39  return (40    <time dateTime={at} title={`observed ${e.observed_at}`} className="tnum text-xs text-ink-2">41      {fmtDate(at)}42    </time>43  );44}4546/** New entities of one type as a dense table. */47export function NewEntitiesSection({ id, title, items, total, empty, type }: { id: string; title: string; items: EntitySummary[]; total: number | null; empty: string; type: 'model' | 'paper' | 'other' }) {48  return (49    <Section id={id} eyebrow={title} title={<SectionTitle title={title} n={total ?? items.length} />}>50      {items.length === 0 ? (51        <EmptyState title={empty} />52      ) : (53        <>54          <DataTable caption={title} compact scroll>55            <thead>56              <tr>57                <Th>{type === 'paper' ? 'Paper' : type === 'model' ? 'Model' : 'Entity'}</Th>58                {type === 'other' && <Th>Type</Th>}59                <Th>Organization</Th>60                {type === 'model' && (61                  <>62                    <Th num>Params</Th>63                    <Th num>Context</Th>64                    <Th>Openness</Th>65                    <Th>Released</Th>66                  </>67                )}68                {type === 'paper' && <Th>Published</Th>}69                <Th>First seen</Th>70              </tr>71            </thead>72            <tbody>73              {items.map((e) => {74                const a = e.attributes ?? {};75                return (76                  <tr key={e.id}>77                    <Td primary>78                      <EntityLink e={e} />79                    </Td>80                    {type === 'other' && (81                      <Td label="Type">82                        <EntityBadge type={e.entity_type} small />83                      </Td>84                    )}85                    <Td label="Organization" className="text-ink-2">86                      {e.organization ? <Link href={routes.entity({ entity_type: 'company', slug: e.organization.slug })} className="hover:text-accent">{e.organization.name}</Link> : <span className="text-ink-3">—</span>}87                    </Td>88                    {type === 'model' && (89                      <>90                        <Td num label="Params" className="tnum">{fmtParams(a.parameter_count)}</Td>91                        <Td num label="Context" className="tnum">{num(a.context_length) === null ? '—' : fmtTokens(a.context_length)}</Td>92                        <Td label="Openness">{typeof a.openness === 'string' ? <OpennessBadge openness={a.openness} /> : <span className="text-ink-3">—</span>}</Td>93                        <Td label="Released" className="tnum text-ink-2">{typeof a.release_date === 'string' ? fmtDate(a.release_date) : '—'}</Td>94                      </>95                    )}96                    {type === 'paper' && <Td label="Published" className="tnum text-ink-2">{typeof a.published_at === 'string' ? fmtDate(a.published_at) : '—'}</Td>}97                    <Td label="First seen" className="tnum text-xs text-ink-3">{fmtDate(e.first_seen_at)}</Td>98                  </tr>99                );100              })}101            </tbody>102          </DataTable>103          <Capped shown={items.length} total={total} what="entities" />104        </>105      )}106    </Section>107  );108}109110type PriceObj = { input_per_mtok?: unknown; output_per_mtok?: unknown };111function priceOf(v: unknown): PriceObj | null {112  return v && typeof v === 'object' ? (v as PriceObj) : null;113}114function DeltaCell({ from, to, fmt }: { from: unknown; to: unknown; fmt: (v: unknown) => string }) {115  const a = num(from);116  const b = num(to);117  const pct = fmtDeltaPct(a, b);118  return (119    <span className="tnum inline-flex flex-wrap items-baseline gap-1">120      <span className="text-ink-3 line-through decoration-ink-3/60">{a === null ? '—' : fmt(a)}</span>121      <span className="text-ink-3">→</span>122      <span className="font-medium text-ink">{b === null ? '—' : fmt(b)}</span>123      {pct && <span className={`text-[11px] ${b !== null && a !== null && b < a ? 'text-positive' : 'text-accent-2'}`}>{pct}</span>}124    </span>125  );126}127128/** PRICE_CHANGED / PROVIDER_LISTED rows: old/new are `{ input_per_mtok, output_per_mtok }` objects. */129export function PriceChangesSection({ id, title, items, total, empty }: { id: string; title: string; items: ChangeEvent[]; total: number | null; empty: string }) {130  return (131    <Section id={id} eyebrow={title} title={<SectionTitle title={title} n={total ?? items.length} />}>132      {items.length === 0 ? (133        <EmptyState title={empty} />134      ) : (135        <>136          <DataTable caption={title} compact scroll>137            <thead>138              <tr>139                <Th>Date</Th>140                <Th>Model</Th>141                <Th>Provider</Th>142                <Th num>Input / 1M</Th>143                <Th num>Output / 1M</Th>144                <Th>Source</Th>145              </tr>146            </thead>147            <tbody>148              {items.map((e) => {149                const o = priceOf(e.old_value);150                const n = priceOf(e.new_value);151                const provider = typeof e.meta?.provider === 'string' ? e.meta.provider : e.entity?.entity_type === 'provider' ? e.entity.name : null;152                return (153                  <tr key={e.id}>154                    <Td label="Date">155                      <span className="inline-flex items-center gap-2">156                        <ImportanceMark importance={e.importance} /> <When e={e} />157                      </span>158                    </Td>159                    <Td primary>{e.entity ? <EntityLink e={e.entity} /> : <span className="text-ink-2">{e.summary}</span>}</Td>160                    <Td label="Provider" className="text-ink-2">{provider ?? '—'}</Td>161                    <Td num label="Input">{o || n ? <DeltaCell from={o?.input_per_mtok} to={n?.input_per_mtok} fmt={(v) => fmtUsdPerM(v)} /> : '—'}</Td>162                    <Td num label="Output">{o || n ? <DeltaCell from={o?.output_per_mtok} to={n?.output_per_mtok} fmt={(v) => fmtUsdPerM(v)} /> : '—'}</Td>163                    <Td label="Source">164                      <Src url={e.source_url} />165                    </Td>166                  </tr>167                );168              })}169            </tbody>170          </DataTable>171          <Capped shown={items.length} total={total} what="price events" />172        </>173      )}174    </Section>175  );176}177178/** CONTEXT_CHANGED (and other numeric property events): old → new with %. */179export function ContextChangesSection({ id, title, items, total, empty }: { id: string; title: string; items: ChangeEvent[]; total: number | null; empty: string }) {180  return (181    <Section id={id} eyebrow={title} title={<SectionTitle title={title} n={total ?? items.length} />}>182      {items.length === 0 ? (183        <EmptyState title={empty} />184      ) : (185        <>186          <DataTable caption={title} compact scroll>187            <thead>188              <tr>189                <Th>Date</Th>190                <Th>Model</Th>191                <Th>Organization</Th>192                <Th num>Context window</Th>193                <Th>Source</Th>194                <Th>History</Th>195              </tr>196            </thead>197            <tbody>198              {items.map((e) => (199                <tr key={e.id}>200                  <Td label="Date">201                    <span className="inline-flex items-center gap-2">202                      <ImportanceMark importance={e.importance} /> <When e={e} />203                    </span>204                  </Td>205                  <Td primary>{e.entity ? <EntityLink e={e.entity} /> : <span className="text-ink-2">{e.summary}</span>}</Td>206                  <Td label="Organization" className="text-ink-2">{e.entity?.organization?.name ?? '—'}</Td>207                  <Td num label="Context">208                    <DeltaCell from={e.old_value} to={e.new_value} fmt={(v) => `${fmtTokens(v)} tokens`} />209                  </Td>210                  <Td label="Source">211                    <Src url={e.source_url} />212                  </Td>213                  <Td label="History">{e.entity ? <Link href={routes.entityHistory(e.entity, e.property ?? undefined)} className="link text-xs">claims →</Link> : '—'}</Td>214                </tr>215              ))}216            </tbody>217          </DataTable>218          <Capped shown={items.length} total={total} what="context changes" />219        </>220      )}221    </Section>222  );223}224225export function LeadersSection({ id, items, a, b }: { id: string; items: NonNullable<DiffPayload11['new_benchmark_leaders']>; a: string; b: string }) {226  return (227    <Section id={id} eyebrow="New benchmark leaders" title={<SectionTitle title="New benchmark leaders" n={items.length} />} lede={`Benchmarks whose primary-group leader (computed from results observed by each date) differs between ${fmtDate(a)} and ${fmtDate(b)}.`}>228      {items.length === 0 ? (229        <EmptyState title="No benchmark changed leader between these dates" />230      ) : (231        <DataTable caption="New benchmark leaders" compact scroll>232          <thead>233            <tr>234              <Th>Benchmark</Th>235              <Th>Leader at {fmtDate(a)}</Th>236              <Th num>Score</Th>237              <Th>Leader at {fmtDate(b)}</Th>238              <Th num>Score</Th>239              <Th>Metric</Th>240            </tr>241          </thead>242          <tbody>243            {items.map((l) => (244              <tr key={l.benchmark.id}>245                <Td primary>246                  <Link href={routes.benchmark(l.benchmark.slug)} className="text-ink hover:text-accent hover:underline">247                    {l.benchmark.name}248                  </Link>249                  {l.benchmark.category && <span className="block text-[11px] text-ink-3">{l.benchmark.category}</span>}250                </Td>251                <Td label={`At ${fmtDate(a)}`}>{l.at_a ? <EntityLink e={l.at_a.model} className="text-ink-2" /> : <span className="text-ink-3">no result observed yet</span>}</Td>252                <Td num label="Score" className="tnum text-ink-2">{l.at_a ? fmtScore(l.at_a.score) : '—'}</Td>253                <Td label={`At ${fmtDate(b)}`}>{l.at_b ? <EntityLink e={l.at_b.model} className="font-medium" /> : <span className="text-ink-3">—</span>}</Td>254                <Td num label="Score" className="tnum font-medium">{l.at_b ? fmtScore(l.at_b.score) : '—'}</Td>255                <Td label="Metric" className="text-xs text-ink-2">{l.at_b?.metric ?? l.at_a?.metric ?? '—'}{l.at_b?.trust_level ? <span className="block text-ink-3">{l.at_b.trust_level}</span> : null}</Td>256              </tr>257            ))}258          </tbody>259        </DataTable>260      )}261    </Section>262  );263}264265/** Generic event list section (property / provider / hardware changes). */266export function EventsSection({ id, title, items, total, empty, lede }: { id: string; title: string; items: ChangeEvent[]; total: number | null; empty: string; lede?: ReactNode }) {267  return (268    <Section id={id} eyebrow={title} title={<SectionTitle title={title} n={total ?? items.length} />} lede={lede}>269      {items.length === 0 ? (270        <EmptyState title={empty} />271      ) : (272        <>273          <ul className="border-t border-rule">274            {items.map((e) => (275              <ChangeRow key={e.id} e={e} showDate live={false} />276            ))}277          </ul>278          <Capped shown={items.length} total={total} what="events" />279        </>280      )}281    </Section>282  );283}284285export function EntitiesSection({ id, title, items, total, empty }: { id: string; title: string; items: EntitySummary[]; total: number | null; empty: string }) {286  return (287    <Section id={id} eyebrow={title} title={<SectionTitle title={title} n={total ?? items.length} />}>288      {items.length === 0 ? (289        <EmptyState title={empty} />290      ) : (291        <>292          <ul className="grid gap-x-8 border-t border-rule sm:grid-cols-2">293            {items.map((e) => (294              <li key={e.id} className="flex items-center gap-2 border-b border-rule py-2 text-sm">295                <EntityBadge type={e.entity_type} small />296                <EntityLink e={e} className="truncate" />297                {e.organization && <span className="ml-auto shrink-0 text-xs text-ink-3">{e.organization.name}</span>}298              </li>299            ))}300          </ul>301          <Capped shown={items.length} total={total} what="entities" />302        </>303      )}304    </Section>305  );306}307