#!/usr/bin/env python3 """Preflight checks for the live Urdu S2S runtime.""" from __future__ import annotations import argparse import importlib.util import json import os import sys from pathlib import Path from typing import Callable, Mapping ROOT = Path(__file__).resolve().parents[1] DEFAULT_AUDIO = ROOT / "data/raw/benchmarks/gemini_urdu_s2s_v1/audio/bench_001.wav" DEFAULT_VOICE_ANCHOR = ROOT / "data/processed/voice_anchors/chatterbox_praxy_v1/bench_025.wav" def default_module_available(name: str) -> bool: return importlib.util.find_spec(name) is not None def check_runtime( *, audio_path: Path, voice_prompt_audio_path: Path, require_openai_key: bool, module_available: Callable[[str], bool] = default_module_available, env: Mapping[str, str] = os.environ, python_version: tuple[int, int, int] = sys.version_info[:3], ) -> dict[str, object]: dependencies = { "faster_whisper": "present" if module_available("faster_whisper") else "missing", "chatterbox": "present" if module_available("chatterbox") else "missing", "soundfile": "present" if module_available("soundfile") else "missing", } paths = { "audio_path": "present" if audio_path.exists() else "missing", "voice_prompt_audio_path": "present" if voice_prompt_audio_path.exists() else "missing", } secrets = { "OPENAI_API_KEY": "present" if env.get("OPENAI_API_KEY") else "missing", } warnings: list[str] = [] if python_version >= (3, 13, 0): warnings.append( f"Python {python_version[0]}.{python_version[1]} detected; " "ML audio packages are usually safer on Python 3.10-3.12." ) checks = list(dependencies.values()) + list(paths.values()) if require_openai_key: checks.extend(secrets.values()) return { "ok": all(value == "present" for value in checks), "python": ".".join(str(part) for part in python_version), "dependencies": dependencies, "paths": paths, "secrets": secrets, "warnings": warnings, } def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser() parser.add_argument("--audio-path", type=Path, default=DEFAULT_AUDIO) parser.add_argument("--voice-prompt-audio-path", type=Path, default=DEFAULT_VOICE_ANCHOR) parser.add_argument("--no-openai-key-required", action="store_true") return parser.parse_args() def main() -> int: args = parse_args() report = check_runtime( audio_path=args.audio_path, voice_prompt_audio_path=args.voice_prompt_audio_path, require_openai_key=not args.no_openai_key_required, ) print(json.dumps(report, indent=2, ensure_ascii=False)) return 0 if report["ok"] else 2 if __name__ == "__main__": raise SystemExit(main())