Updated Jun 21, 2026 pipeline

Step 3 — Narration

Status: ✅ Live (Chapter XIII)

Unlocks when: Episode is segmented

Advances to: audio_ready (on explicit episode approval, after all scenes approved)

Gemini TTS (gemini-3.1-flash-tts-preview) generates one .wav per scene. The flow is sequential — one scene at a time. Each scene must be listened to and individually approved before the next scene unlocks.

How It Works

  1. Scene 1 is active — "Generate" button visible. Remaining scenes are locked.
  2. Click "Generate" → background task → audio player appears when done
  3. Listen → click "Approve" to mark scene done and unlock the next scene
  4. Or click "Regenerate" with a different voice — old file is archived with voice name and timestamp
  5. Once all scenes are approved → "Approve Narration" button appears → episode advances to audio_ready

Per-Scene Controls

  • Voice — dropdown of 30 Gemini TTS voices. Defaults to project voice. Per-scene override saved to DB (scene_voice). Shows last-used voice after generation.
  • Narrator Brief — editable performance direction (e.g. "slow and deliberate, weight on every word, building dread"). Used as Director's Notes in the TTS prompt. Editable inline with AJAX save — tweak and regenerate without leaving Step 3.
  • Audio player — appears once narration is generated. Standard browser <audio> element.

Voice Archive

When regenerating, the existing WAV is renamed to scene_NN_narration_VOICE_YYYYMMDD_HHMMSS.wav before the new file is written. All previous takes are preserved for comparison.

Project Default Voice

Set on the Project detail page. All new scenes default to this voice. Change it any time — existing scene voices are unaffected.

TTS Prompt Structure

# AUDIO PROFILE: Audiobook Narrator
## DIRECTOR'S NOTES
Style: {narrator_brief}
Read as a dramatic audiobook narrator for a dark sci-fi horror series.
No character voices — single narrator throughout. Natural pauses at paragraph breaks.

## TRANSCRIPT
{scene_content}

Model: gemini-3.1-flash-tts-preview (TTS_MODEL_NAME env var)

Output format: WAV (PCM 24kHz 16-bit mono, stdlib wave)

File path: media/studio/{series_slug}/{book_slug}/chapters/{n}/scenes/scene_NN_narration.wav

Archived takes: media/studio/.../scenes/scene_NN_narration_VOICE_TIMESTAMP.wav

Service

studio/tts.pygenerate_narration(scene_content, narrator_brief, voice_profile, output_path, api_key, model_name) — pure Python, zero Django imports. 3 retries on API failure (Google recommends this for occasional 500s from the TTS model).

studio/service.pyrun_narration(episode_id, scene_id, voice_profile) — background thread, StudioTask polling. approve_narration(episode_id) — advances status. regenerate_scene_narration(episode_id, scene_id, voice_profile) — archives existing file then re-runs.

New URLs (Chapter XIII):

POST /studio/project/<slug>/episode/<n>/narrate-scene/<scene_id>/  — generate narration
POST /studio/project/<slug>/episode/<n>/approve-narration/          — approve episode
POST /studio/scene/<scene_id>/approve-scene-narration/              — approve one scene
POST /studio/scene/<scene_id>/regenerate-narration/                 — regenerate one scene
GET  /studio/scene/<scene_id>/serve-narration/                      — stream WAV to browser

Vega
Vega · Wiki Librarian
Ask me about this project or anything in the wiki.