/** * Pure helpers shared by the D1 pages (models · artifacts · families · benchmarks · compare · licences). * No React here — safe to import from server and client components. */ import { DASH, fmtCompact, fmtParams, fmtTokens, fmtUsdPerM, num } from '@/lib/format'; import type { Comparability, EntitySummary, Group, IdentityConfidence, ModelRef } from '@/lib/types'; /** Ontology openness labels (mirrors `/methodology.openness.labels`; the API's own label wins when present). */ export const OPENNESS_11: Record = { 'open-source': 'Open source', 'open-weights': 'Open weights', 'restricted-weights': 'Restricted weights', restricted: 'Restricted weights', proprietary: 'Closed', unknown: 'Unknown', }; export function opennessLabel(v: unknown, labels?: Record): string { if (typeof v !== 'string' || !v) return DASH; return labels?.[v] ?? OPENNESS_11[v] ?? v; } /** Trust levels of benchmark rows (`/methodology.trust_levels`); short labels for badges, long ones in `title`. */ export const TRUST_SHORT: Record = { 'official-model-card': 'Self-reported', 'official-benchmark': 'Official board', 'peer-reviewed': 'Peer-reviewed', 'independent-evaluator': 'Independent', community: 'Community', unverified: 'Unverified', }; export const TRUST_LONG: Record = { 'official-model-card': 'Official model card / technical report (self-reported)', 'official-benchmark': 'Official benchmark leaderboard (submissions checked by the benchmark owner)', 'peer-reviewed': 'Peer-reviewed paper', 'independent-evaluator': 'Independent third-party evaluator', community: 'Community-run leaderboard or submission', unverified: 'Unverified / unknown provenance', }; export function trustShort(level: string | null | undefined, label?: string | null): string { if (!level) return label ?? DASH; return TRUST_SHORT[level] ?? label ?? level; } export const COMPARABILITY_LABEL: Record = { comparable: 'Comparable', 'partially-comparable': 'Partially comparable', 'not-comparable': 'Not comparable' }; export const IDENTITY_LABEL: Record = { high: 'Identity confirmed', medium: 'Identity probable', low: 'Identity uncertain' }; /** Task-defining config keys (define the comparability group) vs condition keys (same group, partially comparable). */ export const TASK_KEYS = new Set(['variant', 'board', 'harness', 'evaluator', 'subset', 'split', 'shots', 'pass_count', 'attempts', 'language', 'scaffold', 'agent', 'system']); export 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']); /** Per-row identifiers — never useful as chips. */ const NOISE_KEYS = new Set(['aa_slug', 'model_tag', 'model_id', 'run_id', 'submission_id', 'date', 'submitted_at', 'url', 'index_version']); export type ConfigChip = { key: string; value: string; kind: 'task' | 'condition' | 'other' }; /** Config → compact chips (task keys first, then conditions, then the rest); `omit` drops keys already implied by the group. */ export function configChipsOf(config: Record | null | undefined, omit?: Record | null, max = 6): ConfigChip[] { const out: ConfigChip[] = []; for (const [k, v] of Object.entries(config ?? {})) { if (v === null || v === undefined || v === '' || NOISE_KEYS.has(k)) continue; if (omit && k in omit && String(omit[k]) === String(v)) continue; const s = typeof v === 'object' ? JSON.stringify(v) : String(v); if (s.length > 40) continue; out.push({ key: k, value: s, kind: TASK_KEYS.has(k) ? 'task' : CONDITION_KEYS.has(k) ? 'condition' : 'other' }); } const order = { task: 0, condition: 1, other: 2 }; return out.sort((a, b) => order[a.kind] - order[b.kind] || a.key.localeCompare(b.key)).slice(0, max); } /** "753B total · 42B active · 1.31M context · Open weights (Apache-2.0)" — every fragment only when sourced. */ export function identityStrip(attrs: Record, opts: { opennessLabel?: string | null; licence?: string | null } = {}): { key: string; text: string }[] { const out: { key: string; text: string }[] = []; const p = num(attrs.parameter_count); const ap = num(attrs.active_parameter_count); if (p !== null) out.push({ key: 'parameter_count', text: `${fmtParams(p)} total` }); if (ap !== null && ap !== p) out.push({ key: 'active_parameter_count', text: `${fmtParams(ap)} active` }); if (num(attrs.context_length) !== null) out.push({ key: 'context_length', text: `${fmtTokens(attrs.context_length)} context` }); const open = opts.opennessLabel ?? (typeof attrs.openness === 'string' ? opennessLabel(attrs.openness) : null); if (open) out.push({ key: 'openness', text: opts.licence ? `${open} (${opts.licence})` : open }); return out; } /** Accept "70B" / "7b" / "1.5T" / "128k" / raw integers for parameter and token inputs. */ export function parseScale(v: string | undefined | null): number | undefined { if (!v) return undefined; const m = /^\s*([\d.]+)\s*([kmbt])?\s*$/i.exec(v); if (!m) return undefined; const n = Number(m[1]); const mult = { k: 1e3, m: 1e6, b: 1e9, t: 1e12 }[(m[2] ?? '').toLowerCase() as 'k' | 'm' | 'b' | 't'] ?? 1; return Number.isFinite(n) ? Math.round(n * mult) : undefined; } /** Group label without the metric prefix ("variant=hard · evaluator=Artificial Analysis"). */ export function groupConditions(g: Group): string { const parts = Object.entries(g.config ?? {}).map(([k, v]) => `${k}=${String(v)}`); return parts.join(' · '); } export function refToSummary(m: ModelRef): EntitySummary { 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: '' }; } /** Score formatter aware of the unit: 93.7% · 65.9 · 1 234 elo. */ export function fmtScoreUnit(score: number | null | undefined, unit: string | null | undefined): string { const n = num(score); if (n === null) return DASH; const s = Number.isInteger(n) ? String(n) : n >= 100 ? n.toFixed(0) : n.toFixed(n < 10 ? 2 : 1); if (unit === '%') return `${s}%`; return unit ? `${s} ${unit}` : s; } /** Signed delta between two scores with the right sign for the metric direction. */ export function scoreDelta(a: number, b: number, unit: string | null | undefined): string { const d = a - b; if (!Number.isFinite(d) || d === 0) return '±0'; const sign = d > 0 ? '+' : '−'; const abs = Math.abs(d); const s = abs >= 100 ? abs.toFixed(0) : abs.toFixed(abs < 10 ? 2 : 1); return `${sign}${s}${unit === '%' ? ' pt' : ''}`; } /** A model's cheapest output price when the API put one on the row (attributes only — nothing fetched). */ export function rowPrice(attrs: Record, side: 'input' | 'output'): number | null { 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']; for (const k of keys) { const v = num(attrs[k]); if (v !== null) return v; } return null; } /** Formatter for a Pareto x axis key (`/pareto?x=`). Pure — usable on the server and the client. */ const X_FMT: Record string> = { output_price: (v) => fmtUsdPerM(v), input_price: (v) => fmtUsdPerM(v), parameter_count: (v) => fmtParams(v), context_length: (v) => fmtTokens(v), memory_estimate: (v) => `${fmtCompact(v)} GB`, }; export function xFormatter(key: string): (v: number) => string { return X_FMT[key] ?? fmtCompact; }