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%
11.8 KB · 225 lines tsx
Raw Blame History
1import { ExternalLink } from 'lucide-react';2import Link from 'next/link';3import { Evidence } from '@/components/evidence/evidence';4import { ViewBeacon } from '@/components/layout/view-beacon';5import { ArtifactKindChip, OpennessChip } from '@/components/models/badges';6import { EntityBadge, StatusBadge } from '@/components/ui/badges';7import { EntityLink, QualityMark } from '@/components/ui/entity';8import { KeyValue, type KVRow } from '@/components/ui/key-value';9import { Container, Note } from '@/components/ui/section';10import { fmtAgo, fmtBytes, fmtDate, fmtGb, fmtInt, num } from '@/lib/format';11import { routes, SITE_NAME, SITE_URL } from '@/lib/site';12import type { ModelDetail } from '@/lib/types';13import { ProvenanceSummary, RelationsBlock, SourcesTable, TimelineList } from './blocks';14import { HardwareFitBlock } from './model-blocks';1516/*17  Artifact page: a checkpoint / quantisation / conversion / packaging of a canonical model. Header points prominently to the18  canonical model; the artifact's own facts (file size, quant format, dtype, downloads, publisher) are shown with evidence.19*/2021const FACT_KEYS = ['quant_format', 'quantization', 'weights_dtype', 'file_size_gb', 'metric.downloads', 'metric.likes', 'hf_repo', 'base_model', 'quantized_by', 'pipeline_tag', 'library_name', 'gated', 'access', 'license', 'release_date', 'last_modified', 'model_card_url', 'tags'];2223export function describeArtifact(d: ModelDetail): string {24  const a = d.attributes ?? {};25  const bits: string[] = [];26  if (typeof a.quant_format === 'string') bits.push(String(a.quant_format).toUpperCase());27  if (num(a.file_size_gb) !== null) bits.push(fmtGb(a.file_size_gb, 1));28  if (num(a['metric.downloads']) !== null) bits.push(`${fmtInt(a['metric.downloads'])} downloads`);29  return `${d.name} is a ${d.artifact_kind ?? 'packaging'} of ${d.canonical?.name ?? 'a canonical model'}${d.organization ? ` published by ${d.organization.name}` : ''}${bits.length ? ` — ${bits.join(', ')}` : ''}. Not an independent model: parameters, benchmarks and prices live on the canonical model page. ${SITE_NAME}.`.slice(0, 300);30}3132export function ArtifactPage({ d, canonical }: { d: ModelDetail; canonical: string }) {33  const a = d.attributes ?? {};34  const entity = { name: d.name, entity_type: d.entity_type };35  const format = typeof a.quant_format === 'string' ? String(a.quant_format).toUpperCase() : Array.isArray(a.weights_dtype) && a.weights_dtype.length ? (a.weights_dtype as string[]).join('/') : null;36  const rows: KVRow[] = FACT_KEYS.filter((k) => a[k] !== undefined && a[k] !== null && a[k] !== '' && !(Array.isArray(a[k]) && (a[k] as unknown[]).length === 0)).map((k) => ({ key: k, raw: a[k] }));37  const hf = typeof a.hf_repo === 'string' ? `https://huggingface.co/${a.hf_repo}` : typeof a.model_card_url === 'string' ? a.model_card_url : null;38  const ld = {39    '@context': 'https://schema.org',40    '@type': 'SoftwareSourceCode',41    name: d.name,42    url: `${SITE_URL}${canonical}`,43    description: d.description ?? describeArtifact(d),44    isBasedOn: d.canonical ? `${SITE_URL}${routes.entity(d.canonical)}` : undefined,45    publisher: d.organization ? { '@type': 'Organization', name: d.organization.name } : undefined,46    fileFormat: typeof a.quant_format === 'string' ? a.quant_format : undefined,47    contentSize: num(a.file_size_gb) !== null ? fmtBytes((num(a.file_size_gb) as number) * 1e9) : undefined,48    codeRepository: hf ?? undefined,49  };50  const quants = Array.isArray(a.quantization) ? (a.quantization as string[]) : [];51  return (52    <Container wide>53      <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(ld) }} />54      <ViewBeacon path={canonical} />55      <nav aria-label="Breadcrumb" className="pt-5 text-xs text-ink-3">56        <ol className="flex flex-wrap items-center gap-1.5">57          <li>58            <Link href="/" className="hover:text-ink">59              AI Atlas60            </Link>61          </li>62          <li aria-hidden>/</li>63          <li>64            <Link href={routes.models()} className="hover:text-ink">65              Models66            </Link>67          </li>68          {d.canonical && (69            <>70              <li aria-hidden>/</li>71              <li>72                <Link href={routes.entity(d.canonical)} className="hover:text-ink">73                  {d.canonical.name}74                </Link>75              </li>76            </>77          )}78          <li aria-hidden>/</li>79          <li className="text-ink-2">{d.name}</li>80        </ol>81      </nav>8283      <header className="pb-6 pt-4 md:pt-5" data-artifact-header>84        <div className="flex flex-wrap items-center gap-2">85          <EntityBadge type="artifact" />86          <ArtifactKindChip kind={d.artifact_kind} />87          {format && <span className="mono text-xs text-ink-2">{format}</span>}88          {typeof a.openness === 'string' && <OpennessChip openness={a.openness} />}89          <StatusBadge status={d.status !== 'active' ? d.status : null} />90          {d.canonical && (91            <span className="text-xs text-ink-3">92              of <EntityLink e={d.canonical} className="font-medium text-ink-2" />93            </span>94          )}95        </div>96        <div className="mt-3 flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">97          <div className="min-w-0">98            <h1 className="display text-[28px] md:text-[40px]">{d.name}</h1>99            <p className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-[15px] text-ink-2">100              {d.organization && (101                <span>102                  published by{' '}103                  <Link href={routes.entity({ entity_type: 'company', slug: d.organization.slug })} className="font-medium text-ink hover:text-accent">104                    {d.organization.name}105                  </Link>106                </span>107              )}108              {hf && (109                <a href={hf} target="_blank" rel="noopener noreferrer" className="inline-flex max-w-full min-w-0 items-center gap-1 text-ink-3 hover:text-accent">110                  <span className="truncate">{hf.replace(/^https?:\/\/(www\.)?/, '').slice(0, 56)}</span> <ExternalLink className="size-3.5 shrink-0" aria-hidden />111                </a>112              )}113            </p>114            {d.canonical ? (115              <p className="mt-4 border-l-2 border-accent bg-accent-soft/40 px-3 py-2 text-sm text-ink-2" data-artifact-note>116                This is a {d.artifact_kind ?? 'packaging'} of{' '}117                <Link href={routes.entity(d.canonical)} className="font-semibold text-ink hover:text-accent">118                  {d.canonical.name}119                </Link>120                , not an independent model. Parameters, benchmarks, prices and lineage are recorded on the canonical model.{' '}121                <Link href={routes.entity(d.canonical)} className="link">122                  Open {d.canonical.name} →123                </Link>124              </p>125            ) : (126              <Note className="mt-4">The canonical model of this artifact is not resolved yet — it is listed as an artifact because its name, repo or metadata identify it as a re-packaging.</Note>127            )}128            {d.description && <p className="mt-3 max-w-3xl text-[15px] leading-relaxed text-ink-2">{d.description}</p>}129          </div>130          <div className="shrink-0 text-xs text-ink-3 lg:text-right">131            <QualityMark q={d.quality?.score} label />132            <p className="mt-1" title={d.updated_at}>133              Updated {fmtAgo(d.updated_at)} · first seen {fmtDate(d.first_seen_at)}134            </p>135            <p className="mono mt-0.5 text-[11px]">{d.id}</p>136          </div>137        </div>138        <dl className="mt-5 grid grid-cols-2 gap-x-6 gap-y-3 border-y border-rule py-3 sm:grid-cols-4" data-artifact-strip>139          {[140            { key: 'file_size_gb', label: 'File size', value: num(a.file_size_gb) === null ? null : fmtGb(a.file_size_gb, 1) },141            { key: 'quant_format', label: 'Format', value: format },142            { key: 'metric.downloads', label: 'Downloads', value: num(a['metric.downloads']) === null ? null : fmtInt(a['metric.downloads']) },143            { key: 'release_date', label: 'Published', value: typeof a.release_date === 'string' ? fmtDate(a.release_date) : typeof a.last_modified === 'string' ? fmtDate(a.last_modified) : null },144          ].map((c) => (145            <div key={c.key} className="min-w-0">146              <dt className="eyebrow">{c.label}</dt>147              <dd className="tnum mt-0.5 truncate text-[15px] font-medium text-ink">148                {c.value === null ? (149                  <span className="text-ink-3">—</span>150                ) : (151                  <Evidence slug={d.slug} property={c.key} value={a[c.key]} display={c.value} fallback={d.provenance?.[c.key]} entity={entity}>152                    {c.value}153                  </Evidence>154                )}155              </dd>156            </div>157          ))}158        </dl>159      </header>160161      <div className="grid gap-10 pb-16 lg:grid-cols-[minmax(0,1fr)_22rem]">162        <div className="min-w-0 space-y-10">163          <section>164            <p className="eyebrow mb-2">Artifact facts</p>165            <KeyValue rows={rows} provenance={d.provenance} slug={d.slug} entity={entity} />166            {quants.length > 0 && <Note className="mt-2">{fmtInt(quants.length)} quantisation levels in this repository ({quants.slice(0, 8).join(', ')}{quants.length > 8 ? '…' : ''}).</Note>}167          </section>168          {d.hardware_fit && d.hardware_fit.length > 0 && (169            <section>170              <p className="eyebrow mb-2">Hardware fit (this packaging)</p>171              <HardwareFitBlock rows={d.hardware_fit} assumptions={d.hardware_fit_assumptions} modelSlug={d.canonical?.slug ?? d.slug} />172            </section>173          )}174          {d.timeline?.length > 0 && (175            <section>176              <p className="eyebrow mb-2">Timeline</p>177              <TimelineList events={d.timeline} slug={d.slug} />178            </section>179          )}180          <section>181            <p className="eyebrow mb-2">Provenance</p>182            <ProvenanceSummary provenance={d.provenance} quality={d.quality} />183            <div className="mt-4">184              <SourcesTable sources={d.sources ?? []} />185            </div>186          </section>187        </div>188        <aside className="min-w-0 space-y-8">189          <section>190            <p className="eyebrow mb-2">Relations</p>191            <RelationsBlock relations={d.relations ?? []} />192          </section>193          {d.canonical && (194            <section>195              <p className="eyebrow mb-2">Canonical model</p>196              <p className="text-sm">197                <EntityLink e={d.canonical} className="font-medium" />198                {d.canonical.organization && <span className="block text-xs text-ink-3">{d.canonical.organization.name}</span>}199              </p>200              <p className="mt-2 text-xs text-ink-3">201                Compare packagings, prices and benchmarks there. <Link href={`${routes.graph(d.canonical.slug)}?mode=lineage`} className="link">Lineage graph →</Link>202              </p>203            </section>204          )}205          {(d.aliases?.length > 0 || d.identifiers?.length > 0) && (206            <section>207              <p className="eyebrow mb-2">Identifiers</p>208              <dl className="kv [&>div]:grid-cols-[8rem_minmax(0,1fr)]">209                {d.identifiers.map((i) => (210                  <div key={`${i.scheme}:${i.value}`}>211                    <dt className="mono text-[11px]">{i.scheme}</dt>212                    <dd className="mono break-all text-[12px] text-ink">{i.value}</dd>213                  </div>214                ))}215              </dl>216              {d.aliases?.length > 0 && <p className="mt-2 text-xs text-ink-3">Also known as: {d.aliases.join(', ')}</p>}217              <p className="mono mt-2 break-all text-[11px] text-ink-3">slug {d.slug}</p>218            </section>219          )}220        </aside>221      </div>222    </Container>223  );224}225