agent-zero/plugins/_kokoro_tts/hooks.py
Alessandro ce48667e98
Some checks failed
Build And Publish Docker Images / plan (push) Has been cancelled
Build And Publish Docker Images / build (push) Has been cancelled
Add Paradee as the default voice in Local TTS
Offer Paradee Heart alongside Kokoro voices in the existing bundled TTS
plugin. Default unconfigured settings to Paradee while preserving saved
Kokoro voices, blends, speed and activation choices. Switching engines
replaces the voice selection without a separate plugin or startup dialog.

Add lazy CPU ONNX synthesis with cached, pinned model assets and split
long input without dropping phonemes. Make status and preload follow the
selected engine, and present both engines through the Local TTS UI.

Prepare Paradee dependencies in hooks.py on plugin install/update,
enabled-plugin startup and re-enable. Reuse installed packages, preserve
browser fallback on setup failure and keep requirements.txt unchanged.
Update plugin documentation and regression coverage.

Validation: 44 focused tests passed in both host and Docker framework
runtimes. Live synthesis and voice-picker switching passed on localhost:32081.
git diff --check passed. Fresh-image builds and actual missing-package
installation were not tested.
2026-10-08 21:36:02 +02:00

69 lines
2.2 KiB
Python

from __future__ import annotations
import importlib
import importlib.metadata
import shutil
import subprocess
import sys
import threading
from packaging.requirements import Requirement
from helpers.print_style import PrintStyle
from plugins._kokoro_tts.helpers import migration, runtime
_DEPENDENCIES = (
Requirement("onnxruntime>=1.19.2"),
Requirement("en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl"),
)
_SETUP_LOCK = threading.Lock()
def _missing_requirements() -> list[str]:
missing = []
for requirement in _DEPENDENCIES:
try:
version = importlib.metadata.version(requirement.name)
except importlib.metadata.PackageNotFoundError:
version = None
if version is None or version not in requirement.specifier:
missing.append(str(requirement))
return missing
def ensure_dependencies(raise_on_error: bool = True) -> bool:
with _SETUP_LOCK:
try:
missing = _missing_requirements()
if not missing:
return True
uv = shutil.which("uv")
if not uv:
raise RuntimeError("Local TTS requires 'uv' to prepare its dependencies.")
PrintStyle.info("Local TTS: preparing dependencies:", ", ".join(missing))
subprocess.check_call(
[uv, "pip", "install", "--python", sys.executable, *missing],
timeout=60,
)
importlib.invalidate_caches()
if _missing_requirements():
raise RuntimeError("Local TTS dependencies are still unavailable after installation.")
return True
except Exception as exc:
if raise_on_error:
raise RuntimeError(f"Local TTS dependency setup failed: {exc}") from exc
PrintStyle.error(f"Local TTS dependency setup failed: {exc}")
return False
def install() -> bool:
return ensure_dependencies()
def get_plugin_config(default=None, **kwargs):
migration.ensure_migrated()
return runtime.normalize_config(default or {})
def save_plugin_config(default=None, settings=None, **kwargs):
return runtime.normalize_config(settings or default or {})