Speech overrides
A SpeechOverride maps a source surface to caller-chosen spoken text. It can match literal substrings or whole words, case-sensitively or case-insensitively, and can be scoped to all units, one unit, or one exact occurrence.
Global and unit-scoped overrides
from ttsready import OverrideScope, SpeechOverride, TextUnit, prepare_units
unit = TextUnit("chapter-1", "ACME ships 2 kg parcels.", "en-US")
company = SpeechOverride("ACME", "A C M E") # all units
weight = SpeechOverride(
"kg",
"kilograms",
scope=OverrideScope("unit", "chapter-1"),
)
result = prepare_units((unit,), overrides=(company, weight))
The default match mode is word. Use match="literal" to match a substring inside a larger token. The default is case-sensitive; set case_sensitive=False for case-insensitive matching.
Exact occurrence
For a correction that applies only to one occurrence, use source-relative half-open offsets:
from ttsready import OverrideScope, SpeechOverride, TextUnit, prepare_units
unit = TextUnit("caption-1", "Use ACME here, not ACME there.", "en-US")
first_start = unit.text.index("ACME")
override = SpeechOverride(
"ACME",
"A C M E",
scope=OverrideScope(
"occurrence",
unit.id,
first_start,
first_start + len("ACME"),
),
)
result = prepare_units((unit,), overrides=(override,))
An occurrence override must exactly select its declared source surface. It cannot overlap a protected span.
Precedence and conflicts
More specific overrides take precedence: occurrence-scoped overrides, then unit-scoped overrides, then global overrides. A higher-priority overlapping rule wins and a lower-priority rule is reported in result.issues. Equally ranked overlapping overrides with different spoken text raise OverrideConflictError; resolve that conflict in caller policy before preparation.
Override IDs are deterministic when omitted. They identify the policy and scope; change IDs identify source occurrences independently of the selected replacement. Override provenance can carry JSON-safe caller metadata.