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%
7.7 KB · 142 lines typescript
Raw Blame History
1/**2 * Pure helpers shared by the D1 pages (models · artifacts · families · benchmarks · compare · licences).3 * No React here — safe to import from server and client components.4 */5import { DASH, fmtCompact, fmtParams, fmtTokens, fmtUsdPerM, num } from '@/lib/format';6import type { Comparability, EntitySummary, Group, IdentityConfidence, ModelRef } from '@/lib/types';78/** Ontology openness labels (mirrors `/methodology.openness.labels`; the API's own label wins when present). */9export const OPENNESS_11: Record<string, string> = {10  'open-source': 'Open source',11  'open-weights': 'Open weights',12  'restricted-weights': 'Restricted weights',13  restricted: 'Restricted weights',14  proprietary: 'Closed',15  unknown: 'Unknown',16};17export function opennessLabel(v: unknown, labels?: Record<string, string>): string {18  if (typeof v !== 'string' || !v) return DASH;19  return labels?.[v] ?? OPENNESS_11[v] ?? v;20}2122/** Trust levels of benchmark rows (`/methodology.trust_levels`); short labels for badges, long ones in `title`. */23export const TRUST_SHORT: Record<string, string> = {24  'official-model-card': 'Self-reported',25  'official-benchmark': 'Official board',26  'peer-reviewed': 'Peer-reviewed',27  'independent-evaluator': 'Independent',28  community: 'Community',29  unverified: 'Unverified',30};31export const TRUST_LONG: Record<string, string> = {32  'official-model-card': 'Official model card / technical report (self-reported)',33  'official-benchmark': 'Official benchmark leaderboard (submissions checked by the benchmark owner)',34  'peer-reviewed': 'Peer-reviewed paper',35  'independent-evaluator': 'Independent third-party evaluator',36  community: 'Community-run leaderboard or submission',37  unverified: 'Unverified / unknown provenance',38};39export function trustShort(level: string | null | undefined, label?: string | null): string {40  if (!level) return label ?? DASH;41  return TRUST_SHORT[level] ?? label ?? level;42}4344export const COMPARABILITY_LABEL: Record<Comparability, string> = { comparable: 'Comparable', 'partially-comparable': 'Partially comparable', 'not-comparable': 'Not comparable' };4546export const IDENTITY_LABEL: Record<IdentityConfidence, string> = { high: 'Identity confirmed', medium: 'Identity probable', low: 'Identity uncertain' };4748/** Task-defining config keys (define the comparability group) vs condition keys (same group, partially comparable). */49export const TASK_KEYS = new Set(['variant', 'board', 'harness', 'evaluator', 'subset', 'split', 'shots', 'pass_count', 'attempts', 'language', 'scaffold', 'agent', 'system']);50export const CONDITION_KEYS = new Set(['reasoning_effort', 'reasoning', 'thinking_budget', 'temperature', 'judge', 'tools', 'tool_use', 'max_tokens', 'context_length', 'sampling', 'aggregation', 'edit_format', 'model_tag']);51/** Per-row identifiers — never useful as chips. */52const NOISE_KEYS = new Set(['aa_slug', 'model_tag', 'model_id', 'run_id', 'submission_id', 'date', 'submitted_at', 'url', 'index_version']);5354export type ConfigChip = { key: string; value: string; kind: 'task' | 'condition' | 'other' };55/** Config → compact chips (task keys first, then conditions, then the rest); `omit` drops keys already implied by the group. */56export function configChipsOf(config: Record<string, unknown> | null | undefined, omit?: Record<string, unknown> | null, max = 6): ConfigChip[] {57  const out: ConfigChip[] = [];58  for (const [k, v] of Object.entries(config ?? {})) {59    if (v === null || v === undefined || v === '' || NOISE_KEYS.has(k)) continue;60    if (omit && k in omit && String(omit[k]) === String(v)) continue;61    const s = typeof v === 'object' ? JSON.stringify(v) : String(v);62    if (s.length > 40) continue;63    out.push({ key: k, value: s, kind: TASK_KEYS.has(k) ? 'task' : CONDITION_KEYS.has(k) ? 'condition' : 'other' });64  }65  const order = { task: 0, condition: 1, other: 2 };66  return out.sort((a, b) => order[a.kind] - order[b.kind] || a.key.localeCompare(b.key)).slice(0, max);67}6869/** "753B total · 42B active · 1.31M context · Open weights (Apache-2.0)" — every fragment only when sourced. */70export function identityStrip(attrs: Record<string, unknown>, opts: { opennessLabel?: string | null; licence?: string | null } = {}): { key: string; text: string }[] {71  const out: { key: string; text: string }[] = [];72  const p = num(attrs.parameter_count);73  const ap = num(attrs.active_parameter_count);74  if (p !== null) out.push({ key: 'parameter_count', text: `${fmtParams(p)} total` });75  if (ap !== null && ap !== p) out.push({ key: 'active_parameter_count', text: `${fmtParams(ap)} active` });76  if (num(attrs.context_length) !== null) out.push({ key: 'context_length', text: `${fmtTokens(attrs.context_length)} context` });77  const open = opts.opennessLabel ?? (typeof attrs.openness === 'string' ? opennessLabel(attrs.openness) : null);78  if (open) out.push({ key: 'openness', text: opts.licence ? `${open} (${opts.licence})` : open });79  return out;80}8182/** Accept "70B" / "7b" / "1.5T" / "128k" / raw integers for parameter and token inputs. */83export function parseScale(v: string | undefined | null): number | undefined {84  if (!v) return undefined;85  const m = /^\s*([\d.]+)\s*([kmbt])?\s*$/i.exec(v);86  if (!m) return undefined;87  const n = Number(m[1]);88  const mult = { k: 1e3, m: 1e6, b: 1e9, t: 1e12 }[(m[2] ?? '').toLowerCase() as 'k' | 'm' | 'b' | 't'] ?? 1;89  return Number.isFinite(n) ? Math.round(n * mult) : undefined;90}9192/** Group label without the metric prefix ("variant=hard · evaluator=Artificial Analysis"). */93export function groupConditions(g: Group): string {94  const parts = Object.entries(g.config ?? {}).map(([k, v]) => `${k}=${String(v)}`);95  return parts.join(' · ');96}9798export function refToSummary(m: ModelRef): EntitySummary {99  return { id: m.id, entity_type: m.entity_type || 'model', slug: m.slug, name: m.name, description: null, status: 'active', organization: m.organization, attributes: m.attributes ?? {}, quality: {}, counts: {}, first_seen_at: '', last_seen_at: '', updated_at: '' };100}101102/** Score formatter aware of the unit: 93.7% · 65.9 · 1 234 elo. */103export function fmtScoreUnit(score: number | null | undefined, unit: string | null | undefined): string {104  const n = num(score);105  if (n === null) return DASH;106  const s = Number.isInteger(n) ? String(n) : n >= 100 ? n.toFixed(0) : n.toFixed(n < 10 ? 2 : 1);107  if (unit === '%') return `${s}%`;108  return unit ? `${s} ${unit}` : s;109}110111/** Signed delta between two scores with the right sign for the metric direction. */112export function scoreDelta(a: number, b: number, unit: string | null | undefined): string {113  const d = a - b;114  if (!Number.isFinite(d) || d === 0) return '±0';115  const sign = d > 0 ? '+' : '−';116  const abs = Math.abs(d);117  const s = abs >= 100 ? abs.toFixed(0) : abs.toFixed(abs < 10 ? 2 : 1);118  return `${sign}${s}${unit === '%' ? ' pt' : ''}`;119}120121/** A model's cheapest output price when the API put one on the row (attributes only — nothing fetched). */122export function rowPrice(attrs: Record<string, unknown>, side: 'input' | 'output'): number | null {123  const keys = side === 'input' ? ['cheapest_input_per_mtok', 'min_input_per_mtok', 'best_input_per_mtok'] : ['cheapest_output_per_mtok', 'min_output_per_mtok', 'best_output_per_mtok'];124  for (const k of keys) {125    const v = num(attrs[k]);126    if (v !== null) return v;127  }128  return null;129}130131/** Formatter for a Pareto x axis key (`/pareto?x=`). Pure — usable on the server and the client. */132const X_FMT: Record<string, (v: number) => string> = {133  output_price: (v) => fmtUsdPerM(v),134  input_price: (v) => fmtUsdPerM(v),135  parameter_count: (v) => fmtParams(v),136  context_length: (v) => fmtTokens(v),137  memory_estimate: (v) => `${fmtCompact(v)} GB`,138};139export function xFormatter(key: string): (v: number) => string {140  return X_FMT[key] ?? fmtCompact;141}142