diff --git a/internal/domain/domain.go b/internal/domain/domain.go index f570839..afceb7f 100644 --- a/internal/domain/domain.go +++ b/internal/domain/domain.go @@ -129,6 +129,50 @@ type Transcription struct { Segments []Segment Endpoint string AudioSeconds float64 + // Reconciliation is set when two engines transcribed the same audio and a local + // model chose between their disagreements (ADR-034). Nil for a single engine. + Reconciliation *Reconciliation +} + +// ReconcileStatus says what became of an attempt to merge two transcripts. +type ReconcileStatus string + +const ( + // ReconcileDone: both engines produced text and the disagreements were resolved. + ReconcileDone ReconcileStatus = "reconciled" + // ReconcileSingle: only one engine produced text, so there was nothing to merge. + ReconcileSingle ReconcileStatus = "single_engine" + // ReconcileSkipped: both engines produced text but the model could not be used; + // the base text stands, unreconciled. + ReconcileSkipped ReconcileStatus = "skipped" +) + +// ContestedSpot is a place the engines disagreed that a reader may want to check +// against the audio: one the model changed, or one it was unsure about. +type ContestedSpot struct { + Seconds float64 `json:"seconds"` // roughly where in the recording + Base string `json:"base"` // what the base engine heard + Alt string `json:"alt"` // what the other engine heard + Used string `json:"used"` // "base" or "alt": the reading now in the text + Unsure bool `json:"unsure"` // the model could not decide; the base was kept +} + +// Reconciliation records how a merged transcript came about, so the page can say so +// plainly and the user can check the uncertain spots. The counts are exact; Contested +// is bounded. +type Reconciliation struct { + Status ReconcileStatus `json:"status"` + Reason string `json:"reason,omitempty"` // why single_engine or skipped + Base string `json:"base"` // engine whose text is the base + Alt string `json:"alt"` + Reconciler string `json:"reconciler"` + Disputes int `json:"disputes"` // places the engines disagreed + AutoResolved int `json:"auto_resolved"` // trivial: compounds, filler words + Adjudicated int `json:"adjudicated"` // decided by the model + Changed int `json:"changed"` // the alternative's reading was used + Unsure int `json:"unsure"` // base kept, flagged + Errors int `json:"errors"` // model calls that failed + Contested []ContestedSpot `json:"contested,omitempty"` } // UploadStatus is the state of an uploaded-audio transcription job.