Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions plugins/_kokoro_tts/api/resolve_hf_repo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import json
import urllib.error
import urllib.request

from helpers.api import ApiHandler, Request, Response


class ResolveHfRepo(ApiHandler):
async def process(self, input: dict, request: Request) -> dict | Response:
repo = str(input.get("repo", "") or "").strip()
if not repo:
return {"success": False, "error": "No repo ID provided."}

try:
url = f"https://huggingface.co/api/models/{repo}"
with urllib.request.urlopen(url, timeout=15) as resp:
data = json.loads(resp.read())
except urllib.error.HTTPError as e:
if e.code == 404:
return {"success": False, "error": f"Repo '{repo}' not found."}
return {"success": False, "error": f"HuggingFace API error: {e}"}
except Exception as e:
return {"success": False, "error": f"Network error: {e}"}

files = [s["rfilename"] for s in data.get("siblings", [])]

# Find model: prefer full-precision .onnx
onnx_files = [f for f in files if f.endswith(".onnx")]
if not onnx_files:
return {"success": False, "error": f"No .onnx file found in {repo}."}
model_file = next(
(
f
for f in onnx_files
if not any(q in f.lower() for q in ("int8", "quantized", "fp16", "q8"))
),
onnx_files[0],
)

# Find voices: .npz or .bin (not .onnx)
voices_files = [
f
for f in files
if f.endswith(".npz") or (f.endswith(".bin") and not f.endswith(".onnx"))
]
if not voices_files:
return {
"success": False,
"error": f"No voices file (.npz or .bin) found in {repo}.",
}
# Prefer .npz over .bin
npz_files = [f for f in voices_files if f.endswith(".npz")]
voices_file = npz_files[0] if npz_files else voices_files[0]

return {
"success": True,
"repo": repo,
"model_file": model_file,
"voices_file": voices_file,
"all_files": files,
}
27 changes: 18 additions & 9 deletions plugins/_kokoro_tts/api/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,37 @@
from plugins._kokoro_tts.helpers import migration, runtime


def _pkg_version(name: str) -> tuple[str, str]:
try:
return importlib.metadata.version(name), ""
except Exception as e:
return "", str(e)


class Status(ApiHandler):
async def process(self, input: dict, request: Request) -> dict | Response:
migration.ensure_migrated()

package_version = ""
package_error = ""
try:
package_version = importlib.metadata.version("kokoro")
except Exception as e:
package_error = str(e)
cfg = runtime.get_config()
py_version, py_error = _pkg_version("kokoro")
onnx_version, onnx_error = _pkg_version("kokoro_onnx")

return {
"plugin": "_kokoro_tts",
"enabled": runtime.is_globally_enabled(),
"config": runtime.get_config(),
"config": cfg,
"engine": cfg.get("engine", "kokoro_py"),
"model": {
"ready": await runtime.is_downloaded(),
"loading": await runtime.is_downloading(),
},
"package": {
"version": package_version,
"error": package_error,
"version": py_version,
"error": py_error,
},
"onnx_package": {
"version": onnx_version,
"error": onnx_error,
},
"fallback": "Browser-native speechSynthesis remains the fallback when Kokoro is disabled.",
}
7 changes: 7 additions & 0 deletions plugins/_kokoro_tts/default_config.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
voice: am_puck,am_onyx
voice_weights: {}
speed: 1.1
engine: kokoro_py # kokoro_py | kokoro_onnx
lang: en-us # espeak-ng language code: en-us, de, fr, es, it, etc.
onnx_hf_repo: '' # HuggingFace repo ID, e.g. Godelaune/Kokoro-82M-ONNX-German-Martin
onnx_model_file: '' # auto-detected from repo if empty; e.g. kokoro-martin.onnx
onnx_voices_file: '' # auto-detected from repo if empty; e.g. voices-martin.npz
onnx_mixed_lang: en-us # secondary espeak-ng language for matched terms
onnx_mixed_lang_terms: '' # comma/newline-separated terms to phonemize with secondary language
Loading