mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
docs: archive historical plans, remove duplicates
- Move migration-roadmap.md, epub3_upgrade_plan.md, entities_step_overhaul_plan.md to docs/archive/ - Remove duplicate tts-plugin-architecture.md
This commit is contained in:
@@ -0,0 +1,689 @@
|
||||
# TTS Plugin Architecture — Final Specification
|
||||
|
||||
## 1. Core Domain
|
||||
|
||||
Zero dependencies. Pure business logic.
|
||||
|
||||
### 1.1 Engine
|
||||
|
||||
Factory for sessions. Stateless. Thread-safe for createSession().
|
||||
|
||||
```
|
||||
interface Engine:
|
||||
createSession() -> EngineSession
|
||||
dispose() -> void
|
||||
```
|
||||
|
||||
**createSession() contract**:
|
||||
- Returns: EngineSession
|
||||
- Raises: EngineError on failure
|
||||
- Ownership: Transfers to caller
|
||||
- Thread-safe: Yes
|
||||
|
||||
**dispose() contract**:
|
||||
- Releases engine resources
|
||||
- Caller must ensure all sessions created by this engine are disposed before calling dispose()
|
||||
- Disposing an engine while any session is still alive violates the API contract; behavior is undefined
|
||||
- Idempotent: Safe to call multiple times
|
||||
- Never raises: Catches and logs internally
|
||||
- After dispose(): All methods except dispose() raise EngineError
|
||||
|
||||
### 1.2 EngineSession
|
||||
|
||||
Owns mutable execution state isolated from other concurrent work. NOT thread-safe.
|
||||
|
||||
```
|
||||
interface EngineSession:
|
||||
synthesize(request: SynthesisRequest) -> SynthesizedAudio
|
||||
dispose() -> void
|
||||
```
|
||||
|
||||
**synthesize() contract**:
|
||||
- Returns: SynthesizedAudio
|
||||
- Raises: EngineError on failure (session remains usable)
|
||||
- Thread-safe: No
|
||||
|
||||
**dispose() contract**:
|
||||
- Releases session resources
|
||||
- Idempotent: Safe to call multiple times
|
||||
- Never raises: Catches and logs internally
|
||||
- After dispose(): All methods except dispose() raise EngineError
|
||||
|
||||
### 1.3 SynthesisRequest
|
||||
|
||||
Immutable value object.
|
||||
|
||||
```
|
||||
SynthesisRequest:
|
||||
text: string
|
||||
voice: VoiceSelection
|
||||
parameters: ParameterValues
|
||||
format: AudioFormat
|
||||
```
|
||||
|
||||
### 1.4 SynthesizedAudio
|
||||
|
||||
Immutable value object.
|
||||
|
||||
```
|
||||
SynthesizedAudio:
|
||||
data: bytes
|
||||
format: AudioFormat
|
||||
duration: Duration
|
||||
```
|
||||
|
||||
### 1.5 VoiceSelection
|
||||
|
||||
Immutable value object. Opaque to engine.
|
||||
|
||||
```
|
||||
VoiceSelection:
|
||||
source: string
|
||||
key: string
|
||||
payload: any = None # Optional; required for clone/blend sources
|
||||
```
|
||||
|
||||
### 1.6 ParameterValues
|
||||
|
||||
Immutable value object. Behaves like Mapping[str, Any].
|
||||
|
||||
```
|
||||
ParameterValues:
|
||||
values: Mapping[str, Any]
|
||||
```
|
||||
|
||||
### 1.7 AudioFormat
|
||||
|
||||
Immutable value object.
|
||||
|
||||
```
|
||||
AudioFormat:
|
||||
mime: string
|
||||
extension: string
|
||||
```
|
||||
|
||||
### 1.8 Duration
|
||||
|
||||
Immutable value object.
|
||||
|
||||
```
|
||||
Duration:
|
||||
seconds: number
|
||||
```
|
||||
|
||||
### 1.9 EngineConfig
|
||||
|
||||
Engine initialization settings only. No resource references.
|
||||
|
||||
```
|
||||
EngineConfig:
|
||||
device: string # "cpu", "cuda:0", etc.
|
||||
# Engine-specific settings (if any)
|
||||
# Unknown keys are ignored (no error)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Error Hierarchy
|
||||
|
||||
Typed exceptions. Engines raise EngineError or subtypes. Never raw exceptions.
|
||||
|
||||
```
|
||||
EngineError (base)
|
||||
├── ModelNotFoundError
|
||||
├── ModelLoadError
|
||||
├── NetworkError
|
||||
├── InvalidInputError
|
||||
├── ConfigurationError
|
||||
├── CancelledError
|
||||
└── InternalError
|
||||
```
|
||||
|
||||
**Contract**:
|
||||
- synthesize() raises EngineError on failure, session remains usable
|
||||
- dispose() never raises (catches and logs internally)
|
||||
- create_engine() raises EngineError on failure, cleans up partially created resources
|
||||
- createSession() raises EngineError on failure, no partially initialized session returned
|
||||
- cancel() causes synthesize() to raise CancelledError
|
||||
|
||||
---
|
||||
|
||||
## 3. Capability Interfaces (Optional)
|
||||
|
||||
Engines implement only what they support. Capabilities are additive.
|
||||
|
||||
### 3.1 VoiceLister
|
||||
|
||||
```
|
||||
interface VoiceLister:
|
||||
listVoices(sourceId: string) -> list[VoiceManifest]
|
||||
```
|
||||
|
||||
### 3.2 PreviewGenerator
|
||||
|
||||
```
|
||||
interface PreviewGenerator:
|
||||
generatePreview(voice: VoiceSelection, text: string) -> SynthesizedAudio
|
||||
```
|
||||
|
||||
### 3.3 ModelRequirements
|
||||
|
||||
Static at plugin level, not engine level. Host reads before creating engine.
|
||||
|
||||
```
|
||||
MODEL_REQUIREMENTS = list[ModelManifest]
|
||||
```
|
||||
|
||||
### 3.4 StreamingSynthesizer
|
||||
|
||||
Optional capability of EngineSession, not Engine.
|
||||
|
||||
```
|
||||
interface StreamingSynthesizer:
|
||||
synthesizeStream(request: SynthesisRequest) -> Iterator[bytes]
|
||||
```
|
||||
|
||||
**Iterator contract**:
|
||||
- Yields audio chunks as they become available
|
||||
- Raises CancelledError if cancel() is called during iteration
|
||||
- Raises EngineError on synthesis failure
|
||||
- Iterator exhaustion = synthesis complete
|
||||
- Session remains usable after iterator completes
|
||||
|
||||
### 3.5 CancelableSession
|
||||
|
||||
Optional capability for engines that support cancellation.
|
||||
|
||||
```
|
||||
interface CancelableSession:
|
||||
cancel() -> void
|
||||
```
|
||||
|
||||
**cancel() contract**:
|
||||
- Cancels in-progress synthesize()
|
||||
- synthesize() raises CancelledError (subtype of EngineError)
|
||||
- EngineSession remains usable after cancellation (unless implementation documents otherwise)
|
||||
|
||||
---
|
||||
|
||||
## 4. Plugin Manifest
|
||||
|
||||
Static metadata. Immutable. No dependencies.
|
||||
|
||||
### 4.1 PluginManifest
|
||||
|
||||
```
|
||||
PluginManifest:
|
||||
id: string
|
||||
name: string
|
||||
version: string
|
||||
api_version: string # semver format: MAJOR.MINOR
|
||||
description: string
|
||||
author: string
|
||||
capabilities: list[string]
|
||||
requires: RequirementManifest
|
||||
engine: EngineManifest
|
||||
```
|
||||
|
||||
**api_version contract**:
|
||||
- Format: semver (MAJOR.MINOR)
|
||||
- Compatibility: Host rejects plugin if major version differs
|
||||
- Minor version: backward compatible, Host accepts higher minor
|
||||
|
||||
### 4.2 EngineManifest
|
||||
|
||||
```
|
||||
EngineManifest:
|
||||
voiceSources: list[VoiceSourceManifest]
|
||||
parameters: list[ParameterManifest]
|
||||
audioFormats: list[AudioFormatManifest]
|
||||
```
|
||||
|
||||
### 4.3 VoiceSourceManifest
|
||||
|
||||
```
|
||||
VoiceSourceManifest:
|
||||
id: string
|
||||
name: string
|
||||
type: string # "list", "speaker_id", "clone", "blend", "generate", "none"
|
||||
config: any
|
||||
```
|
||||
|
||||
### 4.4 VoiceManifest
|
||||
|
||||
```
|
||||
VoiceManifest:
|
||||
id: string
|
||||
name: string
|
||||
tags: list[string]
|
||||
```
|
||||
|
||||
### 4.5 ParameterManifest
|
||||
|
||||
```
|
||||
ParameterManifest:
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
type: string # "float", "int", "string", "boolean", "enum"
|
||||
default: any
|
||||
min: number (optional)
|
||||
max: number (optional)
|
||||
step: number (optional)
|
||||
options: list[EnumOption] (optional)
|
||||
unit: string (optional)
|
||||
group: string (optional)
|
||||
```
|
||||
|
||||
### 4.6 AudioFormatManifest
|
||||
|
||||
```
|
||||
AudioFormatManifest:
|
||||
mime: string
|
||||
extension: string
|
||||
```
|
||||
|
||||
### 4.7 EnumOption
|
||||
|
||||
```
|
||||
EnumOption:
|
||||
value: string
|
||||
label: string
|
||||
```
|
||||
|
||||
### 4.8 RequirementManifest
|
||||
|
||||
```
|
||||
RequirementManifest:
|
||||
gpu: GpuRequirement (optional)
|
||||
memory: number (optional)
|
||||
internet: boolean (optional)
|
||||
```
|
||||
|
||||
### 4.9 GpuRequirement
|
||||
|
||||
```
|
||||
GpuRequirement:
|
||||
required: boolean
|
||||
type: string (optional)
|
||||
memory: number (optional)
|
||||
```
|
||||
|
||||
### 4.10 ModelManifest
|
||||
|
||||
```
|
||||
ModelManifest:
|
||||
id: string
|
||||
name: string
|
||||
size: string
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Host Services
|
||||
|
||||
### 5.1 HostContext
|
||||
|
||||
Minimal. 3 fields maximum. No business logic.
|
||||
|
||||
```
|
||||
HostContext:
|
||||
config_dir: Path # For API keys, preferences
|
||||
logger: Logger # For logging
|
||||
http_client: HttpClient # For network requests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Plugin Contract
|
||||
|
||||
### 6.1 Plugin Exports
|
||||
|
||||
```python
|
||||
# plugins/kokoro/__init__.py
|
||||
|
||||
PLUGIN_MANIFEST = PluginManifest(...)
|
||||
MODEL_REQUIREMENTS = [...] # Static at plugin level
|
||||
|
||||
def create_engine(
|
||||
context: HostContext,
|
||||
model_path: Path | None,
|
||||
config: EngineConfig
|
||||
) -> Engine:
|
||||
"""Create engine. Atomic: succeeds fully or raises and cleans up."""
|
||||
...
|
||||
```
|
||||
|
||||
### 6.2 create_engine() Contract
|
||||
|
||||
- Parameters:
|
||||
- context: HostContext (host services)
|
||||
- model_path: Path | None (resolved model path, or None for cloud/no-model engines)
|
||||
- config: EngineConfig (engine initialization settings)
|
||||
- Returns: Engine
|
||||
- Raises: EngineError on failure
|
||||
- Atomic: Succeeds fully or cleans up and raises
|
||||
- Thread-safe: Can be called from any thread
|
||||
|
||||
---
|
||||
|
||||
## 7. Object Lifecycle
|
||||
|
||||
### 7.1 Engine Lifecycle
|
||||
|
||||
```
|
||||
1. DISCOVERY
|
||||
Host scans plugin directories
|
||||
Loads PLUGIN_MANIFEST and MODEL_REQUIREMENTS
|
||||
|
||||
2. MODEL DOWNLOAD (if MODEL_REQUIREMENTS non-empty)
|
||||
Host reads MODEL_REQUIREMENTS
|
||||
Downloads/caches required models
|
||||
Resolves model_path for create_engine()
|
||||
|
||||
3. ACTIVATION
|
||||
Host calls create_engine(context, model_path, config)
|
||||
Engine created, ready to use
|
||||
Raises EngineError on failure
|
||||
|
||||
4. SESSION CREATION
|
||||
Client calls engine.createSession()
|
||||
Returns EngineSession
|
||||
Ownership transfers to caller
|
||||
Raises EngineError on failure
|
||||
No partially initialized session returned
|
||||
|
||||
5. SYNTHESIS
|
||||
Client calls session.synthesize(request)
|
||||
Returns SynthesizedAudio
|
||||
Raises EngineError on failure (session remains usable)
|
||||
|
||||
6. SESSION DISPOSAL
|
||||
Client calls session.dispose()
|
||||
Releases session resources
|
||||
|
||||
7. DEACTIVATION
|
||||
Client calls engine.dispose()
|
||||
Caller must ensure all sessions are disposed first
|
||||
Disposing engine while sessions are alive is undefined behavior
|
||||
Releases engine resources
|
||||
```
|
||||
|
||||
### 7.2 EngineSession Lifecycle
|
||||
|
||||
```
|
||||
1. CREATION
|
||||
Created by Engine.createSession()
|
||||
Ownership transfers to caller
|
||||
Raises EngineError on failure
|
||||
|
||||
2. USAGE
|
||||
Client calls synthesize() one or more times
|
||||
Each call returns SynthesizedAudio or raises EngineError
|
||||
Session remains usable after synthesize() failure
|
||||
If CancelableSession: cancel() causes synthesize() to raise CancelledError
|
||||
If StreamingSynthesizer: iterator raises CancelledError on cancel(), EngineError on failure
|
||||
|
||||
3. DISPOSAL
|
||||
Client calls dispose()
|
||||
Releases session resources
|
||||
After dispose(), all methods except dispose() raise EngineError
|
||||
```
|
||||
|
||||
### 7.3 Ownership Rules
|
||||
|
||||
- Engine.createSession() transfers ownership of the returned session to the caller
|
||||
- Caller is responsible for disposing all sessions before disposing the engine
|
||||
- Engine does not track sessions; it has no lifecycle registry
|
||||
- Disposing an engine while any session is still alive violates the API contract; behavior is undefined
|
||||
- This design avoids coupling, synchronization overhead, and lifecycle registry complexity
|
||||
|
||||
### 7.4 Concurrent Operations
|
||||
|
||||
**Engine.dispose() concurrent with Engine.createSession()**:
|
||||
- createSession() must either succeed with fully initialized EngineSession or raise EngineError
|
||||
- Partially initialized EngineSession must never be returned
|
||||
- After dispose() completes, subsequent createSession() calls must raise EngineError
|
||||
|
||||
**EngineSession.dispose() concurrent with EngineSession.synthesize()**:
|
||||
- Not thread-safe. Caller must ensure synthesize() completes before dispose().
|
||||
|
||||
**EngineSession.dispose() concurrent with StreamingSynthesizer.synthesizeStream()**:
|
||||
- Not thread-safe. Caller must ensure stream iteration completes before dispose().
|
||||
|
||||
---
|
||||
|
||||
## 8. Thread Safety Contract
|
||||
|
||||
| Component | Thread-safe | Notes |
|
||||
|-----------|-------------|-------|
|
||||
| Engine | Yes | createSession() can be called from any thread |
|
||||
| EngineSession | No | synthesize() must be called from one thread at a time |
|
||||
| HostContext | Yes | Provides shared services |
|
||||
| VoiceSelection | Yes | Immutable value object |
|
||||
| ParameterValues | Yes | Immutable value object |
|
||||
| AudioFormat | Yes | Immutable value object |
|
||||
| EngineConfig | Yes | Immutable value object |
|
||||
|
||||
---
|
||||
|
||||
## 9. dispose() Contract
|
||||
|
||||
**General rules**:
|
||||
- Calling dispose() multiple times is safe (no-op on second call)
|
||||
- dispose() never raises exceptions (catches and logs internally)
|
||||
- After dispose(), all methods except dispose() raise EngineError
|
||||
|
||||
**Engine.dispose()**:
|
||||
- Caller must ensure all sessions are disposed first
|
||||
- Disposing engine while sessions are alive violates API contract; behavior is undefined
|
||||
- Releases engine resources
|
||||
|
||||
**EngineSession.dispose()**:
|
||||
- Releases session resources
|
||||
|
||||
---
|
||||
|
||||
## 10. Dependency Rules
|
||||
|
||||
```
|
||||
Core Domain (Engine, EngineSession, Value Objects)
|
||||
-> No dependencies
|
||||
|
||||
Plugin Manifest (PluginManifest, ModelManifest, etc.)
|
||||
-> No dependencies
|
||||
|
||||
Host Context (HostContext)
|
||||
-> Depends on: Core Domain (for types)
|
||||
|
||||
Plugin Implementation
|
||||
-> Depends on: Core Domain, Host Context
|
||||
|
||||
Host
|
||||
-> Depends on: Core Domain, Plugin Manifest
|
||||
```
|
||||
|
||||
**Forbidden**:
|
||||
- Core Domain -> anything else
|
||||
- Plugin Manifest -> anything else
|
||||
- Plugin Implementation -> Host (only receives HostContext)
|
||||
- Host -> Plugin Implementation (only via create_engine function)
|
||||
|
||||
---
|
||||
|
||||
## 11. Architectural Invariants
|
||||
|
||||
1. Core Domain has zero dependencies
|
||||
2. Plugins receive HostContext at creation, not via global state
|
||||
3. Model requirements are static (plugin level), not dynamic (engine level)
|
||||
4. Host validates capability implementation at load time: each capability declared in PluginManifest.capabilities must be implemented by the exported object via the corresponding interface
|
||||
5. synthesize() raises typed exceptions, not returns Result
|
||||
6. dispose() is idempotent and never raises
|
||||
7. No global state, no service locator
|
||||
8. VoiceSelection and ParameterValues are opaque to engine
|
||||
9. Display information comes from VoiceManifest
|
||||
10. HostContext is minimal (3 fields max)
|
||||
11. EngineConfig contains only engine settings, not resource references
|
||||
12. EngineSession owns mutable execution state isolated from other concurrent work
|
||||
13. Engine.createSession() transfers ownership to caller
|
||||
14. Caller must dispose all sessions before disposing engine
|
||||
15. After dispose(), all methods except dispose() raise EngineError
|
||||
16. create_engine() is atomic (all-or-nothing)
|
||||
17. Garbage collection without dispose() may leak (documented)
|
||||
18. Capabilities are additive (new capabilities don't break old plugins)
|
||||
19. api_version enables compatibility checking
|
||||
20. createSession() returns fully initialized session or raises, never partial
|
||||
21. cancel() causes synthesize() to raise CancelledError
|
||||
22. EngineSession remains usable after cancellation
|
||||
23. Engine does not track sessions; no lifecycle registry
|
||||
|
||||
---
|
||||
|
||||
## 12. Validation Examples
|
||||
|
||||
### 12.1 Kokoro
|
||||
|
||||
```python
|
||||
PLUGIN_MANIFEST = PluginManifest(
|
||||
id="kokoro",
|
||||
api_version="1.0",
|
||||
capabilities=["voice_list", "preview", "voice_blend"],
|
||||
engine=EngineManifest(
|
||||
voiceSources=[
|
||||
VoiceSourceManifest(id="builtin", type="list", config={"voices": [...]}),
|
||||
VoiceSourceManifest(id="formula", type="blend", config={"syntax": "{a}*0.5+{b}*0.5"}),
|
||||
],
|
||||
parameters=[ParameterManifest(id="speed", type="float", default=1.0, min=0.5, max=2.0)],
|
||||
audioFormats=[AudioFormatManifest(mime="audio/wav", extension="wav")],
|
||||
),
|
||||
)
|
||||
|
||||
MODEL_REQUIREMENTS = []
|
||||
|
||||
def create_engine(context: HostContext, model_path: Path | None, config: EngineConfig) -> Engine:
|
||||
model = load_kokoro(model_path)
|
||||
return KokoroEngine(model, config.device)
|
||||
```
|
||||
|
||||
### 12.2 SuperTonic
|
||||
|
||||
```python
|
||||
PLUGIN_MANIFEST = PluginManifest(
|
||||
id="supertonic",
|
||||
api_version="1.0",
|
||||
capabilities=["voice_list", "preview"],
|
||||
engine=EngineManifest(
|
||||
voiceSources=[VoiceSourceManifest(id="builtin", type="list", config={"voices": [...]})],
|
||||
parameters=[
|
||||
ParameterManifest(id="speed", type="float", default=1.0, min=0.5, max=2.0),
|
||||
ParameterManifest(id="steps", type="int", default=20, min=5, max=50),
|
||||
],
|
||||
audioFormats=[AudioFormatManifest(mime="audio/wav", extension="wav")],
|
||||
),
|
||||
)
|
||||
|
||||
MODEL_REQUIREMENTS = []
|
||||
|
||||
def create_engine(context: HostContext, model_path: Path | None, config: EngineConfig) -> Engine:
|
||||
model = load_supertonic(model_path)
|
||||
return SuperTonicEngine(model, config.device)
|
||||
```
|
||||
|
||||
### 12.3 ElevenLabs
|
||||
|
||||
```python
|
||||
PLUGIN_MANIFEST = PluginManifest(
|
||||
id="elevenlabs",
|
||||
api_version="1.0",
|
||||
capabilities=["voice_list"],
|
||||
requires=RequirementManifest(internet=True),
|
||||
engine=EngineManifest(
|
||||
voiceSources=[VoiceSourceManifest(id="cloud", type="list", config={"speakers": [...]})],
|
||||
parameters=[ParameterManifest(id="stability", type="float", default=0.5, min=0.0, max=1.0)],
|
||||
audioFormats=[AudioFormatManifest(mime="audio/mpeg", extension="mp3")],
|
||||
),
|
||||
)
|
||||
|
||||
MODEL_REQUIREMENTS = []
|
||||
|
||||
def create_engine(context: HostContext, model_path: Path | None, config: EngineConfig) -> Engine:
|
||||
api_key = (context.config_dir / "elevenlabs_key").read_text()
|
||||
return ElevenLabsEngine(api_key)
|
||||
```
|
||||
|
||||
### 12.4 Piper
|
||||
|
||||
```python
|
||||
PLUGIN_MANIFEST = PluginManifest(
|
||||
id="piper",
|
||||
api_version="1.0",
|
||||
capabilities=[],
|
||||
engine=EngineManifest(
|
||||
voiceSources=[VoiceSourceManifest(id="downloadable", type="list", config={"models": [...]})],
|
||||
parameters=[ParameterManifest(id="speed", type="float", default=1.0, min=0.5, max=2.0)],
|
||||
audioFormats=[AudioFormatManifest(mime="audio/wav", extension="wav")],
|
||||
),
|
||||
)
|
||||
|
||||
MODEL_REQUIREMENTS = [
|
||||
ModelManifest(id="en_US-lessac-medium", name="English Lessac Medium", size="100MB"),
|
||||
]
|
||||
|
||||
def create_engine(context: HostContext, model_path: Path | None, config: EngineConfig) -> Engine:
|
||||
return PiperEngine(model_path, config.device)
|
||||
```
|
||||
|
||||
### 12.5 XTTS (with streaming and cancellation)
|
||||
|
||||
```python
|
||||
PLUGIN_MANIFEST = PluginManifest(
|
||||
id="xtts",
|
||||
api_version="1.0",
|
||||
capabilities=["voice_list", "preview", "voice_clone", "streaming", "cancel"],
|
||||
requires=RequirementManifest(gpu=GpuRequirement(required=True, type="cuda")),
|
||||
engine=EngineManifest(
|
||||
voiceSources=[
|
||||
VoiceSourceManifest(id="speakers", type="speaker_id", config={"speakers": [...]}),
|
||||
VoiceSourceManifest(id="clone", type="clone", config={"requiresAudio": True, "maxDuration": 30}),
|
||||
],
|
||||
parameters=[ParameterManifest(id="temperature", type="float", default=0.7, min=0.1, max=1.0)],
|
||||
audioFormats=[AudioFormatManifest(mime="audio/wav", extension="wav")],
|
||||
),
|
||||
)
|
||||
|
||||
MODEL_REQUIREMENTS = [
|
||||
ModelManifest(id="xtts_v2", name="XTTS v2", size="2GB"),
|
||||
]
|
||||
|
||||
def create_engine(context: HostContext, model_path: Path | None, config: EngineConfig) -> Engine:
|
||||
return XTTSEngine(model_path, config.device)
|
||||
```
|
||||
|
||||
XTTS session implements: EngineSession, StreamingSynthesizer, CancelableSession.
|
||||
|
||||
---
|
||||
|
||||
## 13. Summary of All Decisions
|
||||
|
||||
| Aspect | Decision |
|
||||
|--------|----------|
|
||||
| Engine | Factory, stateless, thread-safe for createSession() |
|
||||
| EngineSession | Owns mutable execution state, not thread-safe |
|
||||
| EngineSession ownership | Caller owns (transferred from createSession) |
|
||||
| Engine session tracking | None; engine does not track sessions |
|
||||
| StreamingSynthesizer | Optional capability of EngineSession |
|
||||
| CancelableSession | Optional capability, cancel() raises CancelledError |
|
||||
| dispose() | Idempotent, never raises |
|
||||
| Engine.dispose() | Caller must dispose sessions first; undefined if violated |
|
||||
| createSession() | Raises EngineError on failure, no partial sessions |
|
||||
| create_engine() | Atomic, takes context, model_path, config |
|
||||
| EngineConfig | Engine settings only, no resource references |
|
||||
| model_path | Separate argument, not in EngineConfig |
|
||||
| MODEL_REQUIREMENTS | Static at plugin level |
|
||||
| HostContext | Minimal (3 fields) |
|
||||
| Error handling | Typed exceptions (EngineError hierarchy) |
|
||||
| Thread safety | Documented per component |
|
||||
| Capabilities | Additive, optional interfaces |
|
||||
| API versioning | api_version in manifest |
|
||||
| Concurrent dispose/createSession | Fully initialized session or EngineError |
|
||||
| Concurrent dispose/synthesizeStream | Not thread-safe; caller must complete iteration first |
|
||||
Reference in New Issue
Block a user