mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
feat: auto-register existing TTS backends
- Add create_kokoro_backend() factory in kokoro.py - Add create_supertonic_backend() factory in supertonic.py - Auto-discover backend modules in __init__.py via pkgutil - Both backends register themselves on import - Tests verify registration and factory callables
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
"""TTS backends package.
|
||||||
|
|
||||||
|
Backend modules are auto-discovered and imported here.
|
||||||
|
Each backend module registers itself with the global registry
|
||||||
|
when imported.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
import pkgutil
|
||||||
|
|
||||||
|
|
||||||
|
def _discover_backends():
|
||||||
|
"""Import all modules in this package to trigger their registration."""
|
||||||
|
package = __name__
|
||||||
|
for _importer, modname, _ispkg in pkgutil.iter_modules(path=__path__):
|
||||||
|
importlib.import_module(f"{package}.{modname}")
|
||||||
|
|
||||||
|
|
||||||
|
_discover_backends()
|
||||||
|
|
||||||
|
|||||||
@@ -3,3 +3,35 @@ def load_numpy_kpipeline():
|
|||||||
from kokoro import KPipeline # type: ignore[import-not-found]
|
from kokoro import KPipeline # type: ignore[import-not-found]
|
||||||
|
|
||||||
return np, KPipeline
|
return np, KPipeline
|
||||||
|
|
||||||
|
|
||||||
|
def create_kokoro_backend(**kwargs):
|
||||||
|
"""Create a Kokoro TTS backend instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lang_code: Language code (e.g. "a" for American English).
|
||||||
|
repo_id: HuggingFace repo id. Defaults to "hexgrad/Kokoro-82M".
|
||||||
|
device: Device to use ("cpu", "cuda", "mps"). Defaults to "cpu".
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
KPipeline instance.
|
||||||
|
"""
|
||||||
|
_np, KPipeline = load_numpy_kpipeline()
|
||||||
|
return KPipeline(
|
||||||
|
lang_code=kwargs["lang_code"],
|
||||||
|
repo_id=kwargs.get("repo_id", "hexgrad/Kokoro-82M"),
|
||||||
|
device=kwargs.get("device", "cpu"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
from abogen.tts_backend import TTSBackendMetadata
|
||||||
|
from abogen.tts_backend_registry import register_backend
|
||||||
|
|
||||||
|
register_backend(
|
||||||
|
metadata=TTSBackendMetadata(
|
||||||
|
id="kokoro",
|
||||||
|
name="Kokoro",
|
||||||
|
description="Kokoro TTS engine",
|
||||||
|
),
|
||||||
|
factory=create_kokoro_backend,
|
||||||
|
)
|
||||||
|
|||||||
@@ -273,3 +273,34 @@ class SupertonicPipeline:
|
|||||||
audio = _resample_linear(audio, src_rate, self.sample_rate)
|
audio = _resample_linear(audio, src_rate, self.sample_rate)
|
||||||
|
|
||||||
yield SupertonicSegment(graphemes=chunk_to_speak, audio=audio)
|
yield SupertonicSegment(graphemes=chunk_to_speak, audio=audio)
|
||||||
|
|
||||||
|
|
||||||
|
def create_supertonic_backend(**kwargs):
|
||||||
|
"""Create a SuperTonic TTS backend instance.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sample_rate: Audio sample rate. Defaults to 24000.
|
||||||
|
auto_download: Auto-download models. Defaults to True.
|
||||||
|
total_steps: Inference steps. Defaults to 5.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SupertonicPipeline instance.
|
||||||
|
"""
|
||||||
|
return SupertonicPipeline(
|
||||||
|
sample_rate=kwargs.get("sample_rate", 24000),
|
||||||
|
auto_download=kwargs.get("auto_download", True),
|
||||||
|
total_steps=kwargs.get("total_steps", 5),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
from abogen.tts_backend import TTSBackendMetadata
|
||||||
|
from abogen.tts_backend_registry import register_backend
|
||||||
|
|
||||||
|
register_backend(
|
||||||
|
metadata=TTSBackendMetadata(
|
||||||
|
id="supertonic",
|
||||||
|
name="SuperTonic",
|
||||||
|
description="SuperTonic TTS engine",
|
||||||
|
),
|
||||||
|
factory=create_supertonic_backend,
|
||||||
|
)
|
||||||
|
|||||||
@@ -97,3 +97,53 @@ class TestTTSBackendRegistry:
|
|||||||
result = registry.get_metadata("x")
|
result = registry.get_metadata("x")
|
||||||
assert result.name == "V2"
|
assert result.name == "V2"
|
||||||
assert registry.create_backend("x") == "v2"
|
assert registry.create_backend("x") == "v2"
|
||||||
|
|
||||||
|
|
||||||
|
class TestBackendRegistration:
|
||||||
|
"""Tests that existing backends are auto-registered."""
|
||||||
|
|
||||||
|
def test_import_triggers_registration(self):
|
||||||
|
import abogen.tts_backends # noqa: F401
|
||||||
|
|
||||||
|
from abogen.tts_backend_registry import _registry
|
||||||
|
|
||||||
|
backends = _registry.list_backends()
|
||||||
|
ids = [b.id for b in backends]
|
||||||
|
assert "kokoro" in ids
|
||||||
|
assert "supertonic" in ids
|
||||||
|
|
||||||
|
def test_kokoro_metadata(self):
|
||||||
|
import abogen.tts_backends # noqa: F401
|
||||||
|
|
||||||
|
from abogen.tts_backend_registry import _registry
|
||||||
|
|
||||||
|
meta = _registry.get_metadata("kokoro")
|
||||||
|
assert meta.id == "kokoro"
|
||||||
|
assert meta.name == "Kokoro"
|
||||||
|
assert "Kokoro" in meta.description
|
||||||
|
|
||||||
|
def test_supertonic_metadata(self):
|
||||||
|
import abogen.tts_backends # noqa: F401
|
||||||
|
|
||||||
|
from abogen.tts_backend_registry import _registry
|
||||||
|
|
||||||
|
meta = _registry.get_metadata("supertonic")
|
||||||
|
assert meta.id == "supertonic"
|
||||||
|
assert meta.name == "SuperTonic"
|
||||||
|
assert "SuperTonic" in meta.description
|
||||||
|
|
||||||
|
def test_kokoro_factory_callable(self):
|
||||||
|
import abogen.tts_backends # noqa: F401
|
||||||
|
|
||||||
|
from abogen.tts_backend_registry import _registry
|
||||||
|
|
||||||
|
factory = _registry._factories["kokoro"]
|
||||||
|
assert callable(factory)
|
||||||
|
|
||||||
|
def test_supertonic_factory_callable(self):
|
||||||
|
import abogen.tts_backends # noqa: F401
|
||||||
|
|
||||||
|
from abogen.tts_backend_registry import _registry
|
||||||
|
|
||||||
|
factory = _registry._factories["supertonic"]
|
||||||
|
assert callable(factory)
|
||||||
|
|||||||
Reference in New Issue
Block a user