65 lines
2.8 KiB
Python
65 lines
2.8 KiB
Python
"""Confidence-band classification — single source of truth for the cut points.
|
|
|
|
The workbook colours and the review queue MUST agree about what counts as red.
|
|
If each applied its own threshold they would drift the first time one is tuned,
|
|
and a reviewer would see a red cell the queue never asked them to check.
|
|
Everything that needs a band imports from here.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Optional
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Cut points
|
|
# ---------------------------------------------------------------------------
|
|
# Calibrated against the measured distribution over all 225 extracted rows of
|
|
# the six sample documents:
|
|
#
|
|
# 1.00 69.8% crisp print
|
|
# 0.90-0.99 18.2% crisp print
|
|
# 0.80-0.89 11.0% almost entirely handwritten CPT and modifiers
|
|
# 0.70-0.79 0.0% <- empty; the natural gap in this data
|
|
# <0.70 1.1% handwritten modifiers
|
|
#
|
|
# 0.80 left only 1.1% of cells red so nearly everything went green and the
|
|
# colour carried no information. 0.90 sits in the empty band and separates
|
|
# the handwriting cluster from printed text.
|
|
CONFIDENCE_THRESHOLD: float = 0.90
|
|
|
|
# Above CONFIDENCE_THRESHOLD the 0.90-0.99 band is still 18.2% of cells, and
|
|
# routing treats it differently from a clean 1.00: reviewers sample it rather
|
|
# than either trusting it outright or checking every one. A second cut at
|
|
# 0.95 names that band so the sheet shows what the routing rule already assumes.
|
|
#
|
|
# GREEN >= 0.95 clean print, straight through
|
|
# AMBER 0.90-0.95 slightly unclear, sampled
|
|
# RED < 0.90 handwriting cluster, always reviewed
|
|
GREEN_THRESHOLD: float = 0.95
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Band name constants
|
|
# ---------------------------------------------------------------------------
|
|
BAND_GREEN = "green"
|
|
BAND_AMBER = "amber"
|
|
BAND_RED = "red"
|
|
|
|
|
|
def band_of(score: Optional[float]) -> Optional[str]:
|
|
"""Return the confidence band name, or ``None`` when the value was never scored.
|
|
|
|
WHAT THE BAND CLAIMS: green means the source text this value came from was
|
|
transcribed cleanly. It does NOT mean the value is correct. The score is
|
|
the model's own legibility rating, so a confident misread comes back scored
|
|
high. Verifying correctness needs a second, independent read. Red is the
|
|
useful direction: it reliably surfaces handwriting.
|
|
|
|
Amber does not mean "probably fine". It means the reading was good enough to
|
|
escape the handwriting cluster but not clean enough to trust unsampled, which
|
|
is a routing decision, not a quality claim.
|
|
"""
|
|
if score is None:
|
|
return None
|
|
if score >= GREEN_THRESHOLD:
|
|
return BAND_GREEN
|
|
return BAND_AMBER if score >= CONFIDENCE_THRESHOLD else BAND_RED
|