mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 05:40:26 +02:00
refactor(cleanup): remove Legacy TTS Architecture
Delete legacy backend infrastructure: - abogen/tts_backend.py (TTSBackend protocol, TTSBackendMetadata) - abogen/tts_backend_registry.py (TTSBackendRegistry, global singleton, register_backend) - abogen/tts_backends/ (kokoro.py, supertonic.py, __init__.py) Delete legacy tests: - tests/test_tts_backend.py - tests/test_kokoro_backend.py - tests/test_voice_formula_resolution.py - tests/test_tts_supertonic_unsupported_chars.py Production code now uses only Plugin Architecture via create_pipeline(). All contract, behavioral, and integration tests pass. 2 pre-existing failures in test_supertonic_plugin.py (mock engine mismatch).
This commit is contained in:
@@ -1,89 +1,89 @@
|
||||
# Architecture Amendment #1: EngineConfig — `lang_code` field
|
||||
|
||||
**Date:** 2026-07-12
|
||||
**Status:** Accepted
|
||||
**PR:** #12 (Normalize Pipeline Public API)
|
||||
|
||||
## Summary
|
||||
|
||||
Add `lang_code: str = "a"` to `EngineConfig` and update its definition to clarify the architectural contract.
|
||||
|
||||
## Background
|
||||
|
||||
During migration from the old `KokoroBackend` to the Plugin Architecture, the `lang_code` parameter became a dead argument. The old backend read it from `**kwargs` and passed it to `KPipeline(lang_code=...)`. The new `KokoroPlugin.create_engine()` hardcodes `lang_code="a"`, ignoring the config entirely. Callers continued passing `lang_code` to `create_pipeline()`, unaware it had no effect.
|
||||
|
||||
This is a functional regression relative to the pre-Plugin Architecture behavior.
|
||||
|
||||
## Decision
|
||||
|
||||
### 1. Updated EngineConfig definition
|
||||
|
||||
**Before:**
|
||||
```
|
||||
Immutable value object for engine initialization settings.
|
||||
Contains only engine-specific settings, no resource references.
|
||||
```
|
||||
|
||||
**After:**
|
||||
```
|
||||
Immutable configuration of an Engine instance.
|
||||
Contains parameters that define how a particular Engine instance is
|
||||
created and that remain constant throughout the lifetime of that Engine.
|
||||
Plugin implementations may ignore fields that are not applicable to them.
|
||||
```
|
||||
|
||||
### 2. New field
|
||||
|
||||
```python
|
||||
@dataclass(frozen=True)
|
||||
class EngineConfig:
|
||||
device: str = "cpu"
|
||||
lang_code: str = "a"
|
||||
```
|
||||
|
||||
### 3. Architectural rules
|
||||
|
||||
- **Fields in EngineConfig are optional unless explicitly required by a plugin.**
|
||||
- **Plugins MUST ignore unsupported EngineConfig fields.**
|
||||
- **All parameters that may vary between individual synthesis requests must remain in `SynthesisRequest.parameters`.**
|
||||
|
||||
## Rationale
|
||||
|
||||
Analysis of real TTS engines (Kokoro, Piper, XTTS, Coqui, StyleTTS2, Fish Speech) confirmed:
|
||||
|
||||
| Parameter type | Where it belongs | Example |
|
||||
|---------------|-----------------|---------|
|
||||
| Engine instance config (immutable) | `EngineConfig` | `device`, `lang_code` |
|
||||
| Synthesis parameters (per-request) | `SynthesisRequest.parameters` | `speed`, `split_pattern`, `total_steps` |
|
||||
|
||||
`lang_code` determines the engine's behavior at creation time and cannot be changed during the engine's lifetime. It is not a synthesis parameter.
|
||||
|
||||
## Impact on existing plugins
|
||||
|
||||
| Plugin | `device` | `lang_code` | Notes |
|
||||
|--------|----------|-------------|-------|
|
||||
| Kokoro | Reads ✓ | Reads ✓ (was hardcoded, now from config) | Regression fixed |
|
||||
| SuperTonic | Ignores | Ignores | No change — no language concept |
|
||||
| Future plugins | May read | May ignore | Field-ignoring rule applies |
|
||||
|
||||
## Contract tests added
|
||||
|
||||
```python
|
||||
class TestEngineConfigContract:
|
||||
def test_default_lang_code(self) # EngineConfig().lang_code == "a"
|
||||
def test_custom_lang_code(self) # EngineConfig(lang_code="j").lang_code == "j"
|
||||
def test_immutability_lang_code(self) # frozen — cannot reassign
|
||||
def test_plugins_may_ignore_irrelevant_fields(self) # field-ignoring rule
|
||||
def test_engine_config_contains_engine_instance_configuration(self) # definition
|
||||
```
|
||||
|
||||
## Files changed
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `abogen/tts_plugin/types.py` | Updated docstring, added `lang_code: str = "a"` |
|
||||
| `plugins/kokoro/__init__.py` | Reads `config.lang_code` instead of hardcoded `"a"` |
|
||||
| `abogen/tts_plugin/utils.py` | `create_pipeline()` passes `lang_code` to `EngineConfig` |
|
||||
| `tests/contracts/test_types_contract.py` | 5 new contract tests |
|
||||
| `tests/contracts/test_plugin_manager_contract.py` | Updated assertion for `lang_code` |
|
||||
| `tests/test_behavioral_regression.py` | Updated `test_engine_config_defaults` |
|
||||
# Architecture Amendment #1: EngineConfig — `lang_code` field
|
||||
|
||||
**Date:** 2026-07-12
|
||||
**Status:** Accepted
|
||||
**PR:** #12 (Normalize Pipeline Public API)
|
||||
|
||||
## Summary
|
||||
|
||||
Add `lang_code: str = "a"` to `EngineConfig` and update its definition to clarify the architectural contract.
|
||||
|
||||
## Background
|
||||
|
||||
During migration from the old `KokoroBackend` to the Plugin Architecture, the `lang_code` parameter became a dead argument. The old backend read it from `**kwargs` and passed it to `KPipeline(lang_code=...)`. The new `KokoroPlugin.create_engine()` hardcodes `lang_code="a"`, ignoring the config entirely. Callers continued passing `lang_code` to `create_pipeline()`, unaware it had no effect.
|
||||
|
||||
This is a functional regression relative to the pre-Plugin Architecture behavior.
|
||||
|
||||
## Decision
|
||||
|
||||
### 1. Updated EngineConfig definition
|
||||
|
||||
**Before:**
|
||||
```
|
||||
Immutable value object for engine initialization settings.
|
||||
Contains only engine-specific settings, no resource references.
|
||||
```
|
||||
|
||||
**After:**
|
||||
```
|
||||
Immutable configuration of an Engine instance.
|
||||
Contains parameters that define how a particular Engine instance is
|
||||
created and that remain constant throughout the lifetime of that Engine.
|
||||
Plugin implementations may ignore fields that are not applicable to them.
|
||||
```
|
||||
|
||||
### 2. New field
|
||||
|
||||
```python
|
||||
@dataclass(frozen=True)
|
||||
class EngineConfig:
|
||||
device: str = "cpu"
|
||||
lang_code: str = "a"
|
||||
```
|
||||
|
||||
### 3. Architectural rules
|
||||
|
||||
- **Fields in EngineConfig are optional unless explicitly required by a plugin.**
|
||||
- **Plugins MUST ignore unsupported EngineConfig fields.**
|
||||
- **All parameters that may vary between individual synthesis requests must remain in `SynthesisRequest.parameters`.**
|
||||
|
||||
## Rationale
|
||||
|
||||
Analysis of real TTS engines (Kokoro, Piper, XTTS, Coqui, StyleTTS2, Fish Speech) confirmed:
|
||||
|
||||
| Parameter type | Where it belongs | Example |
|
||||
|---------------|-----------------|---------|
|
||||
| Engine instance config (immutable) | `EngineConfig` | `device`, `lang_code` |
|
||||
| Synthesis parameters (per-request) | `SynthesisRequest.parameters` | `speed`, `split_pattern`, `total_steps` |
|
||||
|
||||
`lang_code` determines the engine's behavior at creation time and cannot be changed during the engine's lifetime. It is not a synthesis parameter.
|
||||
|
||||
## Impact on existing plugins
|
||||
|
||||
| Plugin | `device` | `lang_code` | Notes |
|
||||
|--------|----------|-------------|-------|
|
||||
| Kokoro | Reads ✓ | Reads ✓ (was hardcoded, now from config) | Regression fixed |
|
||||
| SuperTonic | Ignores | Ignores | No change — no language concept |
|
||||
| Future plugins | May read | May ignore | Field-ignoring rule applies |
|
||||
|
||||
## Contract tests added
|
||||
|
||||
```python
|
||||
class TestEngineConfigContract:
|
||||
def test_default_lang_code(self) # EngineConfig().lang_code == "a"
|
||||
def test_custom_lang_code(self) # EngineConfig(lang_code="j").lang_code == "j"
|
||||
def test_immutability_lang_code(self) # frozen — cannot reassign
|
||||
def test_plugins_may_ignore_irrelevant_fields(self) # field-ignoring rule
|
||||
def test_engine_config_contains_engine_instance_configuration(self) # definition
|
||||
```
|
||||
|
||||
## Files changed
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `abogen/tts_plugin/types.py` | Updated docstring, added `lang_code: str = "a"` |
|
||||
| `plugins/kokoro/__init__.py` | Reads `config.lang_code` instead of hardcoded `"a"` |
|
||||
| `abogen/tts_plugin/utils.py` | `create_pipeline()` passes `lang_code` to `EngineConfig` |
|
||||
| `tests/contracts/test_types_contract.py` | 5 new contract tests |
|
||||
| `tests/contracts/test_plugin_manager_contract.py` | Updated assertion for `lang_code` |
|
||||
| `tests/test_behavioral_regression.py` | Updated `test_engine_config_defaults` |
|
||||
|
||||
Reference in New Issue
Block a user