"""Narration *delivery* presets — model + voice settings (issue #10, expressiveness).
A :class:`Delivery` bundles the ElevenLabs ``model_id`` and ``voice_settings``
that shape how expressive vs flat a narration reads. The renderer takes one so
we can A/B the same script under different deliveries and pick what has the most
relief without editing the script.
Presets here are a starting point tuned from ``docs/research/expressive-tts-
narration.md``; refine as we learn what sounds best. The key monotony levers:
lower ``stability`` and raise ``style`` add variation (at some cost in
consistency); ``eleven_v3`` adds inline audio tags for real expressive control.
"""
from __future__ import annotations
from dataclasses import dataclass, field
[docs]
@dataclass(frozen=True)
class Delivery:
"""A named narration delivery: which model + voice settings to synthesize with."""
name: str
model_id: str
voice_settings: dict = field(default_factory=dict)
supports_audio_tags: bool = False # True for eleven_v3 (bracketed [tags])
note: str = ""
# --- presets -----------------------------------------------------------------
BASELINE = Delivery(
name="baseline",
model_id="eleven_multilingual_v2",
voice_settings={
"stability": 0.5,
"similarity_boost": 0.75,
"style": 0.0,
"use_speaker_boost": True,
"speed": 0.97,
},
note="Current default — even, safe, tends flat.",
)
# ★ Research-recommended default: v2, moderately loosened + annotated text.
V2_TUNED = Delivery(
name="v2-tuned",
model_id="eleven_multilingual_v2",
voice_settings={
"stability": 0.35,
"similarity_boost": 0.75,
"style": 0.35,
"use_speaker_boost": True,
"speed": 0.98,
},
note="★ recommended: lower stability + raised style; pairs with annotated text.",
)
V2_AGGRESSIVE = Delivery(
name="v2-aggressive",
model_id="eleven_multilingual_v2",
voice_settings={
"stability": 0.28,
"similarity_boost": 0.75,
"style": 0.45,
"use_speaker_boost": True,
"speed": 0.98,
},
note="More variation, more take-to-take variance; may over-emote.",
)
# --- role deliveries: a *presenter* (lively) vs a *narrator* (grave) ----------
# Two deliveries meant to sit together in one production for tasteful contrast:
# the host/presenter reads livelier and a touch quicker; the documentary/book
# narrator reads steadier, flatter-styled and a touch slower (gravitas). Assign
# per beat via ``Narration.voice_settings`` (see braidio.render).
V2_PRESENTER = Delivery(
name="v2-presenter",
model_id="eleven_multilingual_v2",
voice_settings={
"stability": 0.35,
"similarity_boost": 0.75,
"style": 0.35,
"use_speaker_boost": True,
"speed": 0.98,
},
note="Host/presenter commentary — lively (== v2-tuned), for the spine voice.",
)
V2_NARRATOR = Delivery(
name="v2-narrator",
model_id="eleven_multilingual_v2",
voice_settings={
"stability": 0.5,
"similarity_boost": 0.8,
"style": 0.12,
"use_speaker_boost": True,
"speed": 0.94,
},
note="Documentary/book-read narrator — steadier, flatter style, a touch "
"slower for gravitas. Modest contrast against v2-presenter.",
)
V3_NATURAL = Delivery(
name="v3-natural",
model_id="eleven_v3",
voice_settings={"stability": 0.5, "use_speaker_boost": True},
supports_audio_tags=True,
note="Eleven v3, clean text (no tags) — v3's baseline is more dynamic.",
)
V3_CREATIVE = Delivery(
name="v3-creative",
model_id="eleven_v3",
voice_settings={"stability": 0.3, "use_speaker_boost": True},
supports_audio_tags=True,
note="Eleven v3, low stability, driven by inline audio tags. Alpha; per-take variance.",
)
DELIVERIES: dict[str, Delivery] = {
d.name: d
for d in (
BASELINE, V2_TUNED, V2_AGGRESSIVE, V2_PRESENTER, V2_NARRATOR,
V3_NATURAL, V3_CREATIVE,
)
}