Files
neuron/packages/stats/app/src/routes/[lab]/index.tsx
T
2026-06-26 12:00:32 -05:00

448 lines
17 KiB
TypeScript

import "../index.css"
import { Meta, Title } from "@solidjs/meta"
import {
getStatsLabData,
type LabUsageModelEntry,
type ModelUsagePoint,
type StatsLabData,
} from "@opencode-ai/stats-core/domain/home"
import { createAsync, query, useParams } from "@solidjs/router"
import { createMemo, createSignal, For, onMount, Show, type JSX } from "solid-js"
import { getRequestEvent } from "solid-js/web"
import { LocaleLinks } from "../../component/locale-links"
import { useI18n } from "../../context/i18n"
import { useLanguage } from "../../context/language"
import { localizedUrl } from "../../lib/language"
import {
findModelCatalogLab,
formatCatalogLabName,
getModelCatalog,
type ModelCatalogEntry,
type ModelCatalogLab,
} from "../model-catalog"
import { runStatsEffect } from "../../stats-runtime"
import { setStatsPageCacheHeaders } from "../stats-cache"
import {
applyThemePreference,
Footer,
getGitHubStars,
Header,
isThemePreference,
themeStorageKey,
type HeaderLink,
type ThemePreference,
} from "../stats-shell"
const statsUnfurlPath = "banner.png"
const getLabData = query(async (lab: string) => {
"use server"
return runStatsEffect(getStatsLabData(lab))
}, "getStatsLabData")
export default function StatsLab() {
const i18n = useI18n()
const language = useLanguage()
const event = getRequestEvent()
setStatsPageCacheHeaders(event?.response.headers)
const params = useParams()
const labParam = createMemo(() => params.lab ?? "")
const catalog = createAsync(() => getModelCatalog())
const lab = createMemo(() => {
const data = catalog()
if (!data) return undefined
return findModelCatalogLab(data, labParam()) ?? null
})
const stats = createAsync(() => {
const entry = lab()
if (catalog() === undefined || entry === undefined) return Promise.resolve(undefined)
if (!entry) return Promise.resolve(null)
return getLabData(entry.id)
})
const githubStars = createAsync(() => getGitHubStars())
const [themePreference, setThemePreference] = createSignal<ThemePreference>("system")
const labName = createMemo(() => lab()?.name ?? formatCatalogLabName(labParam()))
const labTitle = createMemo(() => i18n.t("lab.title", { lab: labName() }))
const labDescription = createMemo(() => i18n.t("lab.description", { lab: labName() }))
const labPath = createMemo(() => `/data/${lab()?.id ?? labParam()}`)
const labUrl = createMemo(() => localizedUrl(language.locale(), labPath()))
const statsUnfurlUrl = new URL(statsUnfurlPath, localizedUrl("en", "/data/")).toString()
const labHeaderLinks = createMemo<readonly HeaderLink[]>(() => [
{ href: "#overview", label: i18n.t("nav.overview") },
{ href: "#usage", label: i18n.t("nav.usage") },
{ href: "#models", label: i18n.t("nav.models") },
])
const labFooterLinks = createMemo<readonly HeaderLink[]>(() => [
{ href: import.meta.env.BASE_URL, label: i18n.t("nav.dataHome") },
{ href: `${import.meta.env.BASE_URL}#top-models`, label: i18n.t("nav.topModels") },
{ href: `${import.meta.env.BASE_URL}#market-share`, label: i18n.t("nav.marketShare") },
{ href: `${import.meta.env.BASE_URL}#geo-breakdown`, label: i18n.t("nav.geoBreakdown") },
])
const updateThemePreference = (preference: ThemePreference) => {
applyThemePreference(preference)
setThemePreference(preference)
if (typeof window === "undefined") return
window.localStorage.setItem(themeStorageKey, preference)
}
onMount(() => {
if (typeof window === "undefined") return
const preference = window.localStorage.getItem(themeStorageKey)
const nextPreference = isThemePreference(preference) ? preference : "system"
applyThemePreference(nextPreference)
setThemePreference(nextPreference)
})
return (
<main data-page="stats" data-theme={themePreference()}>
<Title>{labTitle()}</Title>
<Meta name="description" content={labDescription()} />
<LocaleLinks path={labPath()} />
<Meta property="og:type" content="website" />
<Meta property="og:site_name" content="OpenCode" />
<Meta property="og:title" content={labTitle()} />
<Meta property="og:description" content={labDescription()} />
<Meta property="og:url" content={labUrl()} />
<Meta property="og:image" content={statsUnfurlUrl} />
<Meta property="og:image:type" content="image/png" />
<Meta property="og:image:width" content="1200" />
<Meta property="og:image:height" content="630" />
<Meta property="og:image:alt" content={i18n.t("app.unfurlAlt")} />
<Meta name="twitter:card" content="summary_large_image" />
<Meta name="twitter:title" content={labTitle()} />
<Meta name="twitter:description" content={labDescription()} />
<Meta name="twitter:image" content={statsUnfurlUrl} />
<Meta name="twitter:image:alt" content={i18n.t("app.unfurlAlt")} />
<Header githubStars={githubStars() ?? "150K"} links={labHeaderLinks()} brandHref={import.meta.env.BASE_URL} />
<div data-component="container">
<div data-component="content">
<Show when={catalog() !== undefined} fallback={<LabLoading />}>
<Show when={lab()} fallback={<LabNotFound lab={labParam()} />}>
{(data) => (
<>
<LabHero lab={data()} stats={stats() ?? null} />
<LabUsageSection lab={data()} data={stats() ?? null} />
<LabModelsSection lab={data()} usage={stats()?.models ?? []} />
</>
)}
</Show>
</Show>
</div>
<Footer
themePreference={themePreference()}
onThemePreferenceChange={updateThemePreference}
links={labFooterLinks()}
/>
</div>
</main>
)
}
function LabLoading() {
const i18n = useI18n()
const language = useLanguage()
return (
<section id="overview" data-section="lab-hero">
<div data-slot="model-hero-grid">
<div data-slot="model-hero-copy">
<a data-slot="model-back-link" href={language.route(import.meta.env.BASE_URL)}>
{i18n.t("footer.modelData")}
</a>
<h1>{i18n.t("lab.loadingTitle")}</h1>
<p>{i18n.t("lab.loadingDescription")}</p>
</div>
</div>
</section>
)
}
function LabNotFound(props: { lab: string }) {
const i18n = useI18n()
const language = useLanguage()
return (
<section id="overview" data-section="lab-hero">
<div data-slot="model-hero-grid">
<div data-slot="model-hero-copy">
<a data-slot="model-back-link" href={language.route(import.meta.env.BASE_URL)}>
{i18n.t("footer.modelData")}
</a>
<h1>{formatCatalogLabName(props.lab)}</h1>
<p>{i18n.t("lab.notFound")}</p>
</div>
</div>
</section>
)
}
function LabHero(props: { lab: ModelCatalogLab; stats: StatsLabData | null }) {
const i18n = useI18n()
const language = useLanguage()
const latest = createMemo(
() =>
props.lab.models
.map((model) => model.releaseDate)
.filter((value): value is string => value !== undefined)
.toSorted((a, b) => new Date(b).getTime() - new Date(a).getTime())[0],
)
const featuredModels = createMemo(() => props.lab.models.slice(0, 3).map((model) => model.name))
return (
<section id="overview" data-section="lab-hero">
<a data-slot="model-back-link" href={language.route(import.meta.env.BASE_URL)}>
{i18n.t("footer.modelData")}
</a>
<div data-slot="model-hero-grid">
<div data-slot="model-hero-copy">
<h1>{props.lab.name}</h1>
<div data-slot="model-hero-pattern" aria-hidden="true" />
<p>
{i18n.t("lab.heroPrefix", { count: props.lab.models.length, lab: props.lab.name })}
<Show when={featuredModels().length > 0}>
{" "}
{i18n.t("lab.heroIncluding", { models: formatList(featuredModels(), language.tag(language.locale())) })}
</Show>
. {i18n.t("lab.heroSuffix")}
</p>
</div>
<div data-component="model-rank-panel">
<span>{i18n.t("lab.tokensProcessed")}</span>
<strong>{props.stats ? formatTokens(props.stats.totals.tokens) : i18n.t("lab.pending")}</strong>
<p>
{props.stats
? i18n.t("lab.shareOfUsage", { share: formatPercent(props.stats.tokenShare) })
: latest()
? i18n.t("lab.latestRelease", {
date: formatCatalogDate(latest(), language.tag(language.locale()), i18n.t("home.unknown")),
})
: i18n.t("lab.usageAfterActivity")}
</p>
</div>
</div>
</section>
)
}
function LabUsageSection(props: { lab: ModelCatalogLab; data: StatsLabData | null }) {
const i18n = useI18n()
const [activeIndex, setActiveIndex] = createSignal<number>()
const usage = createMemo(() => props.data?.usage ?? [])
const max = createMemo(() => Math.max(0, ...usage().map((item) => item.tokens)) || 1)
const activePoint = createMemo(() => {
const index = activeIndex()
if (index === undefined) return undefined
return usage()[index]
})
return (
<section id="usage" data-section="model-panel">
<p data-slot="section-title">
<strong>{i18n.t("lab.usageTitle", { lab: props.lab.name })}.</strong>{" "}
<span>{i18n.t("lab.usageDescription")}</span>
</p>
<Show
when={usage().some((item) => item.tokens > 0)}
fallback={<LabEmptyState title={i18n.t("lab.noUsageTitle")} description={i18n.t("lab.noUsageDescription")} />}
>
<div
data-component="model-usage-chart"
data-dense-labels={isLabUsageDense(usage().length) ? "true" : undefined}
role="img"
aria-label={i18n.t("lab.dailyTokenChart", { lab: props.lab.name })}
style={{ "--model-usage-count": usage().length } as JSX.CSSProperties}
onPointerLeave={(event) => {
if (event.pointerType === "touch") return
setActiveIndex(undefined)
}}
>
<div data-slot="model-usage-axis" aria-hidden="true">
<For each={usage()}>
{(point, index) => (
<div
data-active={activeIndex() === index() ? "true" : undefined}
data-label-hidden={isLabUsageLabelHidden(index(), usage().length) ? "true" : undefined}
>
<span data-slot="model-usage-label">
<span data-slot="model-usage-total">{formatTokens(point.tokens)}</span>
<span data-slot="model-usage-date">{point.date}</span>
</span>
</div>
)}
</For>
</div>
<div data-slot="model-usage-bars">
<For each={usage()}>
{(point, index) => (
<div
data-slot="model-usage-column"
role="button"
tabIndex={0}
aria-label={`${point.date} ${formatTokens(point.tokens)} ${i18n.t("lab.tokens")}`}
data-active={activeIndex() === index() ? "true" : undefined}
data-muted={activeIndex() !== undefined && activeIndex() !== index() ? "true" : undefined}
onPointerDown={(event) => {
if (event.pointerType !== "touch") return
setActiveIndex(index())
}}
onPointerEnter={() => setActiveIndex(index())}
onPointerMove={(event) => {
if (event.pointerType === "touch") return
setActiveIndex(index())
}}
onClick={() => setActiveIndex(index())}
onFocus={() => setActiveIndex(index())}
onBlur={() => setActiveIndex(undefined)}
onKeyDown={(event) => {
if (event.key !== "Enter" && event.key !== " ") return
event.preventDefault()
setActiveIndex(index())
}}
>
<div
data-slot="model-usage-bar"
style={{ "--model-usage-fill": `${usageHeight(point.tokens, max())}%` } as JSX.CSSProperties}
/>
<Show when={activeIndex() === index() && activePoint()}>
{(active) => (
<div
data-component="chart-tooltip"
data-placement={index() > usage().length * 0.62 ? "left" : "right"}
>
<strong>{active().date}</strong>
<span>
{formatTokens(active().tokens)} {i18n.t("lab.tokens")}
</span>
<div data-slot="tooltip-divider" />
<p>
<span data-slot="tooltip-label">
<i /> {i18n.t("lab.dailyTokens")}
</span>
<b>{formatTokens(active().tokens)}</b>
</p>
</div>
)}
</Show>
</div>
)}
</For>
</div>
</div>
</Show>
</section>
)
}
function LabModelsSection(props: { lab: ModelCatalogLab; usage: LabUsageModelEntry[] }) {
const i18n = useI18n()
const usageBySlug = createMemo(() => new Map(props.usage.map((item) => [item.slug, item])))
return (
<section id="models" data-section="model-panel">
<p data-slot="section-title">
<strong>{i18n.t("lab.modelsTitle", { lab: props.lab.name })}.</strong>{" "}
<span>{i18n.t("lab.recentUsageAndLimits")}</span>
</p>
<div data-component="lab-model-grid">
<For each={props.lab.models}>
{(model) => <LabModelCard model={model} usage={usageBySlug().get(model.slug)} />}
</For>
</div>
</section>
)
}
function LabModelCard(props: { model: ModelCatalogEntry; usage: LabUsageModelEntry | undefined }) {
const i18n = useI18n()
const language = useLanguage()
return (
<a data-component="lab-model-card" href={language.route(`${import.meta.env.BASE_URL}${props.model.id}`)}>
<strong>{props.model.name}</strong>
<div data-slot="lab-model-card-meta">
<p>
<b>{i18n.t("lab.usage")}</b>
<em>{props.usage ? formatTokens(props.usage.tokens) : "—"}</em>
</p>
<p>
<b>{i18n.t("lab.share")}</b>
<em>{props.usage ? formatPercent(props.usage.share) : "—"}</em>
</p>
<p>
<b>{i18n.t("model.context")}</b>
<em>{formatCatalogLimit(props.model.limit?.context, i18n.t("home.unknown"))}</em>
</p>
<p>
<b>{i18n.t("model.output")}</b>
<em>{formatCatalogLimit(props.model.limit?.output, i18n.t("home.unknown"))}</em>
</p>
<p>
<b>{i18n.t("model.release")}</b>
<em>{formatCatalogDate(props.model.releaseDate, language.tag(language.locale()), i18n.t("home.unknown"))}</em>
</p>
</div>
</a>
)
}
function LabEmptyState(props: { title: string; description: string }) {
return (
<div data-component="empty-state" data-compact="true">
<strong>{props.title}</strong>
<p>{props.description}</p>
</div>
)
}
function formatCatalogLimit(value: number | undefined, unknown: string) {
return value === undefined ? unknown : formatTokens(value)
}
function formatCatalogDate(value: string | undefined, locale: string, unknown: string) {
if (!value) return unknown
const match = /^(\d{4})(?:-(\d{2}))?(?:-(\d{2}))?$/.exec(value)
if (!match) return value
const year = Number(match[1])
const month = match[2] ? Number(match[2]) - 1 : 0
const day = match[3] ? Number(match[3]) : 1
return new Intl.DateTimeFormat(locale, {
month: match[2] ? "short" : undefined,
day: match[3] ? "numeric" : undefined,
year: "numeric",
timeZone: "UTC",
}).format(new Date(Date.UTC(year, month, day)))
}
function formatList(values: string[], locale = "en") {
if (values.length <= 1) return values[0] ?? ""
return new Intl.ListFormat(locale, { style: "long", type: "conjunction" }).format(values)
}
function formatPercent(value: number) {
return `${trimNumber(value, value >= 10 ? 1 : 2)}%`
}
function formatTokens(value: number) {
if (value >= 1_000_000_000_000)
return `${trimNumber(value / 1_000_000_000_000, value >= 10_000_000_000_000 ? 0 : 1)}T`
if (value >= 1_000_000_000) return `${trimNumber(value / 1_000_000_000, value >= 10_000_000_000 ? 0 : 1)}B`
if (value >= 1_000_000) return `${trimNumber(value / 1_000_000, value >= 10_000_000 ? 0 : 1)}M`
if (value >= 1_000) return `${trimNumber(value / 1_000, value >= 10_000 ? 0 : 1)}K`
return String(Math.round(value))
}
function trimNumber(value: number, digits: number) {
return Number(value.toFixed(digits)).toLocaleString("en")
}
function usageHeight(value: number, max: number) {
if (value <= 0 || max <= 0) return 0
return Math.max(4, (value / max) * 100)
}
function isLabUsageDense(count: number) {
return count > 20
}
function isLabUsageLabelHidden(index: number, count: number) {
if (count <= 14) return false
const cadence = count > 45 ? 7 : count > 28 ? 4 : 2
return index % cadence !== 0 && index !== count - 1
}