Multi-speaker Podcast Generation with Open-Notebook: Implementation Guide

Open-Notebook implements a fully-featured, multi-speaker podcast generation pipeline that stitches together domain models, asynchronous job queues, and REST API services.

The lfnovo/open-notebook repository provides a production-ready architecture for generating conversational audio content with multiple speakers. The system combines persistent entity definitions in the domain layer with crash-resilient execution via the surreal-commands framework to handle complex podcast synthesis workflows.

Domain Models for Multi-Speaker Podcasts

The domain layer in open_notebook/podcasts/models.py defines three core entities that encapsulate podcast configuration, speaker definitions, and episode state.

EpisodeProfile Configuration

The EpisodeProfile class manages high-level parameters for episode generation. It specifies which language models handle distinct phases of the creation process and defines structural constraints.

Key fields include:

  • outline_llm: Model identifier for generating the conversation structure
  • transcript_llm: Model identifier for creating dialogue content
  • speaker_config: Reference to voice and personality definitions
  • default_briefing: Context provided to all episodes using this profile
  • num_segments: Target number of conversational segments to generate

SpeakerProfile Definition

The SpeakerProfile class stores voice synthesis and personality data for 1-4 speakers. It integrates with TTS providers through the voice_model field while maintaining individual speaker characteristics.

Each speaker dictionary contains:

  • name: Display identifier for the participant
  • voice_id: TTS provider-specific voice reference
  • backstory: Character history informing dialogue context
  • personality: Behavioral traits affecting speech patterns

PodcastEpisode Storage

The PodcastEpisode model persists generated content and tracks execution state. It maintains a reference to the surreal-commands job via the command field, enabling asynchronous status monitoring and crash recovery.

Stored content includes:

  • briefing: Input context provided for the episode
  • outline: Structured conversation flow generated by the outline LLM
  • transcript: Generated dialogue text from the transcript LLM
  • audio_file: Path to the final synthesized audio file
  • content: Processed episode metadata and references

Asynchronous Job Execution

The system uses surreal-commands for crash-resilient, asynchronous processing of long-running podcast generation tasks.

The generate_podcast Command

Located in commands/podcast_commands.py, the generate_podcast command encapsulates the complete generation workflow. It orchestrates the transition from outline to audio while maintaining persistent state.

This command coordinates:

  • Outline generation using the configured outline_llm
  • Multi-speaker dialogue creation via transcript_llm
  • Audio synthesis across multiple voice models defined in SpeakerProfile
  • Progress persistence through the PodcastEpisode.command reference

Crash-Resilient Processing

By delegating execution to the surreal-commands queue, the system ensures that podcast generation survives process restarts. The PodcastEpisode.command field links the domain entity to the job queue state, allowing clients to poll for completion status and enabling automatic retry of failed operations.

API Service Layer

The PodcastService class in api/podcast_service.py provides the HTTP façade for client interactions with the podcast generation system.

This service exposes endpoints for:

  • Triggering new generate_podcast jobs with validated configuration
  • Verifying EpisodeProfile and SpeakerProfile schema compliance
  • Polling generation status via the surreal-commands integration
  • Retrieving completed episodes with audio_file URLs and metadata

Model Registry Integration

Both EpisodeProfile and SpeakerProfile expose configuration resolution methods that delegate to the centralized model registry at open_notebook.ai.models.Model.

Configuration Resolution Methods

The domain models implement three helper methods for dynamic provider configuration:

  • resolve_outline_config(): Returns LLM parameters for outline generation
  • resolve_transcript_config(): Returns LLM parameters for dialogue generation
  • resolve_tts_config(): Returns TTS model parameters for audio synthesis

These methods abstract provider-specific implementation details, allowing the system to support multiple LLM and TTS backends without modifying the core generation logic.

Summary

  • Domain models in open_notebook/podcasts/models.py define EpisodeProfile, SpeakerProfile, and PodcastEpisode for persistent configuration and state management across the generation lifecycle.
  • Asynchronous execution via commands/podcast_commands.py leverages the surreal-commands framework for crash-resilient job processing and recovery.
  • API abstraction provided by api/podcast_service.py enables HTTP-based interaction with validation, job triggering, and status polling capabilities.
  • Model registry delegation through resolve_outline_config(), resolve_transcript_config(), and resolve_tts_config() methods enables flexible multi-provider support.

Frequently Asked Questions

How does Open-Notebook handle multiple speakers in podcast generation?

Open-Notebook supports 1-4 speakers through the SpeakerProfile model, which stores individual voice_id, backstory, and personality traits for each participant. The generate_podcast command in commands/podcast_commands.py coordinates multi-voice synthesis by iterating through the speakers list and invoking the TTS provider specified in voice_model for each distinct voice.

What happens if a podcast generation job fails mid-process?

The system uses surreal-commands for durable job queue management. The PodcastEpisode model maintains a command reference that links the domain entity to the job queue state, enabling automatic crash recovery and status polling. Failed jobs can be retried without losing the episode configuration or partial progress stored in the outline and transcript fields.

How do I configure different LLM providers for outline and transcript generation?

The EpisodeProfile model exposes separate outline_llm and transcript_llm fields, allowing distinct model selection for each generation phase. The resolve_outline_config() and resolve_transcript_config() methods delegate to open_notebook.ai.models.Model to fetch provider-specific parameters, enabling flexible backend selection without modifying the core pipeline logic.

Where does Open-Notebook store generated podcast audio files?

The PodcastEpisode model persists the audio_file path, which references the final synthesized audio location. The actual storage mechanism depends on the TTS provider configuration resolved through resolve_tts_config(), while the PodcastService in api/podcast_service.py handles URL generation and secure retrieval for client applications.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →