midnight-static / scripts /verify_kokoro_voices.py
cajpany's picture
Upload folder using huggingface_hub
fc9b7e2 verified
Raw
History Blame Contribute Delete
4.22 kB
"""Discover Kokoro voice IDs available for the configured Kokoro repo.
Run after installing the TTS dependency group:
uv sync --extra dev --extra tts
uv run python scripts/verify_kokoro_voices.py
"""
from __future__ import annotations
import importlib
import json
import sys
from collections.abc import Iterable
from pathlib import Path
from typing import Any
KOKORO_REPO_ID = "hexgrad/Kokoro-82M"
SELECTED_VOICE_IDS = {
"am_michael",
"am_onyx",
"af_bella",
"am_puck",
"am_fenrir",
"bm_george",
"hf_alpha",
"hm_omega",
}
def main() -> None:
report = discover_kokoro_voices()
print(json.dumps(report, indent=2, sort_keys=True))
voices = report.get("voices") or []
if not voices:
raise SystemExit("No Kokoro voices discovered. Inspect the report above.")
missing = sorted(SELECTED_VOICE_IDS.difference(voices))
if missing:
raise SystemExit(f"Selected VoiceID values missing from Kokoro repo: {missing}")
def discover_kokoro_voices() -> dict[str, Any]:
report: dict[str, Any] = {
"repo_id": KOKORO_REPO_ID,
"package": None,
"voices": [],
"selected": sorted(SELECTED_VOICE_IDS),
"sources": [],
"errors": [],
}
try:
kokoro = importlib.import_module("kokoro")
except Exception as exc: # pragma: no cover - depends on optional install
report["errors"].append(f"import kokoro failed: {exc!r}")
return report
report["package"] = {
"module": getattr(kokoro, "__name__", "kokoro"),
"file": getattr(kokoro, "__file__", None),
"version": getattr(kokoro, "__version__", None),
}
voices: set[str] = set()
voices.update(_voices_from_module_attrs(kokoro, report))
voices.update(_voices_from_hub(report))
voices.update(_voices_from_package_files(kokoro, report))
report["voices"] = sorted(voices)
return report
def _voices_from_module_attrs(module: Any, report: dict[str, Any]) -> set[str]:
voices: set[str] = set()
for attr_name in ("VOICES", "voices", "VOICE_NAMES", "VOICE_IDS"):
value = getattr(module, attr_name, None)
extracted = _extract_voice_names(value)
if extracted:
report["sources"].append(f"kokoro.{attr_name}")
voices.update(extracted)
return voices
def _voices_from_hub(report: dict[str, Any]) -> set[str]:
try:
from huggingface_hub import list_repo_files
except Exception as exc: # pragma: no cover - optional dependency guard
report["errors"].append(f"import huggingface_hub.list_repo_files failed: {exc!r}")
return set()
try:
files = list_repo_files(KOKORO_REPO_ID)
except Exception as exc: # pragma: no cover - network/cache dependent
report["errors"].append(f"list_repo_files({KOKORO_REPO_ID!r}) failed: {exc!r}")
return set()
voices = {
Path(file_name).stem
for file_name in files
if file_name.startswith("voices/") and file_name.endswith(".pt")
}
if voices:
report["sources"].append(f"{KOKORO_REPO_ID}:voices/*.pt")
return voices
def _voices_from_package_files(module: Any, report: dict[str, Any]) -> set[str]:
module_file = getattr(module, "__file__", None)
if not module_file:
return set()
root = Path(module_file).resolve().parent
patterns = ("*.pt", "*.pth", "*.bin", "*.onnx", "*.npz")
voices: set[str] = set()
for pattern in patterns:
for path in root.rglob(pattern):
stem = path.stem
if stem and not stem.startswith(("model", "kokoro")):
voices.add(stem)
if voices:
report["sources"].append(f"package files under {root}")
return voices
def _extract_voice_names(value: Any) -> set[str]:
if value is None:
return set()
if isinstance(value, str):
return {value}
if isinstance(value, dict):
return {str(key) for key in value.keys()}
if isinstance(value, Iterable):
return {str(item) for item in value if isinstance(item, str)}
return set()
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
sys.exit(130)