mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-10 03:08:27 +00:00
fix(stats): refine lab page tooltips
This commit is contained in:
parent
5668d36477
commit
beb586a383
3 changed files with 39 additions and 8 deletions
|
|
@ -469,6 +469,12 @@ function LabUsageSection(props: { lab: ModelCatalogLab; data: StatsLabData | nul
|
|||
</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>
|
||||
)
|
||||
}}
|
||||
|
|
@ -759,7 +765,7 @@ function relatedLabStats(labs: ModelCatalogLab[], market: MarketDay[]) {
|
|||
}
|
||||
|
||||
function labRelatedDescription(lab: ModelCatalogLab) {
|
||||
return lab.description ?? `OpenCode Go usage across ${lab.name} models, recent token volume, and model limits.`
|
||||
return lab.description ?? ""
|
||||
}
|
||||
|
||||
function relatedTone(share: number) {
|
||||
|
|
|
|||
|
|
@ -4218,7 +4218,7 @@
|
|||
|
||||
[data-page="stats"] [data-component="model-usage-chart"][data-variant="lab-usage"] [data-component="chart-tooltip"] {
|
||||
z-index: 6;
|
||||
top: clamp(12px, calc(var(--lab-usage-user-y) * 1% - 38px), calc(100% - 92px));
|
||||
top: clamp(12px, calc(var(--lab-usage-user-y) * 1% - 46px), calc(100% - 108px));
|
||||
width: 192px;
|
||||
min-width: 192px;
|
||||
background: var(--stats-bg);
|
||||
|
|
@ -4240,7 +4240,7 @@
|
|||
|
||||
[data-page="stats"] [data-component="model-usage-chart"][data-variant="lab-usage"] [data-component="chart-tooltip"] p {
|
||||
height: 16px;
|
||||
margin: 8px 0;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
[data-page="stats"]
|
||||
|
|
@ -4250,6 +4250,13 @@
|
|||
background: var(--lab-usage-active);
|
||||
}
|
||||
|
||||
[data-page="stats"]
|
||||
[data-component="model-usage-chart"][data-variant="lab-usage"]
|
||||
[data-component="chart-tooltip"]
|
||||
i[data-kind="users"] {
|
||||
background: var(--lab-usage-line);
|
||||
}
|
||||
|
||||
[data-page="stats"] [data-component="model-peer-list"] {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { query } from "@solidjs/router"
|
|||
|
||||
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
|
||||
|
|
@ -57,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) {
|
||||
|
|
@ -113,9 +115,9 @@ 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 labDescriptions = readCatalogLabDescriptions(payload, pricingPayload)
|
||||
const labDescriptions = readCatalogLabDescriptions(payload, pricingPayload, labPayload)
|
||||
const models = readCatalogModels(payload)
|
||||
.flatMap(readModelCatalogEntry)
|
||||
.map((model) => ({
|
||||
|
|
@ -191,7 +193,8 @@ function readCatalogLabDescriptions(...payloads: unknown[]) {
|
|||
if (!description) return
|
||||
const id = stringValue(value.id) ?? fallbackId
|
||||
const name = stringValue(value.name)
|
||||
const keys = [id, name]
|
||||
const title = stringValue(value.title)
|
||||
const keys = [id, name, title]
|
||||
keys.forEach((key) => {
|
||||
if (!key) return
|
||||
descriptions.set(catalogLabSlug(key), description)
|
||||
|
|
@ -226,6 +229,21 @@ async function fetchCatalogPayload(url: string) {
|
|||
.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) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue