Models
src.xil_pipeline.models
Pydantic data models for the podcast production pipeline.
Defines validated, typed structures for script parsing output, cast configuration, and production dialogue entries. These models replace untyped dictionaries with field-level validation and type annotations that render as rich API documentation via mkdocstrings.
TYPE_DEFAULTS
module-attribute
TYPE_DEFAULTS: dict[str, dict] = {'podcast': {'gap_ms': 600, 'stability': None}, 'audiobook': {'gap_ms': 400, 'stability': 0.75}, 'drama': {'gap_ms': 800, 'stability': None}, 'special': {'gap_ms': 600, 'stability': None}}
ProjectConfig
Bases: BaseModel
Typed view of project.json.
All fields are optional with sensible defaults so that a minimal
{"show": "My Show"} project.json validates without change.
Attributes:
-
show(str) –Human-readable show title.
-
type(Literal['podcast', 'audiobook', 'drama', 'special']) –Content type —
"podcast"(default),"audiobook","drama", or"special". Drives section maps, gap defaults, andxil-initsample templates. -
season(int | None) –Season number, or
None. -
season_title(str | None) –Season arc title (e.g.
"The Holiday Shift"). -
tag_format(str | None) –Custom episode tag format string (e.g.
"V{volume:02d}C{chapter:02d}"for audiobooks).Noneuses the standardS01E01/E01derivation.
Source code in src/xil_pipeline/models.py
ScriptEntry
Bases: BaseModel
A single parsed entry from a production script.
Each entry represents one line or block from the markdown script, classified into one of four types: dialogue, direction, section_header, or scene_header.
Attributes:
-
seq(int) –Sequence number, 1-based and unique within a script.
-
type(Literal['dialogue', 'direction', 'section_header', 'scene_header']) –Entry classification determining how the line is processed.
-
section(str | None) –Current section slug (e.g.,
"cold-open","act1"). -
scene(str | None) –Current scene slug (e.g.,
"scene-1") orNone. -
speaker(str | None) –Normalized speaker key for dialogue entries (e.g.,
"adam"). -
direction(str | None) –Parenthetical acting direction for dialogue lines.
-
text(str) –The spoken text, header text, or stage direction content.
-
direction_type(Literal['SFX', 'MUSIC', 'AMBIENCE', 'BEAT', 'VINTAGE FILTER'] | None) –Subtype for direction entries indicating sound category.
Source code in src/xil_pipeline/models.py
type
class-attribute
instance-attribute
type: Literal['dialogue', 'direction', 'section_header', 'scene_header'] = Field(..., description='Entry classification')
section
class-attribute
instance-attribute
scene
class-attribute
instance-attribute
speaker
class-attribute
instance-attribute
direction
class-attribute
instance-attribute
ScriptStats
Bases: BaseModel
Aggregate statistics for a parsed production script.
Attributes:
-
total_entries(int) –Total number of parsed entries.
-
dialogue_lines(int) –Count of dialogue-type entries.
-
direction_lines(int) –Count of direction-type entries.
-
characters_for_tts(int) –Total character count across all dialogue text.
-
speakers(list[str]) –Sorted list of unique speaker keys found in the script.
-
sections(list[str]) –Sorted list of unique section slugs found in the script.
Source code in src/xil_pipeline/models.py
total_entries
class-attribute
instance-attribute
dialogue_lines
class-attribute
instance-attribute
direction_lines
class-attribute
instance-attribute
characters_for_tts
class-attribute
instance-attribute
speakers
class-attribute
instance-attribute
ParsedScript
Bases: BaseModel
Complete output of the script parsing stage.
Produced by parse_script() in XILP001, consumed by
load_production() in XILP002.
Attributes:
-
show(str) –Show title (e.g.,
"nightowls"). -
season(int | None) –Season number, or
Noneif not declared in the script header. -
episode(int) –Episode number.
-
title(str) –Episode title.
-
season_title(str | None) –Season arc title extracted from
Arc: "…"in the script header (e.g."The Holiday Shift").Nonewhen the header contains no arc declaration. -
source_file(str) –Basename of the source markdown file.
-
entries(list[ScriptEntry]) –Ordered list of parsed script entries.
-
stats(ScriptStats) –Aggregate statistics for the parsed script.
Source code in src/xil_pipeline/models.py
season
class-attribute
instance-attribute
season_title
class-attribute
instance-attribute
season_title: str | None = Field(default=None, description='Season arc title from \'Arc: "…"\' in the script header')
source_file
class-attribute
instance-attribute
entries
class-attribute
instance-attribute
stats
class-attribute
instance-attribute
CastMember
Bases: BaseModel
Configuration for a single cast member's voice and audio settings.
Maps a character to their ElevenLabs voice and stereo positioning.
Attributes:
-
full_name(str) –Character's display name (e.g.,
"Adam Santos"). -
voice_id(str) –ElevenLabs voice identifier, or
"TBD"if unassigned. -
pan(float) –Stereo pan position from -1.0 (full left) to 1.0 (full right).
-
filter(str | bool | None) –Audio filter chain.
False/None= none;True/"phone"= phone filter;"vintage"= vintage filter;"vintage,phone"= both filters applied in listed order. -
role(str) –Character role description (e.g.,
"Host/Narrator").
Source code in src/xil_pipeline/models.py
full_name
class-attribute
instance-attribute
voice_id
class-attribute
instance-attribute
voice_id: str = Field(..., description="ElevenLabs voice ID, 'TBD' if unassigned, or '' for non-ElevenLabs backends")
pan
class-attribute
instance-attribute
filter
class-attribute
instance-attribute
filter: str | bool | None = Field(..., description='Audio filter chain (false/phone/vintage/vintage,phone)')
role
class-attribute
instance-attribute
stability
class-attribute
instance-attribute
stability: float | None = Field(default=None, ge=0.0, le=1.0, description='Voice stability (0=expressive, 1=monotone); None uses voice default')
similarity_boost
class-attribute
instance-attribute
similarity_boost: float | None = Field(default=None, ge=0.0, le=1.0, description='Adherence to original voice (0=loose, 1=strict); None uses voice default')
style
class-attribute
instance-attribute
style: float | None = Field(default=None, ge=0.0, le=1.0, description='Style exaggeration of the original speaker; None uses voice default')
use_speaker_boost
class-attribute
instance-attribute
use_speaker_boost: bool | None = Field(default=None, description='Boost similarity to original speaker (higher latency); None uses voice default')
PreambleSegment
Bases: BaseModel
One text slice of a multi-part preamble or postamble.
Attributes:
-
text(str) –Spoken text (may use {season_title}, {episode}, {title} placeholders).
-
shared_key(str | None) –Retained for backward compatibility with existing cast JSONs. No longer used at generation time — all segments are joined and sent as a single TTS call to produce seamless prosody across the whole block.
Source code in src/xil_pipeline/models.py
text
class-attribute
instance-attribute
Preamble
Bases: BaseModel
Broadcast introduction prepended to every episode.
Attributes:
-
text(str | None) –Single-string intro text (legacy). Mutually exclusive with
segments. -
segments(list[PreambleSegment] | None) –Ordered list of cacheable text segments. Stock segments carry a
shared_keyso they are generated once and reused; the variable episode-identifier segment hasshared_key=None. -
speaker(str) –Cast key for the reader (e.g. "tina").
-
speed(float | None) –TTS speaking rate passed to ElevenLabs VoiceSettings (0.7–1.2, default 1.0). Values below 1.0 slow the reader down.
Source code in src/xil_pipeline/models.py
text
class-attribute
instance-attribute
text: str | None = Field(default=None, description='Intro text (may use {season_title}, {episode}, {title}); legacy single-string form')
segments
class-attribute
instance-attribute
segments: list[PreambleSegment] | None = Field(default=None, description="Ordered cacheable segments; preferred over 'text' for new episodes")
speaker
class-attribute
instance-attribute
CastConfiguration
Bases: BaseModel
Complete cast configuration for a production episode.
Loaded from the cast config JSON and used by load_production()
to map speaker keys to voice and audio settings.
Attributes:
-
show(str) –Show title (e.g.,
"nightowls"). -
season(int | None) –Season number, or
Noneif not set in the cast file. -
episode(int | None) –Episode number.
-
title(str | None) –Episode title (optional, not used during production).
-
season_title(str | None) –Season subtitle/arc title (e.g.,
"The Letters"). -
preamble(Preamble | None) –Broadcast intro configuration, or
Noneif not configured. -
cast(dict[str, CastMember]) –Mapping of speaker keys to their voice configurations.
Source code in src/xil_pipeline/models.py
season
class-attribute
instance-attribute
episode
class-attribute
instance-attribute
tag_override
class-attribute
instance-attribute
tag_override: str | None = Field(default=None, description='Raw tag for non-episodic content (e.g. V01C03, D01) — overrides season/episode derivation')
title
class-attribute
instance-attribute
season_title
class-attribute
instance-attribute
artist
class-attribute
instance-attribute
preamble
class-attribute
instance-attribute
postamble
class-attribute
instance-attribute
cast
class-attribute
instance-attribute
VoiceConfig
Bases: BaseModel
Simplified voice configuration used during voice generation.
Built from CastMember by load_production(), carrying only
the fields needed for TTS generation and audio assembly.
Attributes:
-
id(str) –ElevenLabs voice identifier.
-
pan(float) –Stereo pan position from -1.0 (full left) to 1.0 (full right).
-
filter(str | bool | None) –Audio filter chain (see
CastMember.filter).
Source code in src/xil_pipeline/models.py
pan
class-attribute
instance-attribute
DialogueEntry
Bases: BaseModel
A single dialogue line prepared for voice generation.
Produced by load_production() from parsed script entries,
enriched with the stem filename for audio output.
Attributes:
-
speaker(str) –Normalized speaker key (e.g.,
"adam"). -
text(str) –Spoken dialogue text to synthesize.
-
stem_name(str) –Output filename stem (e.g.,
"003_cold-open_adam"). -
seq(int) –Sequence number from the parsed script.
-
direction(str | None) –Acting direction for the line, if any.
Source code in src/xil_pipeline/models.py
SfxEntry
Bases: BaseModel
A single sound effect mapping from script direction to API parameters.
Maps a direction entry's text (e.g., "SFX: PHONE BUZZING") to the
ElevenLabs Sound Effects API parameters needed to generate it, or marks
it as silence (for BEAT entries).
Note: per-effect volume is always volume_percentage, not the prefixed
form (ambience_volume_percentage etc.) — those belong in defaults only.
Attributes:
-
prompt(str | None) –Natural-language description for the ElevenLabs SFX API.
Nonefor silence entries. -
type(Literal['sfx', 'silence']) –Whether this is an API-generated sound effect or local silence.
-
duration_seconds(float) –Length of the generated audio (0.5–30.0s).
-
prompt_influence(float | None) –How closely the output follows the prompt (0.0–1.0).
Noneto use the config-level default. -
loop(bool) –Whether the effect should be loopable (useful for ambience).
Source code in src/xil_pipeline/models.py
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 | |
prompt
class-attribute
instance-attribute
type
class-attribute
instance-attribute
type: Literal['sfx', 'silence'] = Field(default='sfx', description='Effect type: API-generated or local silence')
duration_seconds
class-attribute
instance-attribute
duration_seconds: float = Field(default=5.0, ge=0.0, description='Audio duration in seconds (0.0 for stop markers)')
prompt_influence
class-attribute
instance-attribute
prompt_influence: float | None = Field(default=None, ge=0.0, le=1.0, description='Prompt adherence (0.0–1.0), None for config default')
loop
class-attribute
instance-attribute
source
class-attribute
instance-attribute
source: str | None = Field(default=None, description='Path to a pre-existing audio file (bypasses API generation)')
volume_percentage
class-attribute
instance-attribute
volume_percentage: float | None = Field(default=None, ge=0.0, le=200.0, description='Playback volume as percentage (100=unity); None uses category default')
ramp_in_seconds
class-attribute
instance-attribute
ramp_in_seconds: float | None = Field(default=None, ge=0.0, le=30.0, description='Fade-in duration in seconds; None uses category default')
SfxConfiguration
Bases: BaseModel
Sound effects configuration for a production episode.
Analogous to :class:CastConfiguration for voices. Maps parsed
direction entry text to ElevenLabs Sound Effects API parameters.
Attributes:
-
show(str) –Show title (e.g.,
"nightowls"). -
season(int | None) –Season number, or
Noneif not declared. -
episode(int | None) –Episode number.
-
defaults(dict) –Shared default settings (e.g.,
prompt_influence). -
effects(dict[str, SfxEntry]) –Mapping of direction text to SFX entry configurations.
Source code in src/xil_pipeline/models.py
season
class-attribute
instance-attribute
episode
class-attribute
instance-attribute
tag_override
class-attribute
instance-attribute
tag_override: str | None = Field(default=None, description='Raw tag for non-episodic content (e.g. V01C03, D01) — overrides season/episode derivation')
defaults
class-attribute
instance-attribute
effects
class-attribute
instance-attribute
get_workspace_root
Return the active workspace root.
Resolves in priority order:
1. XIL_PROJECTROOT environment variable (absolute path).
2. Current working directory (existing behaviour).
Source code in src/xil_pipeline/models.py
show_slug
Convert a show title to a filesystem-safe slug.
Lowercases the string and strips all non-alphanumeric characters.
Parameters:
-
show_name(str) –Human-readable show title (e.g.,
"nightowls").
Returns:
-
str–Compact slug like
"nightowls"or"mypodcast".
Source code in src/xil_pipeline/models.py
derive_paths_legacy
Legacy workspace layout paths (pre-0.1.8) — used by the migration tool.
Parameters:
Returns:
Source code in src/xil_pipeline/models.py
derive_paths
Derive all standard pipeline file paths from a show slug and episode tag.
Auto-detects workspace layout: returns legacy paths when the cast config
exists at the legacy root location (pre-0.1.8 workspaces), and normalized
paths otherwise (new workspaces or post-migration). Run xil migrate-workspace
to move an existing workspace to the normalized layout.
Parameters:
Returns:
Source code in src/xil_pipeline/models.py
load_project_config
Load and validate project.json, returning a :class:ProjectConfig.
Parameters:
-
project_path(str, default:'project.json') –Path to the project config file.
Returns:
-
ProjectConfig–class:
ProjectConfigwith all fields populated (defaults where absent).
Source code in src/xil_pipeline/models.py
resolve_project_type
Return the content type from project.json, defaulting to "podcast".
Parameters:
-
project_path(str, default:'project.json') –Path to the project config file.
Returns:
-
str–One of
"podcast","audiobook","drama", or"special".
Source code in src/xil_pipeline/models.py
resolve_slug
Resolve the show slug from CLI arg, project.json, or the default.
Resolution order:
1. Explicit show_arg (passed through :func:show_slug).
2. project.json "show" field (if the file exists).
3. :data:DEFAULT_SLUG ("sample").
Parameters:
-
show_arg(str | None, default:None) –Value of
--showCLI flag, orNone. -
project_path(str, default:'project.json') –Path to the project config file.
Returns:
-
str–Filesystem-safe show slug.
Source code in src/xil_pipeline/models.py
resolve_season_title
resolve_season_title(season_title_arg: str | None = None, project_path: str = 'project.json') -> str | None
Resolve the season/arc title from an explicit value or project.json.
Resolution order:
1. Explicit season_title_arg (e.g. extracted from the script header Arc: token).
2. project.json "season_title" field (if the file exists and the key is present).
3. None — no season title is available.
Parameters:
-
season_title_arg(str | None, default:None) –Season title already known (e.g. from the script header), or
None. -
project_path(str, default:'project.json') –Path to the project config file.
Returns:
-
str | None–Season title string, or
Nonewhen not available from any source.
Source code in src/xil_pipeline/models.py
resolve_season
Resolve the season number from an explicit value or project.json.
Resolution order:
1. Explicit season_arg (e.g. parsed from the script header Season N: token).
2. project.json "season" field (if the file exists and the key is present).
3. None — no season number is available.
Parameters:
-
season_arg(int | None, default:None) –Season number already known (e.g. from the script header), or
None. -
project_path(str, default:'project.json') –Path to the project config file.
Returns:
-
int | None–Season number as an integer, or
Nonewhen not available from any source.
Source code in src/xil_pipeline/models.py
episode_tag
Format season/episode as a compact tag like S01E01 or E01.
Parameters:
Returns:
-
str–"S01E01"when season is set,"E01"otherwise.