text_segment_map
Segment-level mapping between original and TTS-transformed text.
- class pipecat.utils.context.text_segment_map.TextSegment(original: str, tts: str, original_start: int, original_end: int)[source]
Bases:
objectImmutable aligned chunk between original and TTS text.
- Parameters:
original – Chunk of the user-facing / LLM text.
tts – Corresponding chunk in the TTS-transformed text.
original_start – Byte offset in original_text where this chunk begins.
original_end – Byte offset in original_text where this chunk ends.
- original: str
- tts: str
- original_start: int
- original_end: int
- property is_transformed: bool
True when this segment cannot be tracked by proportional char advancement.
This holds either when the alphanumeric content differs between original and TTS sides, or when a replacement changed the segment’s word count (e.g. splitting
"BODYPUMP"into"body pump", or letter-spacing an acronym like"API"into"A P I"). Word-splitting replacements can normalize to the same alphanumeric content on both sides, but the proportional advance still breaks: it would consume alnum chars from a single contiguous original token using word boundaries that only exist on the TTS side, landing mid-word instead of at a real boundary.
- property tts_alnum_count: int
Number of alphanumeric characters in the TTS side of this segment.
- property original_alnum_count: int
Number of alphanumeric characters in the original side of this segment.
- class pipecat.utils.context.text_segment_map.TextSegmentMap(tts_text: str, original_text: str, llm_text: str | None = None)[source]
Bases:
objectMaps cursor positions between transformed TTS text and original text.
Built once from two texts that may differ in alphanumeric content due to text transforms (e.g. currency expansion). Tracks how many TTS alnum chars have been consumed word-by-word and exposes the corresponding position in the original text.
For unchanged segments, both cursors advance proportionally. For transformed segments, both cursors are held until the entire TTS segment has been consumed, then jump to the end of the corresponding original segment in one step.
Callers advance the map word-by-word via
advance_word(), which also strips SSML tag markup from a raw word-timestamp token, tracking tags whose opening tag spans multiple words (e.g. an SSML tag with several attributes, split on whitespace by some TTS providers’ word-timestamp streams).Example:
# "$42.50" was expanded to "forty two dollars and fifty cents" smap = TextSegmentMap( "Your balance is forty two dollars and fifty cents", "Your balance is $42.50", ) for word in ["Your", "balance", "is"]: smap.advance_word(word) # unchanged segment for word in ["forty", "two", "dollars", "and", "fifty"]: smap.advance_word(word) # transformed segment, cursors held smap.advance_word("cents") # segment completes, cursors jump assert smap.last_completed_segment.original == "$42.50" assert not smap.in_transformed_segment
- __init__(tts_text: str, original_text: str, llm_text: str | None = None)[source]
Initialize the segment map.
- Parameters:
tts_text – Post-transform text sent to TTS.
original_text – User-facing pre-transform text (no surrounding tags).
llm_text – LLM-produced text, which may have surrounding tags like
<card>...</card>. Defaults tooriginal_textwhen not provided. The LLM cursor advances through this text at the same segment boundaries as the user-facing cursor.
- strip_word(word: str) str[source]
Return word with any SSML tag markup removed, without consuming it.
Non-mutating peek variant of
advance_word()’s stripping step, so callers can decide whether a word belongs here before consuming it.- Parameters:
word – Raw word token to strip.
- Returns:
word with tag markup removed.
- advance_word(word: str) str[source]
Strip tag markup from word, commit the tag state, and advance.
Combines
strip_word()with the internal char-count advance: strips word (tracking any tag left open for the next call), then advances cursors by the resulting content’s alphanumeric character count – zero for a word that is entirely tag markup.- Parameters:
word – Raw TTS word-timestamp token.
- Returns:
word with tag markup removed. Callers should use this in place of the raw word for their own alnum accounting.
- property user_facing_pos: int
Current byte offset in the original (user-facing) text.
- property llm_pos: int
Current byte offset in the LLM text.
- property in_transformed_segment: bool
True when the cursor is on a transformed segment that isn’t complete yet.
True once the segment’s alnum budget has partly been consumed (the original condition), or once a call has touched this segment without consuming anything (e.g. a leading zero-alnum fragment such as a still-open tag’s attribute text, which normalizes to
"") – as long as that call didn’t simply land here by completing the previous segment, in which case the word that triggered it belongs to that previous segment, not this one.
- property last_completed_segment: TextSegment | None
The segment completed by the last
advance_word()call, orNone.