from dataclasses import asdict, dataclass, field from pathlib import Path from typing import Any, Dict, List, Optional from backend.synthesis_catalog import LOCAL_BACKEND, OMNIVOICE_MODEL 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 = "auto" model: str = OMNIVOICE_MODEL backend: str = LOCAL_BACKEND narrator_id: Optional[str] = None sample_path: Optional[str] = None reference_text: Optional[str] = None design_prompt: Optional[str] = None speaker: Optional[str] = None language: Optional[str] = None apply_text_normalization: bool = False @classmethod def from_dict(cls, data: JsonDict) -> "VoiceConfig": return cls( mode=data.get("mode", "auto"), model=data.get("model", OMNIVOICE_MODEL), backend=data.get("backend", LOCAL_BACKEND), 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"), speaker=data.get("speaker"), language=data.get("language"), apply_text_normalization=bool( data.get("applyTextNormalization", data.get("apply_text_normalization", False)) ), ) def to_dict(self) -> JsonDict: return { "mode": self.mode, "model": self.model, "backend": self.backend, "narratorId": self.narrator_id, "samplePath": self.sample_path, "referenceText": self.reference_text, "designPrompt": self.design_prompt, "speaker": self.speaker, "language": self.language, "applyTextNormalization": self.apply_text_normalization, } @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)