from dataclasses import asdict, dataclass, field from pathlib import Path from typing import Any, Dict, List, Optional JsonDict = Dict[str, Any] @dataclass class Chapter: id: str label: str title: str text: str chars: int est_minutes: int included: bool = True start_seconds: int = 0 def to_dict(self) -> JsonDict: data = asdict(self) data["n"] = data["label"] return data @dataclass class SessionRecord: session_id: str root: Path created_at: float touched_at: float @dataclass class VoiceConfig: mode: str narrator_id: Optional[str] = None sample_path: Optional[str] = None reference_text: Optional[str] = None design_prompt: Optional[str] = None @classmethod def from_dict(cls, data: JsonDict) -> "VoiceConfig": return cls( mode=data.get("mode", "auto"), narrator_id=data.get("narratorId") or data.get("narrator_id"), sample_path=data.get("samplePath") or data.get("sample_path"), reference_text=data.get("referenceText") or data.get("reference_text"), design_prompt=data.get("designPrompt") or data.get("design_prompt"), ) @dataclass class RenderArtifact: path: Path duration_seconds: int chapter_id: str @dataclass class RenderJob: session_id: str status: str = "idle" current_chapter_id: Optional[str] = None outputs: List[RenderArtifact] = field(default_factory=list)