File size: 4,809 Bytes
d70f132
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import Badge from "@/components/ui/Badge";
import { fmt } from "@/lib/data";
import type { DatasetInfo } from "@/lib/types";
import HourBar from "./HourBar";

export interface SplitsTableProps {
  /** Frozen split inventory of a live dataset. */
  splits: NonNullable<DatasetInfo["splits"]>;
  /** Dataset name for the accessible caption, e.g. "ViMedCSS". */
  datasetName?: string;
}

const ROWS: ReadonlyArray<{
  key: keyof NonNullable<DatasetInfo["splits"]>;
  name: string;
  tone: "muted" | "accent" | "accent-soft";
  badge?: { label: string; variant: "accent" | "outline" };
  role: string;
}> = [
  {
    key: "train",
    name: "Train",
    tone: "muted",
    role: "Adaptation corpus — Track C systems may train on this split and nothing else.",
  },
  {
    key: "valid",
    name: "Valid",
    tone: "muted",
    role: "Hyperparameter tuning and checkpoint selection. Never reported as a result.",
  },
  {
    key: "test",
    name: "Test",
    tone: "accent",
    badge: { label: "Primary", variant: "accent" },
    role: "The primary leaderboard — every headline number on the home page is scored here.",
  },
  {
    key: "hard",
    name: "Hard",
    tone: "accent-soft",
    badge: { label: "Generalization", variant: "outline" },
    role: "Rare and unseen terms, disjoint from Train — the generalization leaderboard.",
  },
];

/** Dataset split table with proportional hour-bars and role captions. */
export default function SplitsTable({ splits, datasetName }: SplitsTableProps) {
  const totalHours = ROWS.reduce((sum, r) => sum + splits[r.key].hours, 0);

  return (
    <div className="hairline spotlight-row depth-1 overflow-x-auto rounded-sm bg-surface">
      <table className="w-full min-w-[680px] border-collapse text-sm">
        <caption className="sr-only">
          {datasetName ?? "Dataset"} splits: hours, utterances, share of total
          audio, and the role of each split
        </caption>
        <thead>
          <tr className="hairline-b text-left">
            <th
              scope="col"
              className="num px-4 py-3 text-[11px] font-normal uppercase tracking-[0.14em] text-muted"
            >
              Split
            </th>
            <th
              scope="col"
              className="num px-4 py-3 text-right text-[11px] font-normal uppercase tracking-[0.14em] text-muted"
            >
              Hours
            </th>
            <th
              scope="col"
              className="num px-4 py-3 text-right text-[11px] font-normal uppercase tracking-[0.14em] text-muted"
            >
              Utterances
            </th>
            <th
              scope="col"
              className="num px-4 py-3 text-[11px] font-normal uppercase tracking-[0.14em] text-muted"
            >
              Share of audio
            </th>
            <th
              scope="col"
              className="num px-4 py-3 text-[11px] font-normal uppercase tracking-[0.14em] text-muted"
            >
              Role
            </th>
          </tr>
        </thead>
        <tbody>
          {ROWS.map((row, i) => {
            const s = splits[row.key];
            const share = s.hours / totalHours;
            return (
              <tr
                key={row.key}
                className={i < ROWS.length - 1 ? "hairline-b align-top" : "align-top"}
              >
                <th
                  scope="row"
                  className="whitespace-nowrap px-4 py-3.5 text-left font-medium text-text"
                >
                  <span className="inline-flex items-center gap-2">
                    {row.name}
                    {row.badge && (
                      <Badge variant={row.badge.variant}>{row.badge.label}</Badge>
                    )}
                  </span>
                </th>
                <td className="num whitespace-nowrap px-4 py-3.5 text-right text-text">
                  {fmt(s.hours)}
                  <span className="text-muted"> h</span>
                </td>
                <td className="num whitespace-nowrap px-4 py-3.5 text-right text-text">
                  {s.utts.toLocaleString("en-US")}
                </td>
                <td className="px-4 py-3.5">
                  <div className="flex items-center gap-2.5">
                    <HourBar share={share} tone={row.tone} className="w-24 md:w-32" />
                    <span className="num text-[11px] text-muted">
                      {(share * 100).toFixed(1)}%
                    </span>
                  </div>
                </td>
                <td className="min-w-[16rem] px-4 py-3.5 text-[13px] leading-relaxed text-muted">
                  {row.role}
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}