Refactor to request matching/replacement substrings from LLMs, rather than requesting a complete replacement for the full original text
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user