braidio.conversation#
Conversational register: render an exchange as people talking to each other.
The second delivery register beside narration (braidio#1). A
ConversationCast maps role labels ("A"/"B") to contrasting
conversational ElevenLabs voices. render_dialogue() synthesizes the
whole exchange in one pass via braidio.tts.text_to_dialogue() (eleven_v3)
so prosody is conditioned across turns — the key to not sounding narrated.
render_turns_sequential() is the per-line baseline (each turn synthesized
alone, then concatenated) used for A/B comparison.
Casting note: use conversational-labelled voices, not narrator voices; loosen settings so v3 audio tags fire. The scripted exchange itself must carry the disfluency (backchannels, interruptions, fragments) — the model won’t invent it.
Functions
|
One-pass render of |
|
Per-line baseline: synthesize each turn alone (its role's voice) and concatenate with |
Classes
|
Role → voice mapping + model/settings for a conversational exchange. |
- class braidio.conversation.ConversationCast(roles=<factory>, model_id='eleven_v3', settings=<factory>)[source]#
Bases:
objectRole → voice mapping + model/settings for a conversational exchange.
Default cast: Jessica (playful/bright, F) + Chris (charming/ down-to-earth, M) — snappier than the “relaxed” voices.
stability=0.45is the research sweet spot for a lively but coherent read (never 1.0/Robust, which mutes v3 tags; ~0.1 is too unstable). See braidio#1 + the pacing doc.
- braidio.conversation.render_dialogue(turns, cast=ConversationCast(roles={'A': 'cgSgspJ2msm6clMCkdW9', 'B': 'iP95p4xoKVk53GoZ742B'}, model_id='eleven_v3', settings={'stability': 0.45}), *, api_key=None, out_path, output_format='mp3_44100_128', seed=None, cache=True, refresh=False, tighten_gaps_s=0.6, return_cache_status=False)[source]#
One-pass render of
turns([(role, text), …]) via Text-to-Dialogue.Cached by default (see
braidio.tts.text_to_dialogue()): an unchanged exchange renders instantly on re-run.refresh=Truere-rolls the take.api_keyis an optional per-request ElevenLabs key threaded tobraidio.tts.text_to_dialogue();None(default) keeps the$ELEVENLABS_API_KEYfallback.tighten_gaps_s(>0) applies the “R-tight” pass: ffmpeg trims only the over-long dead gaps (silences ≥ this many seconds) that make v3 dialogue feel draggy, while leaving natural short pauses. Set 0 to keep the raw take.return_cache_status: whenTrue, return(path, was_cached)wherewas_cachedisTrueiff the take came from the on-disk cache (no ElevenLabs call = $0 real spend) — what lets the graph path attribute real cost (braidio#8). DefaultFalsekeeps thePathreturn.
- braidio.conversation.render_turns_sequential(turns, cast=ConversationCast(roles={'A': 'cgSgspJ2msm6clMCkdW9', 'B': 'iP95p4xoKVk53GoZ742B'}, model_id='eleven_v3', settings={'stability': 0.45}), *, api_key=None, out_path, work_dir='data/tts/conversation', voice_settings=None, gap_s=0.25)[source]#
Per-line baseline: synthesize each turn alone (its role’s voice) and concatenate with
gap_sgaps. Prosody is NOT shared across turns — this is what tends to sound like alternating monologues (the thing to beat).api_keyis threaded tobraidio.tts.narrate();None(default) keeps the$ELEVENLABS_API_KEYfallback.- Return type: