How EpisodeProfile and SpeakerProfile Enable Multi-Speaker Podcast Generation in Open Notebook

The EpisodeProfile and SpeakerProfile Pydantic models provide the configuration foundation for multi-speaker podcast generation by separating episode-level LLM settings from voice-specific TTS configurations, supporting up to four distinct speakers per episode.

The open-notebook repository delivers a sophisticated backend for automated podcast creation, with multi-speaker support built on two central data models. These models abstract the complexity of coordinating multiple AI providers—handling everything from outline generation to voice synthesis—into simple, validated configuration objects. By isolating speaker personas from episode generation parameters, the system enables dynamic, personality-driven conversations between multiple AI voices.

EpisodeProfile: The Episode Configuration Container

The EpisodeProfile model in open_notebook/podcasts/models.py serves as the central configuration hub for an individual podcast episode. It stores references to the models used for content generation and links to the speaker configuration that defines who speaks during the episode.

Key capabilities include:

  • Model selection for content generation: Stores outline_llm and transcript_llm references that point to specific model records in the registry
  • Speaker configuration linkage: The speaker_config field references a SpeakerProfile by name, establishing which voices will participate in the episode
  • Token budget control: An optional max_tokens field overrides default limits for both outline and transcript generation stages
  • Configuration resolution: The resolve_outline_config() and resolve_transcript_config() methods (lines 36-44 and 86-89) translate stored model IDs into concrete provider/model/config tuples via _resolve_model_config()

SpeakerProfile: Defining Voices and Personalities

The SpeakerProfile model handles the multi-speaker aspect of podcast generation by defining up to four distinct voices, each with unique characteristics and TTS settings. Located in the same open_notebook/podcasts/models.py file, this model ensures that every speaker has a defined persona and voice configuration.

The model enforces strict validation (lines 71-74) to ensure the speakers list contains between one and four entries. Each speaker entry must include:

  • name: The display name used in the transcript
  • voice_id: The specific voice identifier for the TTS provider
  • backstory: Contextual background information to inform the LLM's generation style
  • personality: Behavioral traits that shape how the speaker interacts with others

The model supports both legacy TTS configuration via tts_provider and tts_model fields, and modern registry-based references through the voice_model field (lines 60-64). The resolve_tts_config() method (lines 93-100) loads the appropriate provider, model name, and credentials at runtime.

Creating a Multi-Speaker Configuration

To define the voices for a podcast, you instantiate a SpeakerProfile with detailed speaker definitions:

from open_notebook.podcasts.models import SpeakerProfile

profile = SpeakerProfile(
    name="tri-voice-news",
    description="Three distinct news anchors",
    voice_model="model:tts/openai/tts-1",
    speakers=[
        {
            "name": "Anchor 1",
            "voice_id": "en-US-Andy",
            "backstory": "Seasoned journalist",
            "personality": "Calm and authoritative",
        },
        {
            "name": "Anchor 2",
            "voice_id": "en-US-Jenny",
            "backstory": "Tech-savvy reporter",
            "personality": "Energetic and witty",
        },
        {
            "name": "Anchor 3",
            "voice_id": "en-US-Mike",
            "backstory": "Finance analyst",
            "personality": "Precise and analytical",
        },
    ],
)
await profile.save()

This configuration creates three distinct personas that the LLM will use to generate dialogue, while the TTS system maps each to a specific voice. The validation logic ensures that exactly three speakers—within the 1-4 supported range—are provided.

Configuring Episode Generation Parameters

Once speaker profiles exist, an EpisodeProfile links them to specific generation models and episode settings:

from open_notebook.podcasts.models import EpisodeProfile

episode = EpisodeProfile(
    name="weekly-tech-summary",
    description="A tech roundup with three hosts",
    speaker_config="tri-voice-news",
    outline_llm="model:openai/gpt-4o-mini",
    transcript_llm="model:openai/gpt-4o",
    default_briefing="Summarize the top tech news of the week.",
    num_segments=5,
    max_tokens=2000,
)
await episode.save()

The speaker_config field references the previously created SpeakerProfile by name, while outline_llm and transcript_llm point to model records that control the AI providers for text generation. The max_tokens parameter applies to both generation stages, providing a unified budget control mechanism.

Runtime Resolution and Service Integration

During podcast generation, the api/podcast_service.py (lines 9-12) orchestrates the workflow by resolving these abstract configurations into concrete provider settings:


# Inside the podcast creation service

episode = await EpisodeProfile.get_by_name("weekly-tech-summary")
speaker = await SpeakerProfile.get_by_name(episode.speaker_config)

provider, model_name, config = await episode.resolve_outline_config()

# → ("openai", "gpt-4o-mini", {"max_tokens": 2000, ...})

tts_provider, tts_model, tts_cfg = await speaker.resolve_tts_config()

# → ("openai", "tts-1", {...})

The resolve_outline_config() and resolve_transcript_config() methods translate the episode's model references into executable tuples containing provider names, model identifiers, and configuration dictionaries. Similarly, speaker.resolve_tts_config() prepares the voice synthesis parameters. These resolved configurations are then passed to the respective LLM and TTS backends to generate the multi-speaker audio content.

Summary

  • EpisodeProfile manages episode-level settings including LLM selection for outlines and transcripts, token limits, and references to speaker configurations.
  • SpeakerProfile defines 1-4 distinct voices with unique personalities, backstories, and TTS settings, validated to ensure proper multi-speaker constraints.
  • Configuration resolution methods translate registry model IDs into provider-specific tuples at runtime, abstracting implementation details from the configuration layer.
  • Service integration in api/podcast_service.py binds these models together to execute the full podcast generation workflow.
  • Both models support modern registry-based model references while maintaining backward compatibility with legacy TTS provider configurations.

Frequently Asked Questions

How many speakers can a single podcast episode support?

The SpeakerProfile model enforces a validation constraint (lines 71-74 in open_notebook/podcasts/models.py) that limits the speakers list to between one and four entries. This design choice balances multi-speaker dialogue complexity with TTS processing feasibility, ensuring the generation pipeline can handle the audio synthesis workload efficiently.

What is the difference between voice_model and the individual speaker voice_id?

The voice_model field in SpeakerProfile (lines 60-64) specifies a default TTS model registry reference for the entire profile, while individual voice_id values within each speaker entry identify specific voices within that provider (such as "en-US-Andy" or "en-US-Jenny"). This architecture allows you to set a global TTS provider while varying specific voice characteristics per speaker, or override the global model with per-speaker configurations if needed.

How does EpisodeProfile connect to SpeakerProfile?

The EpisodeProfile model contains a speaker_config string field that stores the name of a SpeakerProfile record. When the podcast service initiates generation, it loads the episode configuration, extracts the speaker_config value, and retrieves the corresponding SpeakerProfile to access the speaker definitions and TTS settings. This reference-based design enables multiple episodes to reuse the same speaker configurations without duplicating voice definitions.

Can I use different LLMs for outline generation and transcript generation?

Yes. The EpisodeProfile model provides separate outline_llm and transcript_llm fields, each referencing distinct model records in the registry. This allows you to use a smaller, faster model (such as GPT-4o-mini) for generating the structural outline, while employing a more capable model (such as GPT-4o) for the detailed transcript generation, optimizing both cost and quality for each stage of multi-speaker podcast generation.

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 →