from __future__ import annotations import json import os import shutil import uuid from dataclasses import dataclass from pathlib import Path from typing import Any BACKEND_DIR = Path(__file__).resolve().parent DEFAULT_DATA_ROOT = BACKEND_DIR / "data" @dataclass(frozen=True) class DataPaths: data_root: Path playground_dir: Path playground_ref_dir: Path playground_metadata_file: Path playground_speakers_file: Path audio_root: Path video_root: Path post_root: Path def get_data_paths() -> DataPaths: configured_root = os.getenv("OMNIVOICE_DATA_ROOT", "").strip() data_root = Path(configured_root).resolve() if configured_root else DEFAULT_DATA_ROOT paths = DataPaths( data_root=data_root, playground_dir=data_root / "playground", playground_ref_dir=data_root / "playground" / "ref", playground_metadata_file=data_root / "playground" / "metadata.json", playground_speakers_file=data_root / "playground" / "speakers.json", audio_root=data_root / "audio", video_root=data_root / "video", post_root=data_root / "post", ) ensure_paths(paths) return paths def ensure_paths(paths: DataPaths) -> None: paths.playground_ref_dir.mkdir(parents=True, exist_ok=True) paths.audio_root.mkdir(parents=True, exist_ok=True) paths.video_root.mkdir(parents=True, exist_ok=True) paths.post_root.mkdir(parents=True, exist_ok=True) def make_id(prefix: str) -> str: return f"{prefix}_{uuid.uuid4().hex[:10]}" def read_json_file(path: Path, default: Any) -> Any: if not path.exists(): return default try: return json.loads(path.read_text(encoding="utf-8")) except Exception: return default def write_json_file(path: Path, payload: Any) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text( json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8", ) def reset_directory(path: Path) -> None: if path.exists(): shutil.rmtree(path) path.mkdir(parents=True, exist_ok=True)