chore: merge dev into v2 (#35591)

Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com>
Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Jack <jack@anoma.ly>
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: James Long <longster@gmail.com>
Co-authored-by: Dustin Deus <deusdustin@gmail.com>
Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com>
Co-authored-by: Jay <53023+jayair@users.noreply.github.com>
Co-authored-by: runvip <164729189+runvip@users.noreply.github.com>
Co-authored-by: opencode <opencode@sst.dev>
Co-authored-by: Julian Coy <julian@ex-machina.co>
Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: Simon Klee <hello@simonklee.dk>
Co-authored-by: Jay <air@live.ca>
Co-authored-by: David Hill <1879069+iamdavidhill@users.noreply.github.com>
This commit is contained in:
Aiden Cline
2026-07-06 16:05:29 -05:00
committed by GitHub
parent 285231bb3d
commit e192f8a4e5
332 changed files with 24650 additions and 4497 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-app",
"version": "1.17.13",
"version": "1.17.14",
"private": true,
"type": "module",
"license": "MIT",
+11 -2
View File
@@ -4,8 +4,10 @@ import { createStore } from "solid-js/store"
import { createSimpleContext } from "@opencode-ai/ui/context"
import {
LOCALES,
cookie,
detectFromLanguages,
dir,
fromPathname,
label,
localeFromCookieHeader,
localeFromRequest,
@@ -19,11 +21,16 @@ function initial() {
const event = getRequestEvent()
if (event) return localeFromRequest(event.request)
if (typeof window === "object") {
const fromPath = fromPathname(window.location.pathname)
if (fromPath) return fromPath
}
if (typeof document === "object") {
const fromDom = parseLocale(document.documentElement.dataset.locale)
if (fromDom) return fromDom
const fromCookie = localeFromCookieHeader(document.cookie)
if (fromCookie) return fromCookie
const fromDom = parseLocale(document.documentElement.dataset.locale)
if (fromDom) return fromDom
}
if (typeof navigator !== "object") return "en" satisfies Locale
@@ -55,6 +62,8 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
},
setLocale(next: Locale) {
setStore("locale", next)
if (typeof document !== "object") return
document.cookie = cookie(next)
},
}
},
+3 -3
View File
@@ -154,14 +154,14 @@ const en = {
"lab.notFound": "No models matched this lab.",
"lab.heroPrefix": "Explore {{count}} {{lab}} models used in OpenCode",
"lab.heroIncluding": "including {{models}}",
"lab.heroSuffix": "Compare recent token usage, context windows, release dates, and model-specific data.",
"lab.heroSuffix": "Compare recent token usage, context windows, release dates, and model data.",
"lab.tokensProcessed": "Tokens Processed",
"lab.pending": "Pending",
"lab.usageAfterActivity": "Usage appears after model activity lands",
"lab.latestRelease": "Latest release {{date}}",
"lab.shareOfUsage": "{{share}} of recent OpenCode usage",
"lab.usageTitle": "{{lab}} token usage",
"lab.usageDescription": "Daily OpenCode token volume over the last two months.",
"lab.usageDescription": "Daily token volume.",
"lab.noUsageTitle": "No usage yet",
"lab.noUsageDescription": "Recent token usage appears here once this lab has activity.",
"lab.dailyTokenChart": "{{lab}} daily token usage chart",
@@ -198,7 +198,7 @@ const en = {
"model.knowledge": "Knowledge",
"model.release": "Release",
"model.inputs": "Inputs",
"model.overviewDescription": "Recent OpenCode Go tokens, unique users, and market position.",
"model.overviewDescription": "Recent tokens, unique users, and market position.",
"model.noSummaryTitle": "No usage summary",
"model.noSummaryDescription": "This model has no OpenCode Go usage rows yet.",
"model.tokens": "Tokens",
+429 -312
View File
@@ -27,6 +27,7 @@ import {
findModelCatalogEntry,
formatCatalogLabName,
getModelCatalog,
type ModelCatalog,
type ModelCatalogCost,
type ModelCatalogEntry,
} from "../model-catalog"
@@ -47,6 +48,7 @@ import {
const statsUnfurlPath = "banner.png"
const geoMapWidth = 960
const geoMapHeight = 430
const shortMonths = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"] as const
type IsoCountryCode = readonly [string, string, string]
type WorldCountryProperties = GeoJsonProperties & { name?: string }
@@ -118,8 +120,7 @@ export default function StatsModel() {
const statsUnfurlUrl = new URL(statsUnfurlPath, localizedUrl("en", "/data/")).toString()
const modelHeaderLinks = createMemo<readonly HeaderLink[]>(() => [
{ href: "#overview", label: i18n.t("nav.overview") },
{ href: "#usage", label: i18n.t("nav.usage") },
{ href: "#users", label: i18n.t("nav.users") },
{ href: "#momentum", label: i18n.t("model.momentum") },
{ href: "#efficiency", label: i18n.t("nav.efficiency") },
{ href: "#geo-breakdown", label: i18n.t("nav.geoBreakdown") },
{ href: "#peers", label: i18n.t("nav.peers") },
@@ -174,10 +175,14 @@ export default function StatsModel() {
<Show when={catalogEntry() || stats() !== undefined} fallback={<ModelLoading />}>
<Show when={catalogEntry() || stats()} fallback={<ModelNotFound lab={labParam()} model={modelParam()} />}>
<>
<ModelHero data={stats() ?? null} catalog={catalogEntry() ?? null} labName={labName()} />
<ModelOverview data={stats() ?? null} />
<ModelUsageSection data={stats()?.usage ?? []} />
<ModelUsersSection data={stats()?.usage ?? []} />
<ModelHero
data={stats() ?? null}
catalog={catalogEntry() ?? null}
catalogData={catalog() ?? null}
labName={labName()}
/>
<ModelOverview catalog={catalogEntry() ?? null} />
<ModelMomentumSection data={stats() ?? null} />
<ModelEfficiencySection data={stats() ?? null} catalog={catalogEntry() ?? null} />
<ModelGeoBreakdownSection data={stats()?.country ?? emptyCountryRecord()} />
<ModelPeersSection data={stats() ?? null} />
@@ -249,128 +254,227 @@ function ModelNotFound(props: { lab: string; model: string }) {
)
}
function ModelHero(props: { data: StatsModelData | null; catalog: ModelCatalogEntry | null; labName: string }) {
function ModelHero(props: {
data: StatsModelData | null
catalog: ModelCatalogEntry | null
catalogData: ModelCatalog | null
labName: string
}) {
const i18n = useI18n()
const language = useLanguage()
const labId = () => props.catalog?.lab ?? props.data?.provider ?? props.labName
const modelId = () => props.catalog?.id ?? props.data?.model ?? i18n.t("model.fallback")
const modelName = () => props.catalog?.name ?? props.data?.model ?? i18n.t("model.fallback")
const weights = () => props.catalog?.weights[0]
const labs = () => props.catalogData?.labs ?? []
const labModels = () =>
props.catalogData?.labs.find((lab) => lab.id === providerSlug(labId()))?.models ??
(props.catalog ? [props.catalog] : [])
return (
<section id="overview" data-section="model-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">
<div data-slot="model-hero-tags">
<a data-slot="hero-meta" href={language.route(`${import.meta.env.BASE_URL}${providerSlug(labId())}`)}>
<ProviderIcon aria-hidden="true" id={getProviderIconId(labId())} />
<nav data-component="model-hero-breadcrumb" aria-label="Data breadcrumb">
<a data-slot="model-hero-crumb" href={language.route(import.meta.env.BASE_URL)}>
Data
</a>
<span data-slot="model-hero-separator">/</span>
<Show
when={labs().length > 0}
fallback={
<span data-slot="model-hero-crumb" data-current="true">
<span>{props.labName}</span>
</a>
<span data-slot="model-id-tag">{modelId()}</span>
</div>
<h1>
<a data-slot="heading-link" href="#overview">
{props.catalog?.name ?? props.data?.model ?? i18n.t("model.fallback")}
</a>
</h1>
<Show when={props.data} fallback={<p>{i18n.t("model.catalogFallback")}</p>}>
{(data) => (
<p>
{data().rank === null ? i18n.t("model.unranked") : i18n.t("model.ranked", { rank: data().rank ?? "" })}{" "}
{i18n.t("model.observedVolume", { share: formatPercent(data().tokenShare) })}
</p>
)}
</Show>
<ChevronDownIcon />
</span>
}
>
<details data-component="model-hero-menu">
<summary data-slot="model-hero-crumb" data-current="true">
<span>{props.labName}</span>
<ChevronDownIcon />
</summary>
<div data-slot="model-hero-options">
<For each={labs()}>
{(lab) => (
<a
data-slot="model-hero-option"
data-current={lab.id === providerSlug(labId()) ? "true" : undefined}
href={language.route(`${import.meta.env.BASE_URL}${lab.id}`)}
>
{lab.name}
</a>
)}
</For>
</div>
</details>
</Show>
<span data-slot="model-hero-separator">/</span>
<Show
when={labModels().length > 0}
fallback={
<span data-slot="model-hero-crumb" data-current="true" aria-current="page">
<span>{modelName()}</span>
<ChevronDownIcon />
</span>
}
>
<details data-component="model-hero-menu">
<summary data-slot="model-hero-crumb" data-current="true" aria-current="page">
<span>{modelName()}</span>
<ChevronDownIcon />
</summary>
<div data-slot="model-hero-options">
<For each={labModels()}>
{(model) => (
<a
data-slot="model-hero-option"
data-current={model.id === props.catalog?.id ? "true" : undefined}
href={language.route(`${import.meta.env.BASE_URL}${model.id}`)}
>
{model.name}
</a>
)}
</For>
</div>
</details>
</Show>
</nav>
<div data-slot="model-hero-title-row">
<span data-slot="model-hero-avatar">
<ProviderIcon aria-hidden="true" id={getProviderIconId(labId())} />
</span>
<h1>{modelName()}</h1>
<div data-slot="model-hero-actions">
<Show when={props.catalog?.openWeights && weights()}>
{(weight) => (
<a data-slot="model-weight-link" href={weight().url} target="_blank" rel="noopener noreferrer">
{i18n.t("model.weights", { label: weight().label })}
<a data-slot="model-hero-action" href={weight().url} target="_blank" rel="noopener noreferrer">
<ModelHeroActionIcon kind="weights" />
<span>Model weights</span>
</a>
)}
</Show>
</div>
<Show when={props.data} fallback={<ModelCatalogCallout catalog={props.catalog} />}>
{(data) => (
<div data-component="model-rank-panel">
<span>{i18n.t("model.rank")}</span>
<strong>{data().rank === null ? "—" : `#${data().rank}`}</strong>
<p>{formatModelRankMoveLabel(data(), i18n)}</p>
</div>
)}
</Show>
</div>
<div data-slot="model-hero-pattern" aria-hidden="true" />
<Show when={props.catalog}>{(catalog) => <ModelCatalogPanel data={catalog()} />}</Show>
<Show
when={props.data}
fallback={
<p data-slot="model-hero-state">
<span>Listed</span>
<span>across the shared model catalog.</span>
</p>
}
>
{(data) => (
<p data-slot="model-hero-rankline">
<span>Ranked</span>
<span data-slot="model-hero-rank-group">
<span data-slot="model-hero-pill">{formatHeroRank(data().rank)}</span>
<ModelHeroSparkline data={data()} />
</span>
<span>across last week's</span>
<span data-slot="model-hero-pill">OpenCode Go</span>
<span>usage with</span>
<span data-slot="model-hero-pill">{formatPercent(data().tokenShare)}</span>
<span>of observed</span>
<span data-slot="model-hero-pill">2M</span>
<span>volume.</span>
</p>
)}
</Show>
</section>
)
}
function ModelCatalogCallout(props: { catalog: ModelCatalogEntry | null }) {
function ModelHeroActionIcon(props: { kind: "weights" | "compare" }) {
if (props.kind === "weights")
return (
<svg data-slot="model-hero-action-icon" viewBox="0 0 16 16" aria-hidden="true" fill="none">
<path d="M5.5 4.5H4.5V11.5H11.5V10.5" stroke="currentColor" stroke-linecap="square" />
<path d="M8.5 4.5H11.5V7.5" stroke="currentColor" stroke-linecap="square" />
<path d="M11.25 4.75L7.25 8.75" stroke="currentColor" stroke-linecap="square" />
</svg>
)
return (
<svg data-slot="model-hero-action-icon" viewBox="0 0 16 16" aria-hidden="true" fill="none">
<rect x="3.5" y="3.5" width="3" height="3" stroke="currentColor" />
<rect x="9.5" y="3.5" width="3" height="3" stroke="currentColor" />
<rect x="3.5" y="9.5" width="3" height="3" stroke="currentColor" />
<rect x="9.5" y="9.5" width="3" height="3" stroke="currentColor" />
</svg>
)
}
function ModelHeroSparkline(props: { data: StatsModelData }) {
const values = () => props.data.usage.slice(-14).map((point) => point.tokens)
return (
<span data-slot="model-hero-sparkline" aria-hidden="true">
<svg viewBox="0 0 36 24" fill="none">
<path d={sparklineAreaPath(values())} fill="currentColor" opacity="0.14" />
<path d={sparklineLinePath(values())} stroke="currentColor" stroke-width="1.5" stroke-linejoin="round" />
</svg>
</span>
)
}
function ChevronDownIcon() {
return (
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true" fill="none">
<path d="M4.75 6.25L8 9.5L11.25 6.25" stroke="currentColor" stroke-width="1.5" />
</svg>
)
}
function ModelOverview(props: { catalog: ModelCatalogEntry | null }) {
const i18n = useI18n()
const language = useLanguage()
const specs = createMemo(() => [
{
label: i18n.t("model.context"),
value: formatCatalogLimit(props.catalog?.limit?.context, i18n.t("home.unknown")),
},
{
label: i18n.t("model.output"),
value: formatCatalogLimit(props.catalog?.limit?.output, i18n.t("home.unknown")),
},
{
label: i18n.t("model.knowledge"),
value: formatCatalogMonth(props.catalog?.knowledge, language.tag(language.locale()), i18n.t("home.unknown")),
},
{
label: i18n.t("model.release"),
value: formatCatalogMonth(props.catalog?.releaseDate, language.tag(language.locale()), i18n.t("home.unknown")),
},
{
label: i18n.t("model.inputs"),
value: formatCatalogModalities(
props.catalog?.modalities.input ?? [],
language.tag(language.locale()),
i18n.t("home.unknown"),
),
},
])
return (
<section id="model-overview" data-section="model-specs" aria-label={i18n.t("nav.overview")}>
<For each={specs()}>
{(spec) => (
<div data-component="model-spec">
<span>{spec.label}</span>
<strong>{spec.value}</strong>
</div>
)}
</For>
</section>
)
}
function ModelMomentumSection(props: { data: StatsModelData | null }) {
const i18n = useI18n()
const language = useLanguage()
return (
<div data-component="model-rank-panel">
<span>{i18n.t("model.profile")}</span>
<strong>
{props.catalog?.releaseDate
? formatCatalogDate(props.catalog.releaseDate, language.tag(language.locale()), i18n.t("home.unknown"))
: i18n.t("model.listed")}
</strong>
<p>{i18n.t("model.noCurrentUsage")}</p>
</div>
)
}
function ModelCatalogPanel(props: { data: ModelCatalogEntry }) {
const i18n = useI18n()
const language = useLanguage()
return (
<aside data-component="model-catalog" aria-label={i18n.t("model.facts")}>
<div data-slot="model-catalog-grid">
<CatalogDatum
label={i18n.t("model.context")}
value={formatCatalogLimit(props.data.limit?.context, i18n.t("home.unknown"))}
/>
<CatalogDatum
label={i18n.t("model.output")}
value={formatCatalogLimit(props.data.limit?.output, i18n.t("home.unknown"))}
/>
<CatalogDatum
label={i18n.t("model.knowledge")}
value={formatCatalogDate(props.data.knowledge, language.tag(language.locale()), i18n.t("home.unknown"))}
/>
<CatalogDatum
label={i18n.t("model.release")}
value={formatCatalogDate(props.data.releaseDate, language.tag(language.locale()), i18n.t("home.unknown"))}
/>
<CatalogDatum
label={i18n.t("model.inputs")}
value={formatCatalogModalities(props.data.modalities.input, i18n)}
/>
</div>
</aside>
)
}
function CatalogDatum(props: { label: string; value: string }) {
return (
<article data-component="model-catalog-datum">
<span>{props.label}</span>
<strong>{props.value}</strong>
</article>
)
}
function ModelOverview(props: { data: StatsModelData | null }) {
const i18n = useI18n()
return (
<section id="model-overview" data-section="model-panel">
<SectionTitle
href="#model-overview"
title={i18n.t("nav.overview")}
description={i18n.t("model.overviewDescription")}
/>
<section id="momentum" data-section="model-momentum">
<h2 data-slot="model-momentum-title">
<a href="#momentum">{i18n.t("model.momentum")}.</a>
<span>{i18n.t("model.overviewDescription")}</span>
</h2>
<div data-slot="model-momentum-pattern" aria-hidden="true" />
<Show
when={props.data}
fallback={
@@ -378,189 +482,83 @@ function ModelOverview(props: { data: StatsModelData | null }) {
}
>
{(data) => (
<div data-component="model-metric-grid">
<MetricCard
label={i18n.t("model.tokens")}
value={formatTokens(data().totals.tokens)}
detail={i18n.t("model.lastTwoMonths")}
/>
<MetricCard
label={i18n.t("model.uniqueUsers")}
value={formatUsers(data().totals.uniqueUsers)}
detail={i18n.t("model.lastTwoMonths")}
/>
<MetricCard
label={i18n.t("model.sessions")}
value={formatInteger(data().totals.sessions)}
detail={i18n.t("model.completedSessions")}
/>
<MetricCard
label={i18n.t("model.tokenShare")}
value={formatPercent(data().tokenShare)}
detail={i18n.t("model.totalModels", { count: data().totalModels })}
/>
<MetricCard
label={i18n.t("model.momentum")}
value={formatChange(data().tokenChange)}
detail={i18n.t("model.vsPreviousWindow")}
state={data().tokenChange < 0 ? "negative" : "positive"}
/>
</div>
<>
<MomentumChart data={data()} locale={language.tag(language.locale())} />
<div data-slot="model-momentum-metrics">
<MomentumMetric label={i18n.t("model.uniqueUsers")} value={formatUsers(data().totals.uniqueUsers)} />
<MomentumMetric
label={capitalizeLabel(i18n.t("model.completedSessions"))}
value={formatInteger(data().totals.sessions)}
/>
<MomentumMetric label={i18n.t("model.tokenShare")} value={formatPercent(data().tokenShare)} />
<MomentumMetric
label="Rank"
value={formatRankLabel(data().rank)}
watermark={formatRankLabel(data().rank)}
/>
</div>
</>
)}
</Show>
</section>
)
}
function ModelUsageSection(props: { data: ModelUsagePoint[] }) {
const i18n = useI18n()
function MomentumChart(props: { data: StatsModelData; locale: string }) {
const chart = createMemo(() => momentumChart(props.data.usage, props.data.updatedAt))
const changeState = createMemo(() => (props.data.tokenChange < 0 ? "negative" : "positive"))
return (
<section id="usage" data-section="model-panel">
<SectionTitle href="#usage" title={i18n.t("nav.usage")} description={i18n.t("model.usageDescription")} />
<Show
when={props.data.some((item) => item.tokens > 0)}
fallback={
<ModelEmptyState title={i18n.t("model.noUsageTitle")} description={i18n.t("model.noUsageDescription")} />
}
>
<ModelColumnChart data={props.data} metric="tokens" ariaLabel={i18n.t("model.dailyTokenChart")} />
</Show>
</section>
)
}
function ModelUsersSection(props: { data: ModelUsagePoint[] }) {
const i18n = useI18n()
return (
<section id="users" data-section="model-panel">
<SectionTitle href="#users" title={i18n.t("model.uniqueUsers")} description={i18n.t("model.usersDescription")} />
<Show
when={props.data.some((item) => item.users > 0)}
fallback={
<ModelEmptyState title={i18n.t("model.noUsersTitle")} description={i18n.t("model.noUsersDescription")} />
}
>
<ModelColumnChart data={props.data} metric="users" ariaLabel={i18n.t("model.dailyUserChart")} />
</Show>
</section>
)
}
function ModelColumnChart(props: { data: ModelUsagePoint[]; metric: "tokens" | "users"; ariaLabel: string }) {
const i18n = useI18n()
const [activeIndex, setActiveIndex] = createSignal<number>()
const max = createMemo(() => Math.max(0, ...props.data.map((item) => modelUsageMetricValue(item, props.metric))) || 1)
const activePoint = createMemo(() => {
const index = activeIndex()
if (index === undefined) return undefined
return props.data[index]
})
return (
<div
data-component="model-usage-chart"
data-metric={props.metric}
data-dense-labels={isModelUsageDense(props.data.length) ? "true" : undefined}
role="img"
aria-label={props.ariaLabel}
style={{ "--model-usage-count": props.data.length } as JSX.CSSProperties}
onPointerLeave={(event) => {
if (event.pointerType === "touch") return
setActiveIndex(undefined)
}}
>
<div data-slot="model-usage-axis" aria-hidden="true">
<For each={props.data}>
{(point, index) => (
<div
data-active={activeIndex() === index() ? "true" : undefined}
data-label-hidden={isModelUsageLabelHidden(index(), props.data.length) ? "true" : undefined}
>
<span data-slot="model-usage-label">
<span data-slot="model-usage-total">{formatModelUsageValue(point, props.metric)}</span>
<span data-slot="model-usage-date">{point.date}</span>
</span>
</div>
)}
</For>
<div data-component="model-momentum-chart" role="img" aria-label="Recent model token momentum">
<div data-slot="model-momentum-summary">
<div data-slot="model-momentum-total">
<strong>{formatTokens(props.data.totals.tokens)} tokens</strong>
<span data-state={changeState()}>{formatChange(props.data.tokenChange)}</span>
</div>
<p>
<span>{formatMomentumDate(chart().startDate, props.locale, props.data.updatedAt)}</span>
<span aria-hidden="true"></span>
<span>{formatMomentumDate(chart().endDate, props.locale, props.data.updatedAt)}</span>
</p>
</div>
<div data-slot="model-usage-bars">
<For each={props.data}>
{(point, index) => (
<div
data-slot="model-usage-column"
role="button"
tabIndex={0}
aria-label={`${point.date} ${formatModelUsageValue(point, props.metric)} ${modelUsageLabel(props.metric, i18n)}`}
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": `${modelUsageHeight(modelUsageMetricValue(point, props.metric), max())}%`,
} as JSX.CSSProperties
}
<div data-slot="model-momentum-plot">
<svg viewBox="0 0 1200 370" preserveAspectRatio="none" aria-hidden="true">
<path data-slot="model-momentum-line-muted" d={chart().previousPath} />
<path data-slot="model-momentum-line-active" d={chart().currentPath} />
<For each={chart().markers}>
{(marker) => (
<rect
data-slot="model-momentum-marker"
data-active={marker.active ? "true" : undefined}
x={marker.x - 3}
y={marker.y - 3}
width="6"
height="6"
/>
<Show when={activeIndex() === index() && activePoint()}>
{(active) => (
<div
data-component="chart-tooltip"
data-placement={index() > props.data.length * 0.62 ? "left" : "right"}
>
<strong>{active().date}</strong>
<span>
{formatModelUsageValue(active(), props.metric)} {modelUsageLabel(props.metric, i18n)}
</span>
<div data-slot="tooltip-divider" />
<p>
<span data-slot="tooltip-label">
<i /> {i18n.t("chart.daily")} {modelUsageLabel(props.metric, i18n)}
</span>
<b>{formatModelUsageValue(active(), props.metric)}</b>
</p>
</div>
)}
</Show>
</div>
)}
)}
</For>
</svg>
<span data-slot="model-momentum-end" data-state={changeState()} style={chart().endStyle}>
<i />
{formatChange(props.data.tokenChange)}
</span>
</div>
<div data-slot="model-momentum-months" aria-hidden="true">
<For each={momentumMonthLabels(chart().startDate, props.locale, props.data.updatedAt)}>
{(month) => <span style={{ left: `${month.x}%` }}>{month.label}</span>}
</For>
</div>
</div>
)
}
function modelUsageMetricValue(point: ModelUsagePoint, metric: "tokens" | "users") {
if (metric === "users") return point.users
return point.tokens
}
function formatModelUsageValue(point: ModelUsagePoint, metric: "tokens" | "users") {
if (metric === "users") return formatUsers(point.users)
return formatTokens(point.tokens)
}
function modelUsageLabel(metric: "tokens" | "users", i18n: ReturnType<typeof useI18n>) {
if (metric === "users") return i18n.t("format.users")
return i18n.t("format.tokens")
function MomentumMetric(props: { label: string; value: string; watermark?: string }) {
return (
<div data-component="model-momentum-metric">
<Show when={props.watermark}>{(watermark) => <em aria-hidden="true">{watermark()}</em>}</Show>
<span>{props.label}</span>
<strong>{props.value}</strong>
</div>
)
}
function ModelEfficiencySection(props: { data: StatsModelData | null; catalog: ModelCatalogEntry | null }) {
@@ -918,19 +916,111 @@ function formatGeoShare(value: number) {
return `${value.toFixed(value > 0 && value < 1 ? 1 : 0)}%`
}
function modelUsageHeight(tokens: number, max: number) {
if (tokens <= 0) return 0
return Math.max(2, Math.min(100, (tokens / max) * 100))
function momentumChart(data: ModelUsagePoint[], updatedAt: string | null) {
const fallbackDate = updatedAt ? formatMomentumDateLabel(updatedAt) : "JAN 1"
const points =
data.length > 1 ? data : [data[0] ?? emptyUsagePoint(fallbackDate), data[0] ?? emptyUsagePoint(fallbackDate)]
const max = Math.max(1, ...points.map((point) => point.tokens))
const split = Math.max(1, Math.floor((points.length - 1) / 2))
const coordinates = points.map((point, index) => ({
date: point.date,
tokens: point.tokens,
x: (index / Math.max(1, points.length - 1)) * 1200,
y: 364 - (point.tokens / max) * 364,
}))
const end = coordinates[coordinates.length - 1]
return {
startDate: coordinates[0].date,
endDate: end.date,
previousPath: smoothLinePath(coordinates.slice(0, split + 1)),
currentPath: smoothLinePath(coordinates.slice(split)),
markers: [
{ ...coordinates[0], active: false },
{ ...coordinates[split], active: true },
{ ...end, active: true },
],
endStyle: {
"--momentum-end-x": `${Math.min(94, Math.max(0, ((end.x + 8) / 1200) * 100))}%`,
"--momentum-end-y": `${Math.min(96, Math.max(0, ((end.y - 7) / 370) * 100))}%`,
} as JSX.CSSProperties,
}
}
function isModelUsageDense(count: number) {
return count > 20
function emptyUsagePoint(date: string): ModelUsagePoint {
return { date, tokens: 0, users: 0, sessions: 0, cost: 0 }
}
function isModelUsageLabelHidden(index: number, count: number) {
if (count <= 16) return false
const interval = Math.ceil(count / 8)
return index !== count - 1 && index % interval !== 0
function smoothLinePath(points: { x: number; y: number }[]) {
if (points.length === 0) return ""
if (points.length === 1) return `M${formatSparklinePoint(points[0].x)} ${formatSparklinePoint(points[0].y)}`
return points
.map((point, index) => {
if (index === 0) return `M${formatSparklinePoint(point.x)} ${formatSparklinePoint(point.y)}`
const previous = points[index - 1]
const next = points[index + 1] ?? point
const beforePrevious = points[index - 2] ?? previous
const controlStart = {
x: previous.x + (point.x - beforePrevious.x) / 6,
y: previous.y + (point.y - beforePrevious.y) / 6,
}
const controlEnd = {
x: point.x - (next.x - previous.x) / 6,
y: point.y - (next.y - previous.y) / 6,
}
return `C${formatSparklinePoint(controlStart.x)} ${formatSparklinePoint(controlStart.y)} ${formatSparklinePoint(controlEnd.x)} ${formatSparklinePoint(controlEnd.y)} ${formatSparklinePoint(point.x)} ${formatSparklinePoint(point.y)}`
})
.join(" ")
}
function momentumMonthLabels(startDate: string, locale: string, updatedAt: string | null) {
const start = parseMomentumDate(startDate, updatedAt)
const first = new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth() - 1, 1))
return Array.from({ length: 5 }, (_, index) => {
const date = new Date(Date.UTC(first.getUTCFullYear(), first.getUTCMonth() + index, 1))
return {
label: new Intl.DateTimeFormat(locale, { month: "short", timeZone: "UTC" }).format(date).toUpperCase(),
x: index === 4 ? 98 : index * 24.5,
}
})
}
function formatMomentumDate(date: string, locale: string, updatedAt: string | null) {
return new Intl.DateTimeFormat(locale, {
month: "short",
day: "numeric",
year: "numeric",
timeZone: "UTC",
})
.format(parseMomentumDate(date, updatedAt))
.toUpperCase()
}
function parseMomentumDate(date: string, updatedAt: string | null): Date {
const iso = /^(\d{4})-(\d{2})-(\d{2})/.exec(date)
if (iso) return new Date(Date.UTC(Number(iso[1]), Number(iso[2]) - 1, Number(iso[3])))
const label = /^([A-Za-z]{3})\s+(\d{1,2})$/.exec(date.trim())
const month = label ? shortMonths.findIndex((item) => item.toLowerCase() === label[1].toLowerCase()) : -1
if (!label || month < 0) return new Date(Date.UTC(1970, 0, 1))
const anchor = updatedAt ? parseMomentumDate(updatedAt, null) : new Date(Date.UTC(1970, 0, 1))
const year = month > anchor.getUTCMonth() + 1 ? anchor.getUTCFullYear() - 1 : anchor.getUTCFullYear()
return new Date(Date.UTC(year, month, Number(label[2])))
}
function formatMomentumDateLabel(date: string) {
const parsed = parseMomentumDate(date, null)
if (parsed.getUTCFullYear() === 1970) return "JAN 1"
return `${shortMonths[parsed.getUTCMonth()]} ${parsed.getUTCDate()}`
}
function formatRankLabel(rank: number | null) {
if (rank === null) return "--"
return `#${String(rank).padStart(2, "0")}`
}
function capitalizeLabel(value: string) {
return value.charAt(0).toUpperCase() + value.slice(1)
}
function formatRankMove(change: number) {
@@ -938,6 +1028,40 @@ function formatRankMove(change: number) {
return `${change}`
}
function formatHeroRank(rank: number | null) {
if (rank === null) return "--"
return String(rank).padStart(2, "0")
}
function sparklineLinePath(values: number[]) {
return sparklinePoints(values)
.map(
(point, index) => `${index === 0 ? "M" : "L"}${formatSparklinePoint(point.x)} ${formatSparklinePoint(point.y)}`,
)
.join(" ")
}
function sparklineAreaPath(values: number[]) {
const points = sparklinePoints(values)
return `M${formatSparklinePoint(points[0].x)} 18 ${points
.map((point) => `L${formatSparklinePoint(point.x)} ${formatSparklinePoint(point.y)}`)
.join(" ")} L${formatSparklinePoint(points[points.length - 1].x)} 18 Z`
}
function sparklinePoints(values: number[]) {
const normalized = values.length > 1 ? values : [values[0] ?? 0, values[0] ?? 0]
const min = Math.min(...normalized)
const max = Math.max(...normalized)
return normalized.map((value, index) => ({
x: 8 + (index / Math.max(1, normalized.length - 1)) * 20,
y: min === max ? 12 : 18 - ((value - min) / (max - min)) * 12,
}))
}
function formatSparklinePoint(value: number) {
return Number(value.toFixed(2)).toString()
}
function formatModelRankMoveLabel(data: StatsModelData, i18n: ReturnType<typeof useI18n>) {
if (data.rank === null) return i18n.t("model.noUsageLastWeek")
if (data.previousRank === null) return i18n.t("model.newThisWeek")
@@ -955,6 +1079,28 @@ function formatTokens(value: number) {
return String(Math.round(value))
}
function formatCatalogLimit(value: number | undefined, unknown: string) {
return value === undefined ? unknown : formatTokens(value)
}
function formatCatalogMonth(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
return new Intl.DateTimeFormat(locale, {
month: match[2] ? "short" : undefined,
year: "numeric",
timeZone: "UTC",
}).format(new Date(Date.UTC(Number(match[1]), match[2] ? Number(match[2]) - 1 : 0, 1)))
}
function formatCatalogModalities(values: string[], locale: string, unknown: string) {
if (values.length === 0) return unknown
const labels = values.map((value) => value.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase()))
if (labels.length === 1) return labels[0] ?? unknown
return new Intl.ListFormat(locale, { style: "long", type: "conjunction" }).format(labels)
}
function formatInteger(value: number) {
return new Intl.NumberFormat("en").format(value)
}
@@ -993,35 +1139,6 @@ function formatChange(value: number) {
return `${value}%`
}
function formatCatalogLimit(value: number | undefined, unknown: string) {
return value === undefined ? unknown : formatTokens(value)
}
function formatCatalogModalities(value: string[], i18n: ReturnType<typeof useI18n>) {
if (value.length === 0) return i18n.t("home.unknown")
return value.map((item) => formatCatalogModality(item, i18n)).join(", ")
}
function formatCatalogModality(value: string, i18n: ReturnType<typeof useI18n>) {
if (value === "pdf") return i18n.t("model.pdf")
return value.charAt(0).toUpperCase() + value.slice(1)
}
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 trimNumber(value: number, digits: number) {
return Number(value.toFixed(digits)).toLocaleString("en")
}
+668 -189
View File
@@ -1,19 +1,24 @@
import "../index.css"
import { Meta, Title } from "@solidjs/meta"
import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
import {
getStatsLabData,
getStatsHomeData,
type LabUsageModelEntry,
type MarketDay,
type ModelUsagePoint,
type StatsHomeData,
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 { createMemo, createSignal, createUniqueId, 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 {
catalogSlug,
findModelCatalogLab,
formatCatalogLabName,
getModelCatalog,
@@ -41,6 +46,19 @@ const getLabData = query(async (lab: string) => {
return runStatsEffect(getStatsLabData(lab))
}, "getStatsLabData")
const getHomeData = query(async () => {
"use server"
return runStatsEffect(getStatsHomeData())
}, "getStatsHomeData")
type LabModelTooltipState = {
model: ModelCatalogEntry
placement: "left" | "right"
usage: LabUsageModelEntry | undefined
x: number
y: number
}
export default function StatsLab() {
const i18n = useI18n()
const language = useLanguage()
@@ -60,6 +78,7 @@ export default function StatsLab() {
if (!entry) return Promise.resolve(null)
return getLabData(entry.id)
})
const homeStats = createAsync((): Promise<StatsHomeData | undefined> => getHomeData())
const githubStars = createAsync(() => getGitHubStars())
const [themePreference, setThemePreference] = createSignal<ThemePreference>("system")
const labName = createMemo(() => lab()?.name ?? formatCatalogLabName(labParam()))
@@ -118,12 +137,18 @@ export default function StatsLab() {
<div data-component="container">
<div data-component="content">
<Show when={catalog() !== undefined} fallback={<LabLoading />}>
<Show when={lab()} fallback={<LabNotFound lab={labParam()} />}>
<Show when={lab()} fallback={<LabNotFound lab={labParam()} labs={catalog()?.labs ?? []} />}>
{(data) => (
<>
<LabHero lab={data()} stats={stats() ?? null} />
<LabHero lab={data()} labs={catalog()?.labs ?? []} />
<LabOverview lab={data()} data={stats() ?? null} />
<LabUsageSection lab={data()} data={stats() ?? null} />
<LabModelsSection lab={data()} usage={stats()?.models ?? []} />
<LabRelatedSection
lab={data()}
labs={catalog()?.labs ?? []}
market={homeStats()?.market["2M"] ?? []}
/>
</>
)}
</Show>
@@ -141,201 +166,329 @@ export default function StatsLab() {
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>
<a data-slot="heading-link" href="#overview">
{i18n.t("lab.loadingTitle")}
</a>
</h1>
<p>{i18n.t("lab.loadingDescription")}</p>
</div>
</div>
<LabHeroBreadcrumb label={i18n.t("lab.loadingTitle")} />
<LabHeroTitleRow label={i18n.t("lab.loadingTitle")} />
</section>
)
}
function LabNotFound(props: { lab: string }) {
function LabNotFound(props: { lab: string; labs: ModelCatalogLab[] }) {
const i18n = useI18n()
const language = useLanguage()
const labName = () => formatCatalogLabName(props.lab)
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>
<a data-slot="heading-link" href="#overview">
{formatCatalogLabName(props.lab)}
</a>
</h1>
<p>{i18n.t("lab.notFound")}</p>
</div>
</div>
<LabHeroBreadcrumb label={labName()} labs={props.labs} />
<LabHeroTitleRow label={labName()} />
<p data-slot="lab-hero-state">{i18n.t("lab.notFound")}</p>
</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))
function LabHero(props: { lab: ModelCatalogLab; labs: ModelCatalogLab[] }) {
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")}
<LabHeroBreadcrumb label={props.lab.name} labs={props.labs} />
<LabHeroTitleRow icon={props.lab.id} label={props.lab.name} />
</section>
)
}
function LabHeroBreadcrumb(props: { label: string; labs?: ModelCatalogLab[] }) {
const language = useLanguage()
const labs = () => props.labs ?? []
return (
<nav data-component="lab-hero-breadcrumb" aria-label="Data breadcrumb">
<a data-slot="lab-hero-crumb" href={language.route(import.meta.env.BASE_URL)}>
Data
</a>
<div data-slot="model-hero-grid">
<div data-slot="model-hero-copy">
<h1>
<a data-slot="heading-link" href="#overview">
{props.lab.name}
</a>
</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>
<span data-slot="lab-hero-separator">/</span>
<Show
when={labs().length > 0}
fallback={
<span data-slot="lab-hero-crumb" data-current="true" aria-current="page">
<span>{props.label}</span>
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
<path d="M4.75 6.25L8 9.5L11.25 6.25" fill="none" stroke="currentColor" stroke-width="1.5" />
</svg>
</span>
}
>
<details data-component="lab-hero-menu">
<summary data-slot="lab-hero-crumb" data-current="true" aria-current="page">
<span>{props.label}</span>
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
<path d="M4.75 6.25L8 9.5L11.25 6.25" fill="none" stroke="currentColor" stroke-width="1.5" />
</svg>
</summary>
<div data-slot="lab-hero-options">
<For each={labs()}>
{(lab) => (
<a
data-slot="lab-hero-option"
data-current={lab.name === props.label ? "true" : undefined}
href={language.route(`${import.meta.env.BASE_URL}${lab.id}`)}
>
{lab.name}
</a>
)}
</For>
</div>
</details>
</Show>
</nav>
)
}
function LabHeroTitleRow(props: { icon?: string; label: string }) {
return (
<div data-slot="lab-hero-title-row">
<span data-slot="lab-hero-avatar" data-empty={props.icon ? undefined : "true"}>
<Show when={props.icon}>{(icon) => <ProviderIcon aria-hidden="true" id={getProviderIconId(icon())} />}</Show>
</span>
<h1>{props.label}</h1>
<div data-slot="lab-hero-pattern" aria-hidden="true" />
</div>
)
}
function LabOverview(props: { lab: ModelCatalogLab; data: StatsLabData | null }) {
const i18n = useI18n()
const language = useLanguage()
const featuredModels = createMemo(() => props.lab.models.slice(0, 3).map((model) => model.name))
return (
<section data-section="lab-overview">
<div data-slot="lab-overview-copy">
<ProviderIcon data-slot="lab-overview-watermark" aria-hidden="true" id={getProviderIconId(props.lab.id)} />
<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>
<LabOverviewMetric
label="Tokens processed"
value={props.data ? formatTokens(props.data.totals.tokens) : i18n.t("lab.pending")}
/>
<LabOverviewMetric
label="Recent usage"
value={props.data ? formatWholePercent(props.data.tokenShare) : i18n.t("lab.pending")}
/>
</section>
)
}
function LabOverviewMetric(props: { label: string; value: string }) {
return (
<article data-component="lab-overview-metric">
<span>{props.label}</span>
<strong>{props.value}</strong>
</article>
)
}
function LabUsageSection(props: { lab: ModelCatalogLab; data: StatsLabData | null }) {
const i18n = useI18n()
const activeLineClipId = createUniqueId()
const activeLineMaskId = createUniqueId()
const [activeIndex, setActiveIndex] = createSignal<number>()
const usage = createMemo(() => props.data?.usage ?? [])
const max = createMemo(() => Math.max(0, ...usage().map((item) => item.tokens)) || 1)
const tokenMax = createMemo(() => Math.max(0, ...usage().map((item) => item.tokens)) || 1)
const userMax = createMemo(() => Math.max(0, ...usage().map((item) => item.users)) || 1)
const linePoints = createMemo(() =>
usage().map((point, index) => ({
point,
x: usagePointX(index, usage().length),
y: usageLineY(point.users, userMax()),
})),
)
const userLinePath = createMemo(() => usageLinePath(linePoints()))
const activeLineBreak = createMemo(() => {
const index = activeIndex()
if (index === undefined) return undefined
const points = linePoints()
if (points.length < 2) return undefined
return usageColumnBounds(index, points.length)
})
const activeLineClip = createMemo(() => {
const index = activeIndex()
if (index === undefined) return undefined
const points = linePoints()
if (points.length < 2) return undefined
return usageColumnInnerBounds(index, points.length)
})
const monthTicks = createMemo(() => labUsageMonthTicks(usage()))
const activePoint = createMemo(() => {
const index = activeIndex()
if (index === undefined) return undefined
return usage()[index]
})
const activeTooltip = createMemo(() => {
const index = activeIndex()
const point = activePoint()
if (index === undefined || !point) return undefined
const bounds = usageColumnBounds(index, usage().length)
return {
bounds,
index,
point,
userY: linePoints()[index]?.y ?? 100,
}
})
return (
<section id="usage" data-section="model-panel">
<SectionHeading
href="#usage"
title={i18n.t("lab.usageTitle", { lab: props.lab.name })}
description={i18n.t("lab.usageDescription")}
/>
<SectionHeading href="#usage" title={i18n.t("nav.usage")} description={i18n.t("lab.usageDescription")} />
<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-variant="lab-usage"
data-dense-labels={isLabUsageDense(usage().length) ? "true" : undefined}
role="img"
aria-label={i18n.t("lab.dailyTokenChart", { lab: props.lab.name })}
aria-label={`${props.lab.name} daily token volume and unique active user chart`}
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"}
<div data-slot="lab-usage-plot">
<Show when={userLinePath()}>
{(path) => (
<>
<svg
data-slot="lab-usage-line"
data-layer="base"
viewBox="0 0 100 100"
preserveAspectRatio="none"
aria-hidden="true"
>
<Show when={activeLineBreak()} fallback={<path data-slot="lab-usage-line-base" d={path()} />}>
{(lineBreak) => (
<>
<defs>
<mask id={activeLineMaskId} maskUnits="userSpaceOnUse">
<rect x="0" y="-2" width="100" height="104" fill="white" />
<rect x={lineBreak().x} y="-2" width={lineBreak().width} height="104" fill="black" />
</mask>
</defs>
<path data-slot="lab-usage-line-base" d={path()} mask={`url(#${activeLineMaskId})`} />
</>
)}
</Show>
</svg>
<Show when={activeLineClip()}>
{(clip) => (
<svg
data-slot="lab-usage-line"
data-layer="active"
viewBox="0 0 100 100"
preserveAspectRatio="none"
aria-hidden="true"
>
<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>
<defs>
<clipPath id={activeLineClipId} clipPathUnits="userSpaceOnUse">
<rect x={clip().x} y="-2" width={clip().width} height="104" />
</clipPath>
</defs>
<path data-slot="lab-usage-line-active" d={path()} clip-path={`url(#${activeLineClipId})`} />
</svg>
)}
</Show>
</div>
</>
)}
</Show>
<div data-slot="lab-usage-bars">
<For each={usage()}>
{(point, index) => (
<div
data-slot="lab-usage-column"
role="button"
tabIndex={0}
aria-label={`${point.date} ${formatTokens(point.tokens)} ${i18n.t("lab.tokens")}, ${formatUsers(point.users)} ${i18n.t("format.users")}`}
data-active={activeIndex() === index() ? "true" : undefined}
data-muted={activeIndex() !== undefined && activeIndex() !== index() ? "true" : undefined}
style={
{
"--lab-usage-token-height": `${usageStripHeight(point.tokens, tokenMax())}px`,
"--lab-usage-user-y": `${linePoints()[index()]?.y ?? 100}`,
} as JSX.CSSProperties
}
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="lab-usage-token-bar" />
</div>
)}
</For>
</div>
<Show when={activeTooltip()} keyed>
{(active) => {
return (
<div
data-component="chart-tooltip"
data-placement={active.index > usage().length * 0.62 ? "left" : "right"}
style={
{
"--lab-usage-tooltip-left": `${active.bounds.x}%`,
"--lab-usage-tooltip-right": `${active.bounds.x + active.bounds.width}%`,
"--lab-usage-user-y": `${active.userY}`,
} as JSX.CSSProperties
}
>
<strong>{formatUsageTooltipDate(active.point.date)}</strong>
<span>
{formatTokens(active.point.tokens)} {i18n.t("lab.tokens")}
</span>
<div data-slot="tooltip-divider" />
<p>
<span data-slot="tooltip-label">
<i data-kind="tokens" /> {i18n.t("lab.dailyTokens")}
</span>
<b>{formatTokens(active.point.tokens)}</b>
</p>
<p>
<span data-slot="tooltip-label">
<i data-kind="users" /> {i18n.t("model.uniqueUsers")}
</span>
<b>{formatUsers(active.point.users)}</b>
</p>
</div>
)
}}
</Show>
</div>
<div data-slot="lab-usage-months" aria-hidden="true">
<For each={monthTicks()}>
{(tick) => (
<span
data-align={tick.align}
style={{ "--lab-usage-month-left": `${tick.left}%` } as JSX.CSSProperties}
>
{tick.label}
</span>
)}
</For>
</div>
@@ -347,50 +500,224 @@ function LabUsageSection(props: { lab: ModelCatalogLab; data: StatsLabData | nul
function LabModelsSection(props: { lab: ModelCatalogLab; usage: LabUsageModelEntry[] }) {
const i18n = useI18n()
const [activeTooltip, setActiveTooltip] = createSignal<LabModelTooltipState>()
const usageBySlug = createMemo(() => new Map(props.usage.map((item) => [item.slug, item])))
return (
<section id="models" data-section="model-panel">
<SectionHeading
href="#models"
title={i18n.t("lab.modelsTitle", { lab: props.lab.name })}
description={i18n.t("lab.recentUsageAndLimits")}
/>
<div data-component="lab-model-grid">
<For each={props.lab.models}>
{(model) => <LabModelCard model={model} usage={usageBySlug().get(model.slug)} />}
</For>
<section id="models" data-section="model-panel" data-variant="lab-models">
<div data-slot="lab-model-heading">
<SectionHeading href="#models" title={i18n.t("nav.models")} description={i18n.t("lab.recentUsageAndLimits")} />
<button data-slot="lab-model-compare" type="button" aria-label="Compare models" hidden>
<span data-slot="lab-model-compare-icon" aria-hidden="true" />
<span>Compare</span>
</button>
</div>
<div data-slot="lab-model-pattern" aria-hidden="true" />
<div
data-component="lab-model-table"
role="table"
aria-label={i18n.t("lab.modelsTitle", { lab: props.lab.name })}
>
<div data-slot="lab-model-table-track">
<div data-slot="lab-model-table-head" role="row">
<span data-column="model" role="columnheader">
{i18n.t("nav.models")}
</span>
<span data-column="usage" role="columnheader">
{i18n.t("lab.usage")}
</span>
<span data-column="share" role="columnheader">
{i18n.t("lab.share")}
</span>
<span data-column="context" role="columnheader">
{i18n.t("model.context")}
</span>
<span data-column="output" role="columnheader">
{i18n.t("model.output")}
</span>
<span data-column="release" role="columnheader">
{i18n.t("model.release")}
</span>
</div>
<For each={props.lab.models}>
{(model) => (
<LabModelRow model={model} usage={usageBySlug().get(model.slug)} onTooltipChange={setActiveTooltip} />
)}
</For>
</div>
</div>
<Show when={activeTooltip()} keyed>
{(state) => <LabModelTooltip state={state} />}
</Show>
</section>
)
}
function LabModelRow(props: {
model: ModelCatalogEntry
onTooltipChange: (state: LabModelTooltipState | undefined) => void
usage: LabUsageModelEntry | undefined
}) {
const i18n = useI18n()
const language = useLanguage()
const showTooltip = (target: HTMLAnchorElement) => {
const rect = target.getBoundingClientRect()
const viewportWidth = typeof window === "undefined" ? 0 : window.innerWidth
const viewportHeight = typeof window === "undefined" ? 0 : window.innerHeight
const anchorX = viewportWidth > 0 ? Math.min(Math.max(rect.left + 320, 24), viewportWidth - 24) : rect.left + 320
props.onTooltipChange({
model: props.model,
placement: viewportWidth > 0 && anchorX > viewportWidth - 280 ? "left" : "right",
usage: props.usage,
x: anchorX,
y:
viewportHeight > 0
? Math.min(Math.max(rect.top + rect.height / 2, 96), viewportHeight - 128)
: rect.top + rect.height / 2,
})
}
const showPointerTooltip: JSX.EventHandler<HTMLAnchorElement, PointerEvent> = (event) => {
if (event.pointerType === "touch") return
showTooltip(event.currentTarget)
}
const showFocusTooltip: JSX.EventHandler<HTMLAnchorElement, FocusEvent> = (event) => {
showTooltip(event.currentTarget)
}
return (
<a
data-component="lab-model-row"
href={language.route(`${import.meta.env.BASE_URL}${props.model.id}`)}
role="row"
aria-label={props.model.name}
onBlur={() => props.onTooltipChange(undefined)}
onFocus={showFocusTooltip}
onPointerEnter={showPointerTooltip}
onPointerDown={() => props.onTooltipChange(undefined)}
onPointerLeave={(event) => {
if (event.pointerType === "touch") return
props.onTooltipChange(undefined)
}}
onClick={() => props.onTooltipChange(undefined)}
>
<span data-slot="lab-model-cell" data-column="model" role="cell">
<span data-slot="lab-model-avatar" aria-hidden="true">
<ProviderIcon id={getProviderIconId(props.model.lab)} />
</span>
<strong>{props.model.name}</strong>
</span>
<span data-slot="lab-model-cell" data-column="usage" role="cell">
{props.usage ? formatTokens(props.usage.tokens) : "-"}
</span>
<span data-slot="lab-model-cell" data-column="share" role="cell">
{props.usage ? formatPercent(props.usage.share) : "-"}
</span>
<span data-slot="lab-model-cell" data-column="context" role="cell">
{formatCatalogLimit(props.model.limit?.context, i18n.t("home.unknown"))}
</span>
<span data-slot="lab-model-cell" data-column="output" role="cell">
{formatCatalogLimit(props.model.limit?.output, i18n.t("home.unknown"))}
</span>
<span data-slot="lab-model-cell" data-column="release" role="cell">
{formatCatalogDate(props.model.releaseDate, language.tag(language.locale()), i18n.t("home.unknown"))}
</span>
</a>
)
}
function LabModelTooltip(props: { state: LabModelTooltipState }) {
const i18n = useI18n()
return (
<div
data-component="lab-model-tooltip"
data-placement={props.state.placement}
style={
{
"--lab-model-tooltip-x": `${props.state.x}px`,
"--lab-model-tooltip-y": `${props.state.y}px`,
} as JSX.CSSProperties
}
>
<div data-slot="lab-model-tooltip-summary">
<div data-slot="lab-model-tooltip-head">
<span data-slot="lab-model-tooltip-avatar" aria-hidden="true">
<ProviderIcon id={getProviderIconId(props.state.model.lab)} />
</span>
<strong>{props.state.model.name}</strong>
</div>
<p>{props.state.model.description ?? "Recent OpenCode Go usage, share, context, and output limits."}</p>
</div>
<div data-slot="tooltip-divider" />
<div data-slot="lab-model-tooltip-metrics">
<p>
<span>{i18n.t("lab.usage")}</span>
<b>{props.state.usage ? formatTokens(props.state.usage.tokens) : "-"}</b>
</p>
<p>
<span>{i18n.t("lab.share")}</span>
<b>{props.state.usage ? formatPercent(props.state.usage.share) : "-"}</b>
</p>
<p>
<span>{i18n.t("model.context")}</span>
<b>{formatCatalogLimit(props.state.model.limit?.context, i18n.t("home.unknown"))}</b>
</p>
<p>
<span>{i18n.t("model.output")}</span>
<b>{formatCatalogLimit(props.state.model.limit?.output, i18n.t("home.unknown"))}</b>
</p>
</div>
</div>
)
}
function LabRelatedSection(props: { lab: ModelCatalogLab; labs: ModelCatalogLab[]; market: MarketDay[] }) {
const related = createMemo(() => relatedLabs(props.lab, props.labs, props.market))
return (
<section id="related-labs" data-section="model-panel" data-variant="lab-related">
<SectionHeading href="#related-labs" title="Related labs" description="Explore more." />
<div data-component="lab-related-list">
<For each={related()}>{(entry) => <LabRelatedCard entry={entry} />}</For>
</div>
</section>
)
}
function LabModelCard(props: { model: ModelCatalogEntry; usage: LabUsageModelEntry | undefined }) {
const i18n = useI18n()
function LabRelatedCard(props: { entry: RelatedLabEntry }) {
const language = useLanguage()
const featured = () => props.entry.lab.models[0]
const otherCount = () => Math.max(props.entry.lab.models.length - 1, 0)
const modelSummary = () => {
const model = featured()
if (!model) return props.entry.lab.name
const count = otherCount()
if (count === 0) return model.name
return `${model.name} + ${count} other ${count === 1 ? "model" : "models"}`
}
const activeBars = () => {
if (props.entry.share <= 0) return 0
return Math.max(1, Math.min(20, Math.round(props.entry.share / 5)))
}
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>
<a
data-component="lab-related-card"
data-tone={relatedTone(props.entry.share)}
href={language.route(`${import.meta.env.BASE_URL}${props.entry.lab.id}`)}
>
<ProviderIcon data-slot="lab-related-watermark" aria-hidden="true" id={getProviderIconId(props.entry.lab.id)} />
<div data-slot="lab-related-heading">
<span data-slot="lab-related-avatar" aria-hidden="true">
<ProviderIcon id={getProviderIconId(props.entry.lab.id)} />
</span>
<strong>{props.entry.lab.name}</strong>
</div>
<p data-slot="lab-related-copy">{labRelatedDescription(props.entry.lab)}</p>
<p data-slot="lab-related-models">{modelSummary()}</p>
<div data-slot="lab-related-divider" />
<div data-slot="lab-related-usage">
<span>Used by {formatWholePercent(props.entry.share)}</span>
<i aria-hidden="true">
<For each={Array.from({ length: 20 })}>
{(_, index) => <b data-active={index() < activeBars() ? "true" : undefined} />}
</For>
</i>
</div>
</a>
)
@@ -405,6 +732,53 @@ function LabEmptyState(props: { title: string; description: string }) {
)
}
type RelatedLabEntry = { lab: ModelCatalogLab; share: number; tokens: number }
function relatedLabs(current: ModelCatalogLab, labs: ModelCatalogLab[], market: MarketDay[]): RelatedLabEntry[] {
const stats = relatedLabStats(labs, market)
return labs
.filter((lab) => lab.id !== current.id)
.map((lab) => stats.get(lab.id) ?? { lab, share: 0, tokens: 0 })
.toSorted((a, b) => b.tokens - a.tokens || a.lab.name.localeCompare(b.lab.name))
.slice(0, 3)
}
function relatedLabStats(labs: ModelCatalogLab[], market: MarketDay[]) {
const labByKey = new Map<string, ModelCatalogLab>()
labs.forEach((lab) => {
labByKey.set(lab.id, lab)
labByKey.set(catalogSlug(lab.name), lab)
labByKey.set(catalogSlug(formatCatalogLabName(lab.id)), lab)
})
const tokensByLab = new Map<string, number>()
const total = market.reduce((sum, day) => {
day.authors.forEach((author) => {
const lab = labByKey.get(catalogSlug(author.author))
if (!lab) return
tokensByLab.set(lab.id, (tokensByLab.get(lab.id) ?? 0) + author.tokens)
})
return sum + day.total
}, 0)
return new Map(
labs.map((lab) => {
const tokens = tokensByLab.get(lab.id) ?? 0
return [lab.id, { lab, tokens, share: total > 0 ? (tokens / total) * 100 : 0 }]
}),
)
}
function labRelatedDescription(lab: ModelCatalogLab) {
return lab.description ?? ""
}
function relatedTone(share: number) {
if (share >= 50) return "high"
if (share > 0 && share < 10) return "low"
return "mid"
}
function formatCatalogLimit(value: number | undefined, unknown: string) {
return value === undefined ? unknown : formatTokens(value)
}
@@ -433,6 +807,10 @@ function formatPercent(value: number) {
return `${trimNumber(value, value >= 10 ? 1 : 2)}%`
}
function formatWholePercent(value: number) {
return `${Math.round(value).toLocaleString("en")}%`
}
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`
@@ -442,21 +820,122 @@ function formatTokens(value: number) {
return String(Math.round(value))
}
function formatUsers(value: number) {
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 new Intl.NumberFormat("en").format(Math.round(value))
}
function formatUsageTooltipDate(value: string) {
const match = /^([A-Z]{3})\s+(\d{1,2})$/.exec(value)
if (!match) return value
return `${monthName(match[1])} ${Number(match[2])} ${new Date().getFullYear()}`
}
function monthName(value: string) {
const names: Record<string, string> = {
JAN: "Jan",
FEB: "Feb",
MAR: "Mar",
APR: "Apr",
MAY: "May",
JUN: "Jun",
JUL: "Jul",
AUG: "Aug",
SEP: "Sep",
OCT: "Oct",
NOV: "Nov",
DEC: "Dec",
}
return names[value] ?? value
}
function trimNumber(value: number, digits: number) {
return Number(value.toFixed(digits)).toLocaleString("en")
}
function usageHeight(value: number, max: number) {
function usageStripHeight(value: number, max: number) {
if (value <= 0 || max <= 0) return 0
return Math.max(4, (value / max) * 100)
return Math.max(2, (value / max) * 76)
}
function usageLineY(value: number, max: number) {
if (value <= 0 || max <= 0) return 100
return Math.max(0, 100 - (value / max) * 100)
}
function usagePointX(index: number, count: number) {
if (count <= 1) return 50
return ((index + 0.5) / count) * 100
}
function usageColumnBounds(index: number, count: number) {
if (count <= 0) return { x: 0, width: 100 }
return { x: (index / count) * 100, width: 100 / count }
}
function usageColumnInnerBounds(index: number, count: number) {
const bounds = usageColumnBounds(index, count)
const inset = Math.min(bounds.width * 0.1, 0.24)
return { x: bounds.x + inset, width: Math.max(0.001, bounds.width - inset * 2) }
}
type UsageLinePoint = { x: number; y: number }
function usageLinePath(points: UsageLinePoint[]) {
if (points.length === 0) return ""
if (points.length === 1) return `M ${pathNumber(points[0].x)} ${pathNumber(points[0].y)}`
return points.slice(0, -1).reduce(
(path, point, index) => {
const next = points[index + 1]
const previous = points[index - 1] ?? point
const afterNext = points[index + 2] ?? next
const controlA = {
x: point.x + (next.x - previous.x) / 6,
y: clampUsagePercent(point.y + (next.y - previous.y) / 6),
}
const controlB = {
x: next.x - (afterNext.x - point.x) / 6,
y: clampUsagePercent(next.y - (afterNext.y - point.y) / 6),
}
return `${path} C ${pathNumber(controlA.x)} ${pathNumber(controlA.y)}, ${pathNumber(controlB.x)} ${pathNumber(controlB.y)}, ${pathNumber(next.x)} ${pathNumber(next.y)}`
},
`M ${pathNumber(points[0].x)} ${pathNumber(points[0].y)}`,
)
}
function pathNumber(value: number) {
return Number(value.toFixed(3))
}
function clampUsagePercent(value: number) {
return Math.max(0, Math.min(100, value))
}
function labUsageMonthTicks(points: ModelUsagePoint[]) {
const seen = new Set<string>()
return points.flatMap((point, index) => {
const label = point.date.split(" ")[0]
if (!label || seen.has(label)) return []
seen.add(label)
return [
{
label,
left: usagePointX(index, points.length),
align: index === 0 ? "start" : index >= points.length - 2 ? "end" : "center",
},
]
})
}
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
function getProviderIconId(provider: string) {
const id = provider.toLowerCase().replace(/[^a-z0-9]+/g, "")
if (id === "moonshot") return "moonshotai"
if (id === "zhipu") return "zhipuai"
return id
}
File diff suppressed because it is too large Load Diff
+47 -21
View File
@@ -1262,30 +1262,56 @@ function MarketShareList(props: {
onActiveAuthorChange: (author: string) => void
}) {
const i18n = useI18n()
const language = useLanguage()
return (
<ol data-component="market-share-list">
<For each={props.data}>
{(item, index) => (
<li
role="button"
tabIndex={0}
aria-label={`${item.author} ${formatTrillions(item.tokens)} ${item.share.toFixed(1)} ${i18n.t("chart.percent")}`}
data-active={props.activeAuthor === item.author ? "true" : undefined}
onPointerEnter={() => props.onActiveAuthorChange(item.author)}
onFocus={() => props.onActiveAuthorChange(item.author)}
onKeyDown={(event) => {
if (event.key !== "Enter" && event.key !== " ") return
event.preventDefault()
props.onActiveAuthorChange(item.author)
}}
>
<span>{String(index() + 1).padStart(2, "0")}</span>
<i style={{ background: getRankColor(item.author, index(), props.authorOrder, marketColors) }} />
<strong>{item.author}</strong>
<em>{formatTrillions(item.tokens)}</em>
<b>{item.share.toFixed(1)}%</b>
</li>
)}
{(item, index) => {
const label = () =>
`${item.author} ${formatTrillions(item.tokens)} ${item.share.toFixed(1)} ${i18n.t("chart.percent")}`
const content = () => (
<>
<span>{String(index() + 1).padStart(2, "0")}</span>
<i style={{ background: getRankColor(item.author, index(), props.authorOrder, marketColors) }} />
<strong>{item.author}</strong>
<em>{formatTrillions(item.tokens)}</em>
<b>{item.share.toFixed(1)}%</b>
</>
)
const href = () =>
item.author === "Other" ? undefined : language.route(`${import.meta.env.BASE_URL}${modelSlug(item.author)}`)
return (
<li
data-active={props.activeAuthor === item.author ? "true" : undefined}
onPointerEnter={() => props.onActiveAuthorChange(item.author)}
>
<Show
when={href()}
fallback={
<button
type="button"
aria-label={label()}
onClick={() => props.onActiveAuthorChange(item.author)}
onFocus={() => props.onActiveAuthorChange(item.author)}
>
{content()}
</button>
}
>
{(href) => (
<a
href={href()}
aria-label={label()}
onClick={() => props.onActiveAuthorChange(item.author)}
onFocus={() => props.onActiveAuthorChange(item.author)}
>
{content()}
</a>
)}
</Show>
</li>
)
}}
</For>
</ol>
)
+73 -5
View File
@@ -1,7 +1,8 @@
import { query } from "@solidjs/router"
export const modelCatalogSourceUrl = "https://models.dev/models.json"
export const modelCatalogSourceUrl = "https://models.dev/catalog.json"
export const modelCatalogPricingUrl = "https://models.dev/api.json"
export const modelCatalogLabSourceUrl = "https://models.dev/labs"
export type ModelCatalogCost = {
input: number
@@ -15,6 +16,7 @@ export type ModelCatalogEntry = {
lab: string
slug: string
name: string
description?: string
family?: string
knowledge?: string
releaseDate?: string
@@ -45,6 +47,7 @@ export type ModelCatalogBenchmark = {
export type ModelCatalogLab = {
id: string
name: string
description?: string
models: ModelCatalogEntry[]
}
@@ -55,11 +58,12 @@ export type ModelCatalog = {
export const getModelCatalog = query(async () => {
"use server"
const [models, pricing] = await Promise.all([
const [models, pricing, labs] = await Promise.all([
fetchCatalogPayload(modelCatalogSourceUrl),
fetchCatalogPayload(modelCatalogPricingUrl),
fetchLabCatalogPayload(modelCatalogLabSourceUrl),
])
return buildModelCatalog(models, pricing)
return buildModelCatalog(models, pricing, labs)
}, "getModelCatalog")
export function findModelCatalogEntry(catalog: ModelCatalog, model: string, lab?: string) {
@@ -111,9 +115,10 @@ export function catalogSlug(value: string) {
.replace(/-{2,}/g, "-")
}
function buildModelCatalog(payload: unknown, pricingPayload?: unknown): ModelCatalog {
function buildModelCatalog(payload: unknown, pricingPayload?: unknown, labPayload?: unknown): ModelCatalog {
const costs = readCatalogCosts(pricingPayload)
const models = (Array.isArray(payload) ? payload : isRecord(payload) ? Object.values(payload) : [])
const labDescriptions = readCatalogLabDescriptions(payload, pricingPayload, labPayload)
const models = readCatalogModels(payload)
.flatMap(readModelCatalogEntry)
.map((model) => ({
...model,
@@ -131,6 +136,7 @@ function buildModelCatalog(payload: unknown, pricingPayload?: unknown): ModelCat
result[model.lab] = {
id: model.lab,
name: formatCatalogLabName(model.lab),
description: result[model.lab]?.description ?? labDescriptions.get(model.lab),
models: [...(result[model.lab]?.models ?? []), model],
}
return result
@@ -152,6 +158,7 @@ function readModelCatalogEntry(value: unknown): ModelCatalogEntry[] {
lab: catalogSlug(lab),
slug: catalogSlug(slug),
name,
description: stringValue(value.description),
family: stringValue(value.family),
knowledge: stringValue(value.knowledge),
releaseDate: stringValue(value.release_date),
@@ -170,12 +177,73 @@ function readModelCatalogEntry(value: unknown): ModelCatalogEntry[] {
]
}
function readCatalogModels(payload: unknown): unknown[] {
if (Array.isArray(payload)) return payload
if (!isRecord(payload)) return []
if (Array.isArray(payload.models)) return payload.models
if (isRecord(payload.models)) return Object.values(payload.models)
return Object.values(payload)
}
function readCatalogLabDescriptions(...payloads: unknown[]) {
const descriptions = new Map<string, string>()
const add = (value: unknown, fallbackId?: string) => {
if (!isRecord(value)) return
const description = stringValue(value.description)
if (!description) return
const id = stringValue(value.id) ?? fallbackId
const name = stringValue(value.name)
const title = stringValue(value.title)
const keys = [id, name, title]
keys.forEach((key) => {
if (!key) return
descriptions.set(catalogLabSlug(key), description)
})
}
const addCollection = (value: unknown) => {
if (Array.isArray(value)) {
value.forEach((item) => add(item))
return
}
if (!isRecord(value)) return
Object.entries(value).forEach(([key, item]) => add(item, key))
}
payloads.forEach((payload) => {
if (Array.isArray(payload)) {
payload.forEach((item) => add(item))
return
}
if (!isRecord(payload)) return
addCollection(payload.labs)
addCollection(payload.providers)
Object.entries(payload).forEach(([key, value]) => add(value, key))
})
return descriptions
}
async function fetchCatalogPayload(url: string) {
return fetch(url)
.then((response): Promise<unknown> => (response.ok ? (response.json() as Promise<unknown>) : Promise.resolve()))
.catch(() => undefined)
}
async function fetchLabCatalogPayload(url: string) {
return fetch(url)
.then((response) => (response.ok ? response.text() : Promise.resolve("")))
.then(readLabSearchIndex)
.catch(() => undefined)
}
function readLabSearchIndex(html: string) {
const match = /<script[^>]*id=["']search-index["'][^>]*>([\s\S]*?)<\/script>/.exec(html)
if (!match) return undefined
const parsed = JSON.parse(match[1]) as unknown
if (!Array.isArray(parsed)) return undefined
return parsed.filter((item) => isRecord(item) && item.type === "lab")
}
function readCatalogCosts(payload: unknown) {
const costs = new Map<string, ModelCatalogCost>()
const add = (model: unknown, provider?: string) => {
+3 -1
View File
@@ -1,10 +1,12 @@
import { LOCALE_HEADER } from "../lib/language"
const statsPageCacheControl = "public, max-age=60, s-maxage=300, stale-while-revalidate=86400"
export function setStatsPageCacheHeaders(headers: Headers | undefined) {
if (!headers) return
headers.set("Cache-Control", statsPageCacheControl)
appendVary(headers, "Accept-Language", "Cookie")
appendVary(headers, "Accept-Language", "Cookie", LOCALE_HEADER)
}
function appendVary(headers: Headers, ...values: string[]) {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-core",
"version": "1.17.13",
"version": "1.17.14",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/stats-server",
"version": "1.17.13",
"version": "1.17.14",
"private": true,
"type": "module",
"license": "MIT",