Skip to content

fix: handle SSML phoneme attribute order in ssml_to_deepgram - #741

Merged
GregHolmes merged 3 commits into
deepgram:mainfrom
NishchayMahor:fix/ssml-phoneme-attribute-order
Sep 1, 2026
Merged

fix: handle SSML phoneme attribute order in ssml_to_deepgram#741
GregHolmes merged 3 commits into
deepgram:mainfrom
NishchayMahor:fix/ssml-phoneme-attribute-order

Conversation

@NishchayMahor

Copy link
Copy Markdown
Contributor

What

ssml_to_deepgram() only recognized <phoneme> tags when the attributes were in alphabet-before-ph order. Since SSML attribute order is not significant, a perfectly valid tag written the other way was silently dropped:

ssml_to_deepgram('<phoneme alphabet="ipa" ph="ˌæzə">azathioprine</phoneme>')
# -> {"word": "azathioprine", "pronounce": "ˌæzə"}   ✅

ssml_to_deepgram('<phoneme ph="ˌæzə" alphabet="ipa">azathioprine</phoneme>')
# -> "azathioprine"   ❌  pronunciation silently lost

The regex hardcoded alphabet=... ph=...; when reversed, the tag didn't match phoneme_pattern and fell through to the generic <[^>]+> strip, leaving only the bare word — no error, so the caller never knows the pronunciation was dropped.

Fix

Match the <phoneme> attributes as a group and pull ph out of it, so order no longer matters (src/deepgram/helpers/text_builder.py). If there's no ph attribute, it degrades gracefully to the plain word. Behavior for the existing alphabet-first form is unchanged.

Testing

Added test_phoneme_attribute_order_independent to TestSsmlToDeepgram. pytest tests/custom/test_text_builder.py45 passed. Pure string transformation — no API key/network.

ssml_to_deepgram only matched <phoneme> tags with alphabet before ph, so
<phoneme ph="..." alphabet="ipa">word</phoneme> silently lost its
pronunciation and fell through to the generic tag strip, leaving the bare
word. SSML attribute order is not significant, so match the attributes as a
group and pull ph out of it. Add a regression test.
@GregHolmes
GregHolmes merged commit 7fd4b63 into deepgram:main Sep 1, 2026
10 checks passed
GregHolmes added a commit that referenced this pull request Sep 3, 2026
🤖 I have created a release *beep* *boop*
---


##
[7.8.1](v7.8.0...v7.8.1)
(2026-09-03)


### Bug Fixes

* **TextBuilder:** `ssml_to_deepgram()` now preserves a `<phoneme>`
pronunciation when its valid `ph` and `alphabet` attributes appear in
either order.
([#741](#741))
([7fd4b63](7fd4b63))
* **Credentials:** Explicitly passing `api_key=None` continues to
disable ambient `DEEPGRAM_API_KEY` lookup, which is important for
multi-tenant and test environments.
([#778](#778))
([e675990](e675990))
* **Credentials:** `DeepgramClient()` and `AsyncDeepgramClient()` now
resolve `DEEPGRAM_API_KEY` when constructed, so `load_dotenv()` can run
after importing the SDK. Closes
[#734](#734).
([#767](#767))
([ec362ec](ec362ec))
* **Custom transports:** Speak V2 WebSocket connections now honor
`transport_factory`, matching the routing behavior of other WebSocket
APIs for proxies, test doubles, and custom-hosted transports.
([#766](#766))
([0980663](0980663))


### Documentation

* **Transcription:** Clarified that Nova-3 assumes English when
`language` is omitted; non-English and multilingual audio require an
explicit language such as `fr` or `multi`.
([#771](#771))
([4574337](4574337))
* **Examples:** Added Listen V1 live microphone transcription with
optional `sounddevice`, device selection, bounded audio buffering,
transcript output, and clean Ctrl-C shutdown.
([#780](#780))
([08f0471](08f0471))
* **Examples:** Added a resilient Listen V1 live transcription pattern
with exponential backoff, reconnect-aware audio buffering, timestamp
continuity, and clean shutdown.
([#776](#776))
([96b2d11](96b2d11))
* **Examples:** Added an application-owned Voice Agent session recorder
that serializes received transcripts, function calls, and latency
reports as JSON while leaving consent, redaction, retention, and storage
policy to the application. Closes
[#775](#775).
([#781](#781))
([30ad152](30ad152))
* **Text-to-Speech:** Corrected streaming synthesis snippets to iterate
the response byte chunks instead of accessing a nonexistent `.stream`
attribute.
([#749](#749))
([178724e](178724e))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Greg Holmes <greg.holmes@deepgram.com>
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.

2 participants