an.audio.elevenlabs_tts#
ElevenLabsTTS — real speech via the ElevenLabs API. Requires ELEVEN_API_KEY.
Lazily imports the elevenlabs SDK so the rest of an works without it.
If you want real speech, pip install elevenlabs and set
ELEVEN_API_KEY (or ELEVENLABS_API_KEY) in your environment.
Expressive voices (an#209). A voice document in the voices store may
declare, beside voice_id, the model_id it speaks with, its
voice_settings and a sampling seed; a dialogue line’s [emotion] and
{direction} reach a model that takes inline audio tags (eleven_v3,
eleven_v4 and their variants) as [excited] Hi!.
ElevenLabsTTS.synthesis_options() turns those into the keyword arguments
ElevenLabsTTS.synthesize() takes — the audio pipeline keys its cache on
exactly that dict, and a voice declaring none of them yields {}, so no
existing cache key moves.
>>> tts = ElevenLabsTTS(api_key="unused")
>>> tts.synthesis_options({})
{}
>>> tts.synthesis_options({"model_id": "eleven_v3"}, emotion="happy", direction=["sighs"])
{'model_id': 'eleven_v3', 'audio_tags': ['happy', 'sighs']}
>>> tts.synthesis_options({"voice_settings": {"stability": 0.3, "speed": 1.1}})
{'voice_settings': {'speed': 1.1, 'stability': 0.3}}
>>> tagged_text("Hi!", ["excited"])
'[excited] Hi!'
Module Attributes
Model ids that read inline audio tags ( |
|
The |
Functions
The canonical |
|
|
|
|
Whether |
Classes
|
ElevenLabs-backed TTSProvider. |
Exceptions
A request cannot be sent: no API key is configured. |
|
A voice document declares ElevenLabs settings that are malformed. |
- an.audio.elevenlabs_tts.AUDIO_TAG_MODEL_PREFIXES: tuple[str, ...] = ('eleven_v3', 'eleven_v4')#
Model ids that read inline audio tags (
[excited],[sighs]). Matched as prefixes, soeleven_v3_conversationalandeleven_v4_turbocount. Every other model would speak the brackets, so it never receives a tag.
- class an.audio.elevenlabs_tts.ElevenLabsTTS(*, api_key=None, model_id='eleven_turbo_v2_5', output_format='mp3_44100_128', audio_tag_model_prefixes=('eleven_v3', 'eleven_v4'), client_factory=None)[source]#
Bases:
objectElevenLabs-backed TTSProvider. Constructor takes an optional api_key (falls back to
ELEVEN_API_KEY/ELEVENLABS_API_KEY).Implements the
TTSProviderprotocol, plus the optionalsynthesis_optionshook the audio pipeline reads (an#209).- billed_characters(text, *, audio_tags=None, **_options)[source]#
Characters one request bills: the text as sent, audio tags included.
- Return type:
>>> ElevenLabsTTS(api_key="unused").billed_characters("Hi!", audio_tags=["excited"]) 13
- check_available()[source]#
Raise
ElevenLabsUnavailableErrorwhen a request could not be sent (no API key) — what the audio pipeline asks before the first request of a render, so nothing is half-synthesized (an#305).- Return type:
- client_factory#
api_key -> client; tests inject a fake so nothing reaches the API.
- list_voices(*, search=None)[source]#
The account’s voices (its own plus the ones it saved), newest API.
searchfilters by name, description and labels on the server. An absent key or SDK yields[]; a key that is present and a call that fails RAISES — an empty listing must mean “no voices”, not “it broke”.
- synthesis_options(voice, *, emotion=None, direction=None)[source]#
The
synthesizekeyword arguments a voice document and a line imply.Only what is declared appears (
{}for a plain voice), so the audio cache key — which includes this dict when it is non-empty — is unchanged for every voice that declares nothing new.audio_tagsare the line’s[emotion](unlessneutral) then itsdirectioncues, and only on a model that reads tags; elsewhere a direction is dropped with a warning and the emotion stays a face-only cue, as before.
- synthesize(text, voice_id=None, *, model_id=None, voice_settings=None, seed=None, audio_tags=None, **kw)[source]#
Speak
text. The clip’stranscriptistextWITHOUT the tags, so alignment and captions never read a cue.- Return type:
- take_options(options, take)[source]#
The request for candidate
takeof a best-of-N line (an.audio.takes).A declared
seedis offset by the take, so a model that does honour it (every model buteleven_v3, measured) still returns different takes; without a seed the request is unchanged and the model’s own sampling varies the take.>>> ElevenLabsTTS(api_key="unused").take_options({"seed": 11}, 2) {'seed': 13}
Bases:
RuntimeErrorA request cannot be sent: no API key is configured.
- exception an.audio.elevenlabs_tts.ElevenLabsVoiceError[source]#
Bases:
ValueErrorA voice document declares ElevenLabs settings that are malformed.
- an.audio.elevenlabs_tts.VOICE_SETTINGS_RANGES: dict[str, tuple[float, float] | None] = {'similarity_boost': (0.0, 1.0), 'speed': (0.7, 1.2), 'stability': (0.0, 1.0), 'style': (0.0, 1.0), 'use_speaker_boost': None}#
The
voice_settingskeys the API takes, with the range each accepts (None= a boolean).speedis the API’s documented 0.7–1.2.
- an.audio.elevenlabs_tts.normalize_voice_settings(raw)[source]#
The canonical
voice_settingsdict — only what was declared, key-sorted.Omit-when-unset:
Noneand{}give{}. Unknown keys and values out of range raise, so a typo cannot silently fall back to the account default.>>> normalize_voice_settings({"style": 1, "stability": 0.25}) {'stability': 0.25, 'style': 1.0} >>> normalize_voice_settings({"stabilty": 0.5}) Traceback (most recent call last): ... an.audio.elevenlabs_tts.ElevenLabsVoiceError: unknown voice_settings key(s) ['stabilty']; known: ['similarity_boost', 'speed', 'stability', 'style', 'use_speaker_boost']