diff --git a/packages/stats/app/src/routes/compare-radar.tsx b/packages/stats/app/src/routes/compare-radar.tsx new file mode 100644 index 0000000000..2b06ac1e56 --- /dev/null +++ b/packages/stats/app/src/routes/compare-radar.tsx @@ -0,0 +1,538 @@ +import { Icon } from "@opencode-ai/ui/icon" +import { createMemo, createSignal, For, Show, type JSX } from "solid-js" +import type { ModelCatalogBenchmark, ModelCatalogEntry } from "./model-catalog" + +const radarRingCount = 5 +const radarColors = ["#294bdb", "#159447", "#d24a3b", "#8a4fd2", "#b47400", "#008c95"] as const +const codingBenchmarkPattern = /(swe|aider|code|coding|nl2repo)/ +const reasoningBenchmarkPattern = /(gpqa|humanity|last exam|reasoning|aime|hmmt|math|mmlu|mrcr|charxiv|cti realm)/ +const toolUseBenchmarkPattern = /(terminal bench|claw eval|tau ?(?:bench|2|3))/ + +export type ComparisonRadarModel = { + name: string + labName: string + catalog: ModelCatalogEntry | null +} + +type ComparisonRadarProps = { + models: readonly ComparisonRadarModel[] + catalogModels: readonly ModelCatalogEntry[] +} + +type RadarAxis = { + label: string + description: string + score: (model: ModelCatalogEntry) => number | undefined +} + +type RadarSeries = { + name: string + labName: string + color: string + scores: (number | undefined)[] +} + +type RadarPoint = { + x: number + y: number +} + +export function ComparisonRadar(props: ComparisonRadarProps) { + let section: HTMLElement | undefined + const [activeAxis, setActiveAxis] = createSignal() + const axes = createMemo(() => buildRadarAxes(props.catalogModels)) + const series = createMemo(() => + props.models.map((model, index) => ({ + name: model.name, + labName: model.labName, + color: radarColors[index % radarColors.length], + scores: axes().map((axis) => (model.catalog ? axis.score(model.catalog) : undefined)), + })), + ) + const accessibleDescription = createMemo(() => + series() + .map( + (model) => + `${model.name}: ${axes() + .map((axis, index) => `${axis.label} ${formatRadarScore(model.scores[index])}`) + .join(", ")}`, + ) + .join(". "), + ) + const clearActiveAxis = (index: number) => setActiveAxis((active) => (active === index ? undefined : active)) + const download = () => downloadRadarChart(axes(), series()) + const open = () => openRadarChart(section, axes(), series()) + + return ( +
(section = element)} data-section="compare-radar" aria-label="Model capabilities"> +
    + + {(model) => ( +
  1. +