Skip to content

ElevenLabs: model-aware SpeechMarkdown dialects, modelId, voice_settings.speed - #34

Merged
willwade merged 4 commits into
mainfrom
feat/elevenlabs-speechmarkdown
Sep 4, 2026
Merged

ElevenLabs: model-aware SpeechMarkdown dialects, modelId, voice_settings.speed#34
willwade merged 4 commits into
mainfrom
feat/elevenlabs-speechmarkdown

Conversation

@willwade

@willwade willwade commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

ElevenLabs previously routed SpeechMarkdown through the Alexa SSML fallback and then stripped it to plain text in speak() — every break, tag and IPA hint was silently lost. This wires up the real dialects added in AACTools/speechmarkdown-rust#4:

  • preprocess_speech_markdown routes "elevenlabs" → pre-v3 prompt markup (<break time>) and "elevenlabs-v3" → audio-tag dialect ([pause], [whispers], "/IPA/"), returned with is_ssml=false so the dialect text reaches the API verbatim instead of being stripped
  • speak() picks the dialect from the model: eleven_v3* → audio tags. The model is now settable via the modelId credential (was hardcoded eleven_multilingual_v2). The mapping must follow the model — v3 reads stray XML aloud, pre-v3 reads audio tags aloud
  • rate (1.0 = normal) maps to the deterministic voice_settings.speed API parameter, clamped to the documented 0.7–1.2; only sent for explicit non-default rates
  • ElevenLabs boundary offsets search the caller's original input when SpeechMarkdown was reformatted (injected tags shifted offsets against the processed string)
  • live-cloud template: v3 audio-tag synthesis + timestamps tests; also fixed the stale template (it didn't compile — speak() gained on_mark, boundary callbacks a bool)
  • .env.example documents ELEVENLABS_MODEL_ID
  • [patch.crates-io] points speechmarkdown-rust at the feat/elevenlabs-dialects git branch (relative-path patch can't resolve in CI); swap to a version bump after 0.4.14 publishes

Test plan

ElevenLabs previously routed SpeechMarkdown through the Alexa fallback
and then stripped it to plain text in speak() — every break, tag and
IPA hint was silently lost. Now:

- preprocess_speech_markdown routes elevenlabs to the pre-v3 prompt
  dialect (<break time>) and elevenlabs-v3 to the audio-tag dialect
  ([pause], [whispers], "/IPA/"), returning is_ssml=false so the
  dialect text reaches the API verbatim instead of being stripped
- speak() picks the dialect from the model: eleven_v3* (settable via
  the modelId credential, previously hardcoded to multilingual_v2)
  gets audio tags — v3 reads stray XML aloud, pre-v3 reads tags aloud,
  so the mapping must follow the model
- rate (1.0 = normal) maps to the deterministic voice_settings.speed
  API parameter, clamped to the documented 0.7-1.2 range
- ElevenLabs boundary offsets search the caller's original input when
  SpeechMarkdown was reformatted (injected tags shifted offsets)
- live-cloud template: v3 audio-tag synthesis + timestamps tests, and
  fixed the stale template (speak() gained on_mark, boundary callbacks
  a bool) so it compiles again
- [patch.crates-io] points speechmarkdown-rust at the sibling checkout
  until >= 0.4.14 (Platform::ElevenLabsV3) is published
…branch

The relative-path patch only resolves in a sibling checkout; CI needs
the pushed branch. Swap to a version bump after 0.4.14 is published.
…ecedence

- extract elevenlabs_smd_platform() and assert against the production
  helper (the test previously checked a local copy that would keep
  passing if the real predicate flipped)
- derived voice_settings no longer clobbers a config-supplied one
  (skipped when extra_body carries voice_settings; also inserted before
  the extra_body loop so config wins either way)
- live template header lists the v3 dialect tests; README notes the
  3s break clamp
v0.4.14 (published from the merged ElevenLabs PR) carries
Platform::ElevenLabsV3 and the expressive/strict-break parser work —
drop the temporary [patch.crates-io] git-branch override.
@willwade
willwade merged commit be24707 into main Sep 4, 2026
22 checks passed
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.

1 participant