Refactor to request matching/replacement substrings from LLMs, rather than requesting a complete replacement for the full original text

This commit is contained in:
2026-04-21 12:33:15 -05:00
parent 23532cade1
commit 4296e3576e
5 changed files with 102 additions and 50 deletions

View File

@@ -1,5 +1,5 @@
from dataclasses import asdict, dataclass
from typing import Dict, Iterable, List, Optional, Tuple
from typing import Iterable, List, Optional, Tuple
from .errors import AuditaValidationError
from .schemas import CorrectionCandidate, TranscriptSegment
@@ -32,33 +32,20 @@ def apply_corrections(
if not 0.0 <= confidence_threshold <= 1.0:
raise AuditaValidationError("Confidence threshold must be between 0.0 and 1.0.")
correction_by_id: Dict[int, CorrectionCandidate] = {}
revised = list(transcript)
skipped: List[SkippedCorrection] = []
for correction in corrections:
segment_id = correction.segment_id
if segment_id in correction_by_id:
skipped.append(
_skip(
correction,
"duplicate correction for segment already handled",
)
)
if correction.confidence < confidence_threshold:
continue
reason, actual_text = _target_error(transcript, correction)
reason, actual_text = _target_error(revised, correction)
if reason is not None:
skipped.append(_skip(correction, reason, actual_text=actual_text))
continue
correction_by_id[segment_id] = correction
revised: List[TranscriptSegment] = []
for original_id, segment in enumerate(transcript):
correction = correction_by_id.get(original_id)
if correction is not None and correction.confidence >= confidence_threshold:
revised.append(segment.model_copy(update={"text": correction.corrected_text}))
else:
revised.append(segment)
segment = revised[correction.segment_id]
revised_text = segment.text.replace(correction.original_text, correction.corrected_text, 1)
revised[correction.segment_id] = segment.model_copy(update={"text": revised_text})
indexed_revised = list(enumerate(revised))
indexed_revised.sort(key=lambda item: (item[1].start, item[1].end, item[0]))
@@ -76,8 +63,16 @@ def _target_error(
return "segment_id does not exist in transcript", None
segment = transcript[correction.segment_id]
if correction.original_text != segment.text:
return "original_text does not exactly match segment text", segment.text
if correction.original_text == "":
return "original_text is empty", segment.text
if correction.original_text == correction.corrected_text:
return "original_text and corrected_text are identical", segment.text
match_count = segment.text.count(correction.original_text)
if match_count == 0:
return "original_text does not match any substring in segment text", segment.text
if match_count > 1:
return "original_text appears multiple times in segment text", segment.text
return None, None

View File

@@ -31,11 +31,13 @@ def build_glossary_correction_messages(section: TranscriptSection, glossary: Glo
"- Inappropriate example: correcting \"Lyra\" to \"Jesters\" should be omitted because those words are not similar in spoken English, even if \"Jesters\" appears in the glossary.\n"
"- Do not replace one clear glossary term, character name, location, or ordinary word with a different glossary term unless it is a plausible mishearing.\n"
"- Assign high confidence only when the correction is supported by glossary evidence, local context, and spoken-word similarity; otherwise omit the correction.\n"
"- Use the exact segment_id and original_text from the input segment.\n"
"- Use the exact segment_id from the input segment.\n"
"- For returned corrections, original_text must be only the exact text span that needs replacement, not the full segment text unless the whole segment is the replacement span.\n"
"- corrected_text must be only the replacement text for that span, not the full corrected segment text unless the whole segment is the replacement span.\n"
"- Each returned correction must contain only segment_id, original_text, corrected_text, and confidence.\n"
"- Do not return corrections where original_text and corrected_text are identical.\n"
"- Do not return speaker, start, or end fields.\n"
"- Return only changed segments; do not return entries for unchanged segments.\n"
"- corrected_text must contain the full corrected text for that segment.\n"
"- confidence must be between 0.0 and 1.0.\n"
"- If no corrections are needed, return an empty corrections list.\n\n"
f"Glossary:\n{glossary_json}\n\n"