Skip to main content
Some bots need hundreds of pronunciation overrides: medication names, product names, place names. There are two ways to do this. Both build on text transforms.

Client side with replace_text

replace_text builds one transform from a list of (pattern, replacement) pairs. It works with every TTS service because the substitution happens in Pipecat before the text is sent.
Rules are regular expressions, compiled once. Each chunk of text runs through the list in order, so cost grows in a straight line with rule count and stays small: on an Apple silicon laptop, 300 rules added about 0.4 ms per sentence and 1000 rules about 1.4 ms. Your hardware and patterns will move those numbers. Two tips:
  • Order matters. Rules run in sequence, so an earlier replacement can change what a later rule matches.
  • Use word boundaries (\b) so “cat” does not rewrite the middle of “catheter”.
Multi-word replacements need sentence aggregation. Text transforms run after text aggregation and see one aggregation at a time. With TextAggregationMode.TOKEN, text passes straight through with no buffering, so a pattern that spans more than one word never matches: the words arrive in separate calls. If your lexicon has any multi-word entry ("beta blocker", "St. John's wort"), keep the default sentence aggregation.

Provider side lexicons

Some services host the lexicon for you. This keeps the list out of your process but ties you to that provider.
NVIDIA custom_dictionary entries cannot contain commas. The dictionary is sent as one comma separated string with no escaping, so a comma inside an entry splits it and corrupts the rest of the dictionary. Strip commas first.
Azure has no pronunciation lexicon path in Pipecat. AzureTTSService escapes your text before wrapping it in SSML, so a <phoneme> tag injected by a text transform is read out loud as literal characters. There is no flag to turn this off. On Azure, use respellings through replace_text.

ElevenLabs: prefer respellings over IPA

Respellings need no flags and work on every model, so they are the safer default for a large lexicon.