WillHbx Claude Sonnet 4.6 commited on
Commit
3206b9c
·
1 Parent(s): a85aadb

Auto-download Kokoro model files if missing at startup

Browse files

Replaces the FileNotFoundError with _ensure_kokoro_models() which
downloads kokoro-v1.0.onnx and voices-v1.0.bin from the kokoro-onnx
GitHub releases if they are absent — handles the HF Space ephemeral
filesystem without breaking local or modal configurations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. visualnovel/tts.py +22 -10
visualnovel/tts.py CHANGED
@@ -69,6 +69,27 @@ _FEMALE_GENDER_HINTS = {"woman", "female", "her", "she", "girl", "lady"}
69
 
70
  _MODEL_PATH = config.MODELS_DIR / "kokoro" / "kokoro-v1.0.onnx"
71
  _VOICES_PATH = config.MODELS_DIR / "kokoro" / "voices-v1.0.bin"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
 
74
  def _pick_voice(voice_description: str, sprite_seed: int) -> str:
@@ -106,16 +127,7 @@ class KokoroTTS:
106
  def __init__(self) -> None:
107
  from kokoro_onnx import Kokoro # noqa: PLC0415
108
 
109
- if not _MODEL_PATH.exists() or not _VOICES_PATH.exists():
110
- raise FileNotFoundError(
111
- f"Kokoro model files missing from {_MODEL_PATH.parent}.\n"
112
- "Download them with:\n"
113
- " curl -L -o models/kokoro/kokoro-v1.0.onnx \\\n"
114
- " https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/kokoro-v1.0.onnx\n"
115
- " curl -L -o models/kokoro/voices-v1.0.bin \\\n"
116
- " https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/voices-v1.0.bin"
117
- )
118
-
119
  self._kokoro = Kokoro(str(_MODEL_PATH), str(_VOICES_PATH))
120
  # Filter profiles to voices actually present in the loaded model
121
  available = set(self._kokoro.get_voices())
 
69
 
70
  _MODEL_PATH = config.MODELS_DIR / "kokoro" / "kokoro-v1.0.onnx"
71
  _VOICES_PATH = config.MODELS_DIR / "kokoro" / "voices-v1.0.bin"
72
+ _KOKORO_BASE_URL = (
73
+ "https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0"
74
+ )
75
+
76
+
77
+ def _ensure_kokoro_models() -> None:
78
+ """Download Kokoro model files if absent (handles HF Space ephemeral filesystem)."""
79
+ files = {
80
+ _MODEL_PATH: f"{_KOKORO_BASE_URL}/kokoro-v1.0.onnx",
81
+ _VOICES_PATH: f"{_KOKORO_BASE_URL}/voices-v1.0.bin",
82
+ }
83
+ missing = {p: u for p, u in files.items() if not p.exists()}
84
+ if not missing:
85
+ return
86
+ import urllib.request
87
+
88
+ _MODEL_PATH.parent.mkdir(parents=True, exist_ok=True)
89
+ for path, url in missing.items():
90
+ print(f"[tts] Downloading {path.name} …", flush=True)
91
+ urllib.request.urlretrieve(url, path)
92
+ print(f"[tts] {path.name} ready ({path.stat().st_size // 1_000_000} MB)", flush=True)
93
 
94
 
95
  def _pick_voice(voice_description: str, sprite_seed: int) -> str:
 
127
  def __init__(self) -> None:
128
  from kokoro_onnx import Kokoro # noqa: PLC0415
129
 
130
+ _ensure_kokoro_models()
 
 
 
 
 
 
 
 
 
131
  self._kokoro = Kokoro(str(_MODEL_PATH), str(_VOICES_PATH))
132
  # Filter profiles to voices actually present in the loaded model
133
  available = set(self._kokoro.get_voices())