Skip to content

fix(helpers): decode XML entities in ssml_to_deepgram - #812

Open
RaphaelFakhri wants to merge 1 commit into
deepgram:mainfrom
RaphaelFakhri:fix/ssml-xml-entities
Open

RaphaelFakhri wants to merge 1 commit into
deepgram:mainfrom
RaphaelFakhri:fix/ssml-xml-entities

Conversation

@RaphaelFakhri

Copy link
Copy Markdown

What

ssml_to_deepgram() and TextBuilder.from_ssml() strip SSML tags but never decode XML entities. SSML is XML, so text such as AT&T or it's is commonly written as AT&T or it's. Those entities reach the TTS request unchanged, so the voice reads the markup:

from deepgram.helpers import ssml_to_deepgram

ssml_to_deepgram("<speak>Call AT&amp;T, it&apos;s open.</speak>")
# before: 'Call AT&amp;T, it&apos;s open.'
# after:  "Call AT&T, it's open."

ssml_to_deepgram('<phoneme alphabet="ipa" ph="t&#601;">AT&amp;T</phoneme>')
# before: '\{"word": "AT&amp;T", "pronounce": "t&#601;"\}'
# after:  '\{"word": "AT&T", "pronounce": "tə"\}'

Fix

src/deepgram/helpers/text_builder.py decodes the five predefined XML entities (&amp;, &lt;, &gt;, &quot;, &apos;) and numeric character references (&#39;, &#x2C8;):

  • In the <phoneme> word and ph value, before building the pronunciation control, so json.dumps escapes the decoded characters correctly.
  • In the remaining text after tag stripping, so escaped markup such as &lt;break/&gt; stays literal text instead of being parsed or removed. Inline controls are skipped so they are not decoded twice. A <phoneme> without an IPA alphabet keeps its word as text, which is decoded once in this step.

The decoder handles XML entities only. HTML-only names such as &copy; and bare & are left unchanged.

Testing

Added four tests to TestSsmlToDeepgram in tests/custom/test_text_builder.py: entities in text, entities in a <phoneme> word and ph value, escaped markup that must stay text, and a non-IPA <phoneme> whose word is decoded only once.

  • Without the fix: pytest tests/custom/test_text_builder.py gives 4 failed, 56 passed.
  • With the fix: 60 passed.
  • ruff check passes and mypy src/deepgram/helpers reports no issues.

Fixes #811

Copilot AI balanced review requested due to automatic review settings October 22, 2026 12:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: ssml_to_deepgram leaves XML entities such as &amp; and &apos; in the TTS text

2 participants