File size: 2,144 Bytes
004f460
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { useI18n } from '../i18n'
import { Callout } from './ui'
import type { BiometricResult } from '../biometrics/results'

const TONE: Record<BiometricResult['summaryKey'], 'ok' | 'bad' | 'warn'> = {
  'result.match': 'ok', 'result.pass': 'ok', 'result.enrolled': 'ok',
  'result.noMatch': 'bad', 'result.fail': 'bad', 'result.enrollFailed': 'bad',
  'result.inconclusive': 'warn',
}

/** Renders a backend-produced biometric decision. Shows scores as understandable
 *  labels + a collapsible technical panel. Never renders templates/embeddings. */
export function ResultPanel({ r }: { r: BiometricResult }) {
  const { t } = useI18n()
  return (
    <div className="result-panel">
      <Callout tone={TONE[r.summaryKey]}>{t(r.summaryKey)}</Callout>
      <dl className="summary-grid">
        {r.similarity !== undefined && (<><dt>{t('result.similarity')}</dt><dd>{r.similarity.toFixed(3)}</dd></>)}
        {r.threshold !== undefined && (<><dt>{t('result.threshold')}</dt><dd>{r.threshold.toFixed(3)}</dd></>)}
        {r.deepfakeScore != null && (
          <><dt>{t('result.deepfake')}</dt>
            <dd>{r.deepfakeScore.toFixed(3)} <span className="hint">({t('bio.experimental')})</span></dd></>
        )}
      </dl>
      {r.perModality && Object.keys(r.perModality).length > 0 && (
        <dl className="summary-grid">
          <dt className="section">{t('bio.perModality')}</dt><dd />
          {Object.entries(r.perModality).map(([m, s]) => (
            <div key={m} style={{ display: 'contents' }}>
              <dt>{t(`bio.modality.${m}` as 'bio.modality.face')}</dt><dd>{s.toFixed(3)}</dd>
            </div>
          ))}
        </dl>
      )}
      <details className="support">
        <summary>{t('tech.title')}</summary>
        <dl className="tech-grid mono" dir="ltr">
          {r.userId && (<><dt>{t('bio.userId')}</dt><dd>{r.userId}</dd></>)}
          {r.modalities && (<><dt>modalities</dt><dd>{r.modalities.join(', ')}</dd></>)}
          <dt>{t('tech.requestId')}</dt><dd>{r.requestId ?? '—'}</dd>
          <dt>{t('tech.created')}</dt><dd>{r.at}</dd>
        </dl>
      </details>
    </div>
  )
}