File size: 5,795 Bytes
729628a
 
 
 
 
 
 
 
 
 
 
fb23187
 
729628a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb23187
 
 
 
 
 
 
 
 
 
 
 
729628a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb23187
 
 
 
729628a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb23187
 
 
 
 
 
 
 
 
 
 
 
729628a
fb23187
 
 
 
 
 
729628a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import Box from '@mui/material/Box';
import Chip from '@mui/material/Chip';
import Alert from '@mui/material/Alert';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Typography from '@mui/material/Typography';
import type { ClassMetrics, QualityMetrics, ScenarioMetrics } from '../../types/labeleval';
import { SectionCard, MetricCard, fmtPct, fmtInt } from './shared';
import { ExplainTip, HeadCell } from '../help/InfoTip';
import { glossaryKeyForStatus } from '../../content/glossary';

function PrTable({ title, rows }: { title: string; rows: Array<ClassMetrics | ScenarioMetrics> }) {
  return (
    <Box sx={{ flex: '1 1 320px', minWidth: 300 }}>
      <Typography variant="caption" sx={{ color: '#8a949e', fontWeight: 700 }}>
        {title}
      </Typography>
      {rows.length === 0 ? (
        <Typography variant="body2" sx={{ color: '#8a949e', mt: 1 }}>
          No data yet.
        </Typography>
      ) : (
        <Table size="small">
          <TableHead>
            <TableRow>
              <TableCell>{'class_name' in (rows[0] ?? {}) ? 'Class' : 'Scenario'}</TableCell>
              <TableCell align="right">
                <HeadCell label="Precision" term="precision" />
              </TableCell>
              <TableCell align="right">
                <HeadCell label="Recall" term="recall" />
              </TableCell>
              <TableCell align="right">
                <HeadCell label="F1" term="f1" />
              </TableCell>
              <TableCell align="right">
                <HeadCell label="Support" title="Support" detail="Number of reference objects behind this row — small support means noisy metrics." />
              </TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map((r) => {
              const name = 'class_name' in r ? r.class_name : r.scenario;
              return (
                <TableRow key={name} hover>
                  <TableCell sx={{ fontWeight: 600 }}>{name.replace(/_/g, ' ')}</TableCell>
                  <TableCell align="right" sx={{ fontFamily: 'monospace', fontSize: 12 }}>
                    {fmtPct(r.precision)}
                  </TableCell>
                  <TableCell align="right" sx={{ fontFamily: 'monospace', fontSize: 12 }}>
                    {fmtPct(r.recall)}
                  </TableCell>
                  <TableCell align="right" sx={{ fontFamily: 'monospace', fontSize: 12 }}>
                    {fmtPct(r.f1)}
                  </TableCell>
                  <TableCell align="right" sx={{ fontFamily: 'monospace', fontSize: 12 }}>
                    {fmtInt(r.support)}
                  </TableCell>
                </TableRow>
              );
            })}
          </TableBody>
        </Table>
      )}
    </Box>
  );
}

export default function GroundTruthComparison({ metrics }: { metrics: QualityMetrics | null }) {
  const gtType = metrics?.gt_type ?? null;
  return (
    <SectionCard
      title="Ground Truth Comparison"
      help="Precision/recall of the auto-labels measured against this dataset's reference labels. The trustworthiness of these numbers depends entirely on the GT tier — hover the GT type chip. Against pseudo-GT they are directional signals only."
    >
      {!metrics ? (
        <Typography variant="body2" sx={{ color: '#8a949e' }}>
          No quality metrics yet — run the evaluation pipeline.
        </Typography>
      ) : (
        <>
          <Box sx={{ display: 'flex', gap: 1.5, flexWrap: 'wrap', alignItems: 'center', mb: 1.5 }}>
            <Chip
              size="small"
              label={metrics.gt_available ? 'GT available' : 'No GT reference'}
              sx={{
                bgcolor: metrics.gt_available ? '#1b3a24' : '#4a1f1f',
                color: metrics.gt_available ? '#a5d6a7' : '#ef9a9a',
                fontWeight: 700,
              }}
            />
            {gtType ? (
              <ExplainTip term={glossaryKeyForStatus(gtType) ?? 'gt_coverage'}>
                <Chip
                  size="small"
                  label={gtType.replace(/_/g, ' ')}
                  sx={{
                    bgcolor: gtType === 'PSEUDO_GROUND_TRUTH' ? '#4a2c00' : '#1b3a24',
                    color: gtType === 'PSEUDO_GROUND_TRUTH' ? '#ffcc80' : '#a5d6a7',
                    fontWeight: 700,
                    cursor: 'help',
                  }}
                />
              </ExplainTip>
            ) : null}
            <MetricCard label="Coverage" value={fmtPct(metrics.gt_coverage)} term="gt_coverage" />
            <MetricCard
              label="Evaluation confidence"
              value={metrics.gt_available ? 'per-dataset' : 'none'}
              info="How much to trust GT-based metrics here: high for human-verified/gold references, medium for vendor labels, low for pseudo-GT, none without any reference."
            />
          </Box>

          {gtType === 'PSEUDO_GROUND_TRUTH' ? (
            <Alert severity="warning" variant="outlined" sx={{ mb: 1.5 }}>
              Pseudo-GT comparison, not gold-standard evaluation — reference labels were themselves machine-generated.
              Treat precision/recall below as directional signals, not certified quality figures.
            </Alert>
          ) : null}

          <Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
            <PrTable title="PER-CLASS PRECISION / RECALL" rows={metrics.per_class} />
            <PrTable title="PER-SCENARIO PRECISION / RECALL" rows={metrics.per_scenario} />
          </Box>
        </>
      )}
    </SectionCard>
  );
}