Spaces:
Sleeping
Sleeping
| import type { ModelRow, Provenance, SplitMetrics } from "@/lib/types"; | |
| import SectionLabel from "./SectionLabel"; | |
| import TopicChart, { type TopicWer } from "./TopicChart"; | |
| export interface TopicBreakdownProps { | |
| model: ModelRow; | |
| } | |
| /** The five ViMedCSS topic domains (ghost state when no breakdown exists). */ | |
| const TOPICS = [ | |
| "Medical Sciences", | |
| "Pathology & Pathogens", | |
| "Treatments", | |
| "Nutrition", | |
| "Diagnostics", | |
| ]; | |
| /** | |
| * Per-topic data is an optional forward-compatible extension of | |
| * SplitMetrics (`topics: [{ topic, wer }]`) written by platform runs; | |
| * paper imports never carry it, so we runtime-guard the shape. | |
| */ | |
| function readTopics(metrics?: ModelRow["metrics"]): TopicWer[] | null { | |
| for (const split of ["test", "hard"] as const) { | |
| const m = metrics?.[split] as | |
| | (SplitMetrics & { topics?: unknown }) | |
| | undefined; | |
| const t = m?.topics; | |
| if ( | |
| Array.isArray(t) && | |
| t.length > 0 && | |
| t.every( | |
| (x): x is TopicWer => | |
| typeof x === "object" && | |
| x !== null && | |
| typeof (x as { topic?: unknown }).topic === "string" && | |
| typeof (x as { wer?: unknown }).wer === "number", | |
| ) | |
| ) { | |
| return t; | |
| } | |
| } | |
| return null; | |
| } | |
| function gapReason(provenance: Provenance): string { | |
| if (provenance === "running") | |
| return "the pilot run executing now records it per domain"; | |
| if (provenance === "planned") return "no run exists yet"; | |
| if (provenance === "paper-imported") | |
| return "paper imports report corpus-level scores only"; | |
| return "this submission did not include a per-domain breakdown"; | |
| } | |
| /** | |
| * Per-topic WER section: recharts horizontal bars when a run recorded the | |
| * breakdown, otherwise an evidence-gap mini-note listing the five domains. | |
| */ | |
| export default function TopicBreakdown({ model }: TopicBreakdownProps) { | |
| const topics = readTopics(model.metrics); | |
| return ( | |
| <section className="flex flex-col gap-4"> | |
| <SectionLabel | |
| index="04" | |
| title="Per-topic WER" | |
| hint="five ViMedCSS domains" | |
| /> | |
| {topics ? ( | |
| <div className="hairline depth-1 rounded-sm bg-surface p-5"> | |
| <TopicChart data={topics} /> | |
| </div> | |
| ) : ( | |
| <div className="rounded-sm border border-dashed border-line px-5 py-4"> | |
| <p className="max-w-xl text-[13px] leading-relaxed text-muted"> | |
| Per-topic WER is unavailable for this row —{" "} | |
| {gapReason(model.provenance)}. Platform-verified runs break WER | |
| down across the five ViMedCSS domains: | |
| </p> | |
| <ul className="mt-3 flex flex-wrap gap-1.5"> | |
| {TOPICS.map((t) => ( | |
| <li | |
| key={t} | |
| className="num rounded-sm border border-line/70 px-1.5 py-0.5 text-[11px] tracking-wide text-muted" | |
| > | |
| {t} | |
| </li> | |
| ))} | |
| </ul> | |
| </div> | |
| )} | |
| </section> | |
| ); | |
| } | |