Skip to content

ElevenLabs: degrade gracefully when /with-timestamps is rejected - #35

Merged
willwade merged 2 commits into
mainfrom
fix/elevenlabs-timestamps-fallback
Sep 4, 2026
Merged

ElevenLabs: degrade gracefully when /with-timestamps is rejected#35
willwade merged 2 commits into
mainfrom
fix/elevenlabs-timestamps-fallback

Conversation

@willwade

@willwade willwade commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #34. The /with-timestamps endpoint variant was appended unconditionally whenever word boundaries were requested, for any model — but its model coverage is not documented for eleven_v3, so a boundary-requesting call on v3 could hard-fail with an opaque API error.

  • A rejected variant now retries once against the plain synthesis endpoint and flows into the streaming path with estimated boundaries. Genuine failures (auth, quota, bad voice) fail the retry too and surface their error there.
  • The estimation plan is built from the caller-facing text (boundary_search_text), not the processed prompt — injected audio tags ([whispers] …) are never estimated as spoken "words".
  • A boundaries-only degraded request now enters the streaming branch (previously it required an on_audio callback, which would have delivered audio but no boundaries at all).

This is the "support v3 as fully as we can" robustness piece that needs no API key: the fallback is empirically safe whichever way the live verification lands — if v3 supports the variant you get real character alignment, if not you get estimates instead of an error.

Test plan

  • All offline suites pass; clippy (pedantic) clean
  • Live template compiles; v3 timestamps test updated to document both outcomes
  • CI green
  • Live confirmation with ELEVENLABS_API_KEY (either outcome is now a pass; which path ran is observable)

The with-timestamps endpoint variant was appended unconditionally
whenever boundaries were requested — its model coverage is not
documented for eleven_v3, so a boundary-requesting call on v3 could
hard-fail. Now a rejected variant retries the plain synthesis endpoint
and flows into the streaming path with estimated boundaries (real
failures — auth, quota — still surface from the retry).

Also: the estimation plan is built from the caller-facing text, not
the processed prompt, so injected audio tags are never estimated as
words; and a boundaries-only degraded request now streams (previously
the streaming branch required an on_audio callback, which would have
delivered no boundaries at all).
Std-TcpListener mock serving a 404 on /with-timestamps then a 200 MP3
(0.4s silence fixture, ffmpeg-generated): asserts the variant is
attempted first, dropped on retry, and estimated boundaries fire with
offsets resolving in the caller's text — the boundaries-only degraded
entry included. No API key needed.
@willwade
willwade merged commit b7a5f7f into main Sep 4, 2026
17 of 22 checks passed
willwade added a commit that referenced this pull request Sep 4, 2026
The test file added in #35 was merged on stale green checks: its final
commit actually failed lint.yml/test.yml (unused TtsEngine import,
doc_markdown, map_unwrap_or under clippy pedantic -D warnings), leaving
main red. Fix the lints; verified against the exact CI command
(clippy --all-targets -- -D warnings with the Linux feature set) and
cargo fmt --all --check.
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