Files
UmbraAudio/scripts/run_voice_analysis.py
B.D. Murphy c86e323d7a Initial commit: UmbraAudio audiobook generation program
Quality-first multi-pass audiobook generation from English manuscripts.

Includes:
- umbraaudio/ core package (pipeline, config, voices, web review UI)
- scripts/ CLI utilities + model download script
- tts_server/ remote TTS server
- specs/ design docs, tests/, pyproject.toml + uv.lock
- Qwen3-TTS git submodule (pinned 022e286) with local demo.py UI patch
  saved at scripts/qwen3_tts_demo_umbra_patch.patch
- .env with runtime config/secrets

Excluded (see .gitignore): models/ (downloaded via scripts/download_models.sh),
output/, logs/, .venv, .umbra runtime data, and book projects
(DealHunterShip_*), which are committed separately.
2026-08-30 07:58:24 -07:00

54 lines
1.7 KiB
Python

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)