import { ExternalLink, FileText } from 'lucide-react'; import Link from 'next/link'; import { SourcesTable, TimelineList } from '@/components/entity/blocks'; import { ViewBeacon } from '@/components/layout/view-beacon'; import { BreadcrumbLd, Breadcrumbs } from '@/components/meta/breadcrumb-ld'; import { WatchButton } from '@/components/watchlist/watch-button'; import { Chip, EntityBadge } from '@/components/ui/badges'; import { DataTable, EmptyRow, Td, Th } from '@/components/ui/data-table'; import { EntityLink, QualityMark } from '@/components/ui/entity'; import { KeyValue } from '@/components/ui/key-value'; import { Container, Note, Section } from '@/components/ui/section'; import { EmptyState } from '@/components/ui/unavailable'; import { api, safe } from '@/lib/api'; import { fmtAgo, fmtDate, fmtInt, fmtParams, fmtTokens, num } from '@/lib/format'; import { routes, SITE_NAME, SITE_URL, typeLabel } from '@/lib/site'; import type { EntityDetail, EntitySummary } from '@/lib/types'; /* Paper page (server, async). Sections: header (title, published, venue, arXiv, PDF/code) → abstract → authors (researcher pages when the `authored` relation names them) → organizations → models introduced (`described_by` inbound) → datasets → benchmarks → repositories → related papers (shared entities) → sources → timeline. Everything comes from the detail payload's relations; nothing is inferred beyond grouping by entity type. */ function relItems(d: EntityDetail, types: string[], predicate?: string): EntitySummary[] { const out: EntitySummary[] = []; const seen = new Set(); for (const g of d.relations ?? []) { if (predicate && g.predicate !== predicate) continue; for (const it of g.items) { if (!types.includes(it.entity_type) || seen.has(it.id)) continue; seen.add(it.id); out.push(it); } } return out; } function ModelsIntroduced({ items }: { items: EntitySummary[] }) { if (!items.length) return Model pages link papers through their model cards and documentation; the relation is written only when a source states it.; return ( Model Type Organization Params Context Released {items.map((m) => { const a = m.attributes ?? {}; return ( {m.organization?.name ?? '—'} {fmtParams(a.parameter_count)} {num(a.context_length) === null ? '—' : fmtTokens(a.context_length)} {typeof a.release_date === 'string' ? fmtDate(a.release_date) : '—'} ); })} ); } function List({ items, empty }: { items: EntitySummary[]; empty: string }) { if (!items.length) return

{empty}

; return ( ); } export async function PaperPage({ d, canonical }: { d: EntityDetail; canonical: string }) { const a = d.attributes ?? {}; const authors: string[] = Array.isArray(a.authors) ? (a.authors as unknown[]).map(String) : []; const researchers = relItems(d, ['researcher'], 'authored'); const byName = new Map(researchers.map((r) => [r.name.toLowerCase(), r])); const models = relItems(d, ['model', 'artifact', 'quantization']); const datasets = relItems(d, ['dataset']); const benchmarks = relItems(d, ['benchmark']); const repos = [...relItems(d, ['repository', 'framework', 'library']), ...(d.repositories ?? [])].filter((x, i, arr) => arr.findIndex((y) => y.id === x.id) === i); const orgs = relItems(d, ['company', 'organization', 'lab', 'university']); const related = await safe(api.entityRelated(d.slug, 12)); const relatedPapers = (related?.items ?? []).filter((r) => r.entity_type === 'paper' && r.id !== d.id); const relatedOther = (related?.items ?? []).filter((r) => r.entity_type !== 'paper' && r.id !== d.id); const arxiv = typeof a.arxiv_id === 'string' ? a.arxiv_id : d.identifiers?.find((i) => i.scheme === 'arxiv')?.value; const pdf = typeof a.pdf_url === 'string' ? a.pdf_url : arxiv ? `https://arxiv.org/pdf/${arxiv}` : null; const code = typeof a.code_url === 'string' ? a.code_url : null; const cats = [...new Set([...(typeof a.primary_category === 'string' ? [a.primary_category] : []), ...(Array.isArray(a.categories) ? (a.categories as unknown[]).map(String) : [])])]; const crumbs = [{ name: SITE_NAME, href: '/' }, { name: 'Research', href: '/papers' }, { name: d.name, href: canonical }]; const ld = { '@context': 'https://schema.org', '@type': 'ScholarlyArticle', headline: d.name, name: d.name, url: `${SITE_URL}${canonical}`, datePublished: typeof a.published_at === 'string' ? a.published_at : undefined, author: authors.slice(0, 30).map((n) => ({ '@type': 'Person', name: n })), abstract: typeof a.abstract === 'string' ? a.abstract : undefined, sameAs: [pdf, arxiv ? `https://arxiv.org/abs/${arxiv}` : null].filter(Boolean), identifier: arxiv ? { '@type': 'PropertyValue', propertyID: 'arxiv', value: arxiv } : undefined, publisher: d.organization ? { '@type': 'Organization', name: d.organization.name } : undefined, }; const specRows = ['published_at', 'venue', 'doi', 'arxiv_id', 'primary_category', 'pdf_url', 'code_url', 'updated_at'].filter((k) => a[k] !== undefined && a[k] !== null && a[k] !== '').map((k) => ({ key: k, raw: a[k] })); return (