| """Day 1 fixture pipeline.""" |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| from pathlib import Path |
|
|
| from .asset_library import ( |
| dialogue_duration_seconds, |
| resolve_broadcast_assets, |
| write_traces, |
| ) |
| from .audio_placeholder import render_placeholder_wav |
| from .mixer import mix_broadcast, mix_crude_broadcast |
| from .schema import Genre |
| from .tts import render_script_wav |
| from .writer import generate_script, get_writer, script_to_json_dict |
|
|
|
|
| def run_fixture_pipeline( |
| premise: str, |
| output_dir: Path = Path("outputs"), |
| mode: str = "placeholder", |
| writer_name: str = "fixture", |
| genre: Genre | str = Genre.WEIRD, |
| ) -> dict[str, str]: |
| writer = get_writer(writer_name) |
| |
| |
| retries = 0 if writer_name == "nemotron" else 1 |
| script = generate_script(writer, premise, genre=Genre(genre), retries=retries) |
| safe_stem = _safe_stem(script.title) |
| output_dir.mkdir(parents=True, exist_ok=True) |
| script_path = output_dir / f"{safe_stem}.json" |
| script_path.write_text(json.dumps(script_to_json_dict(script), indent=2), encoding="utf-8") |
| if mode == "placeholder": |
| audio_path = output_dir / f"{safe_stem}.placeholder.wav" |
| render_placeholder_wav(script, audio_path) |
| return { |
| "script": str(script_path), |
| "audio": str(audio_path), |
| "mode": mode, |
| "writer": writer.name, |
| } |
| if mode in ("crude", "production"): |
| dialogue_path = output_dir / f"{safe_stem}.dialogue.wav" |
| render_script_wav(script, dialogue_path) |
|
|
| |
| |
| resolved = resolve_broadcast_assets( |
| script, dialogue_duration_seconds(dialogue_path) |
| ) |
| traces_path = output_dir / f"{safe_stem}.traces.jsonl" |
| write_traces(resolved.traces, traces_path) |
|
|
| if mode == "crude": |
| audio_path = output_dir / f"{safe_stem}.crude.wav" |
| mix_crude_broadcast( |
| dialogue_path, |
| audio_path, |
| sfx_layers=resolved.sfx_layers, |
| bed=resolved.bed, |
| opening_sting=resolved.opening_sting, |
| closing_sting=resolved.closing_sting, |
| ) |
| else: |
| audio_path = mix_broadcast( |
| dialogue_path, |
| output_dir / f"{safe_stem}.mp3", |
| sfx_layers=resolved.sfx_layers, |
| bed=resolved.bed, |
| opening_sting=resolved.opening_sting, |
| closing_sting=resolved.closing_sting, |
| ) |
| return { |
| "script": str(script_path), |
| "dialogue": str(dialogue_path), |
| "audio": str(audio_path), |
| "traces": str(traces_path), |
| "asset_source": resolved.source, |
| "mode": mode, |
| "writer": writer.name, |
| } |
| raise ValueError(f"unknown pipeline mode: {mode}") |
|
|
|
|
| def main() -> None: |
| parser = argparse.ArgumentParser(description="Run the Midnight Static fixture pipeline.") |
| parser.add_argument("premise", help="Short user premise to turn into a placeholder broadcast.") |
| parser.add_argument("--output-dir", default="outputs", help="Directory for generated artifacts.") |
| parser.add_argument( |
| "--mode", |
| choices=["placeholder", "crude", "production"], |
| default="placeholder", |
| help="placeholder tones, crude Kokoro mix, or the mastered production chain.", |
| ) |
| parser.add_argument( |
| "--writer", |
| default="fixture", |
| help="Writer implementation name. Currently: fixture.", |
| ) |
| parser.add_argument( |
| "--genre", |
| choices=[genre.value for genre in Genre], |
| default=Genre.WEIRD.value, |
| help="Radio-drama genre/station to tune before writing.", |
| ) |
| args = parser.parse_args() |
| result = run_fixture_pipeline( |
| args.premise, |
| Path(args.output_dir), |
| mode=args.mode, |
| writer_name=args.writer, |
| genre=args.genre, |
| ) |
| print(json.dumps(result, indent=2)) |
|
|
|
|
| def _safe_stem(value: str) -> str: |
| stem = "".join(ch.lower() if ch.isalnum() else "-" for ch in value).strip("-") |
| while "--" in stem: |
| stem = stem.replace("--", "-") |
| return stem[:80] or "broadcast" |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|