from __future__ import annotations import json import logging from pathlib import Path from umbraaudio.analysis.voice_analysis import VoiceAnalysisEngine from umbraaudio.config import load_config logger = logging.getLogger(__name__) def run_voice_analysis(project_dir: Path | None = None) -> None: """Compute the objective voice-analysis report for a project.""" project_dir = project_dir or Path(".") cfg = load_config(project_dir) speakers_path = cfg.data_dir / "speakers.json" speaker_names: set[str] = set() if speakers_path.exists(): with open(speakers_path) as f: speaker_names = {s["primary_name"] for s in json.load(f).get("speakers", [])} engine = VoiceAnalysisEngine( refs_dir=cfg.data_dir / "voices", output_dir=cfg.data_dir / "analysis", target_sample_rate=cfg.tts.sample_rate, speaker_names=speaker_names, ) report = engine.analyze() summary = report["summary"] print( f"Analyzed {summary['total']} voices: " f"{summary['passed']} passed, {summary['failed']} failed, " f"{summary['near_duplicate_count']} near-duplicate pairs" ) if report["near_duplicates"]: print("Near-duplicate pairs:") for pair in report["near_duplicates"]: print(f" {pair['a']} <-> {pair['b']} ({pair['similarity']})") if report["errors"]: print("Errors:") for name, err in report["errors"].items(): print(f" {name}: {err}") print(f"Report written to {engine.report_path}") if __name__ == "__main__": import sys logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s") project = Path(sys.argv[1]) if len(sys.argv) > 1 else None run_voice_analysis(project)