ssmd 0.5.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ssmd/__init__.py +189 -0
- ssmd/_version.py +34 -0
- ssmd/capabilities.py +277 -0
- ssmd/document.py +918 -0
- ssmd/formatter.py +244 -0
- ssmd/parser.py +1049 -0
- ssmd/parser_types.py +41 -0
- ssmd/py.typed +0 -0
- ssmd/segment.py +720 -0
- ssmd/sentence.py +270 -0
- ssmd/ssml_conversions.py +124 -0
- ssmd/ssml_parser.py +599 -0
- ssmd/types.py +122 -0
- ssmd/utils.py +333 -0
- ssmd/xsampa_to_ipa.txt +174 -0
- ssmd-0.5.3.dist-info/METADATA +1210 -0
- ssmd-0.5.3.dist-info/RECORD +20 -0
- ssmd-0.5.3.dist-info/WHEEL +5 -0
- ssmd-0.5.3.dist-info/licenses/LICENSE +21 -0
- ssmd-0.5.3.dist-info/top_level.txt +1 -0
ssmd/__init__.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""SSMD - Speech Synthesis Markdown to SSML converter.
|
|
2
|
+
|
|
3
|
+
SSMD provides a lightweight markdown-like syntax for creating SSML
|
|
4
|
+
(Speech Synthesis Markup Language) documents. It's designed to be
|
|
5
|
+
more human-friendly than raw SSML while maintaining full compatibility.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
Basic usage::
|
|
9
|
+
|
|
10
|
+
import ssmd
|
|
11
|
+
|
|
12
|
+
# Create and build a document
|
|
13
|
+
doc = ssmd.Document()
|
|
14
|
+
doc.add_sentence("Hello *world*!")
|
|
15
|
+
doc.add_sentence("This is SSMD.")
|
|
16
|
+
|
|
17
|
+
# Export to different formats
|
|
18
|
+
ssml = doc.to_ssml()
|
|
19
|
+
text = doc.to_text()
|
|
20
|
+
|
|
21
|
+
# Or use convenience functions for one-off conversions
|
|
22
|
+
ssml = ssmd.to_ssml("Hello *world*!")
|
|
23
|
+
|
|
24
|
+
Advanced usage with streaming::
|
|
25
|
+
|
|
26
|
+
# Create parser with custom config
|
|
27
|
+
doc = ssmd.Document(
|
|
28
|
+
capabilities='pyttsx3',
|
|
29
|
+
config={'auto_sentence_tags': True}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Build document incrementally
|
|
33
|
+
doc.add_paragraph("# Welcome")
|
|
34
|
+
doc.add_sentence("Hello and *welcome* to SSMD!")
|
|
35
|
+
|
|
36
|
+
# Stream to TTS
|
|
37
|
+
for sentence in doc.sentences():
|
|
38
|
+
tts_engine.speak(sentence)
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
from typing import Any
|
|
42
|
+
|
|
43
|
+
from ssmd.document import Document
|
|
44
|
+
from ssmd.ssml_parser import SSMLParser
|
|
45
|
+
from ssmd.capabilities import (
|
|
46
|
+
TTSCapabilities,
|
|
47
|
+
get_preset,
|
|
48
|
+
ESPEAK_CAPABILITIES,
|
|
49
|
+
PYTTSX3_CAPABILITIES,
|
|
50
|
+
GOOGLE_TTS_CAPABILITIES,
|
|
51
|
+
AMAZON_POLLY_CAPABILITIES,
|
|
52
|
+
AZURE_TTS_CAPABILITIES,
|
|
53
|
+
MINIMAL_CAPABILITIES,
|
|
54
|
+
FULL_CAPABILITIES,
|
|
55
|
+
)
|
|
56
|
+
from ssmd.parser import (
|
|
57
|
+
parse_sentences,
|
|
58
|
+
parse_segments,
|
|
59
|
+
parse_voice_blocks,
|
|
60
|
+
)
|
|
61
|
+
from ssmd.parser_types import (
|
|
62
|
+
SSMDSegment,
|
|
63
|
+
SSMDSentence,
|
|
64
|
+
VoiceAttrs,
|
|
65
|
+
ProsodyAttrs,
|
|
66
|
+
BreakAttrs,
|
|
67
|
+
SayAsAttrs,
|
|
68
|
+
AudioAttrs,
|
|
69
|
+
PhonemeAttrs,
|
|
70
|
+
)
|
|
71
|
+
from ssmd.segment import Segment
|
|
72
|
+
from ssmd.sentence import Sentence
|
|
73
|
+
from ssmd.types import (
|
|
74
|
+
HeadingConfig,
|
|
75
|
+
DEFAULT_HEADING_LEVELS,
|
|
76
|
+
)
|
|
77
|
+
from ssmd.formatter import format_ssmd
|
|
78
|
+
from ssmd.utils import escape_ssmd_syntax, unescape_ssmd_syntax
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
from ssmd._version import version as __version__
|
|
82
|
+
except ImportError:
|
|
83
|
+
__version__ = "unknown"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# ═══════════════════════════════════════════════════════════
|
|
87
|
+
# CONVENIENCE FUNCTIONS
|
|
88
|
+
# ═══════════════════════════════════════════════════════════
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def to_ssml(ssmd_text: str, **config: Any) -> str:
|
|
92
|
+
"""Convert SSMD to SSML (convenience function).
|
|
93
|
+
|
|
94
|
+
Creates a temporary Document and converts to SSML.
|
|
95
|
+
For repeated conversions with the same config, create a Document instance.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
ssmd_text: SSMD markdown text
|
|
99
|
+
**config: Optional configuration parameters
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
SSML string
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
>>> ssmd.to_ssml("Hello *world*!")
|
|
106
|
+
'<speak>Hello <emphasis>world</emphasis>!</speak>'
|
|
107
|
+
"""
|
|
108
|
+
return Document(ssmd_text, config).to_ssml()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def to_text(ssmd_text: str, **config: Any) -> str:
|
|
112
|
+
"""Convert SSMD to plain text (convenience function).
|
|
113
|
+
|
|
114
|
+
Strips all SSMD markup, returning plain text.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
ssmd_text: SSMD markdown text
|
|
118
|
+
**config: Optional configuration parameters
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Plain text with markup removed
|
|
122
|
+
|
|
123
|
+
Example:
|
|
124
|
+
>>> ssmd.to_text("Hello *world* @marker!")
|
|
125
|
+
'Hello world!'
|
|
126
|
+
"""
|
|
127
|
+
return Document(ssmd_text, config).to_text()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def from_ssml(ssml_text: str, **config: Any) -> str:
|
|
131
|
+
"""Convert SSML to SSMD format (convenience function).
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
ssml_text: SSML XML string
|
|
135
|
+
**config: Optional configuration parameters
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
SSMD markdown string
|
|
139
|
+
|
|
140
|
+
Example:
|
|
141
|
+
>>> ssml = '<speak><emphasis>Hello</emphasis> world</speak>'
|
|
142
|
+
>>> ssmd.from_ssml(ssml)
|
|
143
|
+
'*Hello* world'
|
|
144
|
+
"""
|
|
145
|
+
parser = SSMLParser(config)
|
|
146
|
+
return parser.to_ssmd(ssml_text)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
__all__ = [
|
|
150
|
+
"Document",
|
|
151
|
+
"to_ssml",
|
|
152
|
+
"to_text",
|
|
153
|
+
"from_ssml",
|
|
154
|
+
"SSMLParser",
|
|
155
|
+
"TTSCapabilities",
|
|
156
|
+
"get_preset",
|
|
157
|
+
# Capability presets
|
|
158
|
+
"ESPEAK_CAPABILITIES",
|
|
159
|
+
"PYTTSX3_CAPABILITIES",
|
|
160
|
+
"GOOGLE_TTS_CAPABILITIES",
|
|
161
|
+
"AMAZON_POLLY_CAPABILITIES",
|
|
162
|
+
"AZURE_TTS_CAPABILITIES",
|
|
163
|
+
"MINIMAL_CAPABILITIES",
|
|
164
|
+
"FULL_CAPABILITIES",
|
|
165
|
+
# Parser functions
|
|
166
|
+
"parse_sentences",
|
|
167
|
+
"parse_segments",
|
|
168
|
+
"parse_voice_blocks",
|
|
169
|
+
"format_ssmd",
|
|
170
|
+
# Utility functions
|
|
171
|
+
"escape_ssmd_syntax",
|
|
172
|
+
"unescape_ssmd_syntax",
|
|
173
|
+
# New core classes
|
|
174
|
+
"Segment",
|
|
175
|
+
"Sentence",
|
|
176
|
+
# Types
|
|
177
|
+
"VoiceAttrs",
|
|
178
|
+
"ProsodyAttrs",
|
|
179
|
+
"BreakAttrs",
|
|
180
|
+
"SayAsAttrs",
|
|
181
|
+
"AudioAttrs",
|
|
182
|
+
"PhonemeAttrs",
|
|
183
|
+
"HeadingConfig",
|
|
184
|
+
"DEFAULT_HEADING_LEVELS",
|
|
185
|
+
# Backward compatibility aliases
|
|
186
|
+
"SSMDSegment",
|
|
187
|
+
"SSMDSentence",
|
|
188
|
+
"__version__",
|
|
189
|
+
]
|
ssmd/_version.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '0.5.3'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 5, 3)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
ssmd/capabilities.py
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"""TTS capability definitions and presets.
|
|
2
|
+
|
|
3
|
+
This module defines which SSML features are supported by various TTS engines
|
|
4
|
+
and provides capability-based filtering for SSMD processing.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TTSCapabilities:
|
|
11
|
+
"""Define TTS engine capabilities.
|
|
12
|
+
|
|
13
|
+
This class allows you to specify which SSML features your TTS engine
|
|
14
|
+
supports. Unsupported features will be automatically stripped to plain text.
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
|
+
>>> # Basic TTS with minimal support
|
|
18
|
+
>>> caps = TTSCapabilities(
|
|
19
|
+
... emphasis=False,
|
|
20
|
+
... break_tags=True,
|
|
21
|
+
... prosody=False
|
|
22
|
+
... )
|
|
23
|
+
>>>
|
|
24
|
+
>>> parser = SSMD(capabilities=caps)
|
|
25
|
+
>>> ssml = parser.to_ssml("Hello *world*!")
|
|
26
|
+
>>> # Output: <speak><p>Hello world!</p></speak>
|
|
27
|
+
>>> # (emphasis stripped because not supported)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
# Core features
|
|
33
|
+
emphasis: bool = True,
|
|
34
|
+
break_tags: bool = True,
|
|
35
|
+
paragraph: bool = True,
|
|
36
|
+
# Language & pronunciation
|
|
37
|
+
language: bool = True,
|
|
38
|
+
phoneme: bool = True,
|
|
39
|
+
substitution: bool = True,
|
|
40
|
+
# Prosody (volume, rate, pitch)
|
|
41
|
+
prosody: bool = True,
|
|
42
|
+
prosody_volume: bool = True,
|
|
43
|
+
prosody_rate: bool = True,
|
|
44
|
+
prosody_pitch: bool = True,
|
|
45
|
+
# Advanced features
|
|
46
|
+
say_as: bool = True,
|
|
47
|
+
audio: bool = True,
|
|
48
|
+
mark: bool = True,
|
|
49
|
+
# Extensions (platform-specific)
|
|
50
|
+
extensions: dict[str, bool] | None = None,
|
|
51
|
+
# Sentence and heading support
|
|
52
|
+
sentence_tags: bool = True,
|
|
53
|
+
heading_emphasis: bool = True,
|
|
54
|
+
):
|
|
55
|
+
"""Initialize TTS capabilities.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
emphasis: Support for <emphasis> tags
|
|
59
|
+
break_tags: Support for <break> tags
|
|
60
|
+
paragraph: Support for <p> tags
|
|
61
|
+
language: Support for <lang> tags
|
|
62
|
+
phoneme: Support for <phoneme> tags
|
|
63
|
+
substitution: Support for <sub> tags
|
|
64
|
+
prosody: Support for <prosody> tags (general)
|
|
65
|
+
prosody_volume: Support for volume attribute
|
|
66
|
+
prosody_rate: Support for rate attribute
|
|
67
|
+
prosody_pitch: Support for pitch attribute
|
|
68
|
+
say_as: Support for <say-as> tags
|
|
69
|
+
audio: Support for <audio> tags
|
|
70
|
+
mark: Support for <mark> tags
|
|
71
|
+
extensions: Dict of extension names and their support
|
|
72
|
+
sentence_tags: Support for <s> tags
|
|
73
|
+
heading_emphasis: Support for heading emphasis
|
|
74
|
+
"""
|
|
75
|
+
self.emphasis = emphasis
|
|
76
|
+
self.break_tags = break_tags
|
|
77
|
+
self.paragraph = paragraph
|
|
78
|
+
self.language = language
|
|
79
|
+
self.phoneme = phoneme
|
|
80
|
+
self.substitution = substitution
|
|
81
|
+
self.prosody = prosody
|
|
82
|
+
self.prosody_volume = prosody_volume and prosody
|
|
83
|
+
self.prosody_rate = prosody_rate and prosody
|
|
84
|
+
self.prosody_pitch = prosody_pitch and prosody
|
|
85
|
+
self.say_as = say_as
|
|
86
|
+
self.audio = audio
|
|
87
|
+
self.mark = mark
|
|
88
|
+
self.extensions = extensions or {}
|
|
89
|
+
self.sentence_tags = sentence_tags
|
|
90
|
+
self.heading_emphasis = heading_emphasis
|
|
91
|
+
|
|
92
|
+
def to_config(self) -> dict[str, Any]:
|
|
93
|
+
"""Convert capabilities to SSMD config.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Configuration dict for SSMD converter
|
|
97
|
+
"""
|
|
98
|
+
config: dict[str, Any] = {
|
|
99
|
+
"skip": [],
|
|
100
|
+
"capabilities": self,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# Skip processors for unsupported features
|
|
104
|
+
if not self.emphasis:
|
|
105
|
+
config["skip"].append("emphasis")
|
|
106
|
+
if not self.break_tags:
|
|
107
|
+
config["skip"].append("break")
|
|
108
|
+
if not self.paragraph:
|
|
109
|
+
config["skip"].append("paragraph")
|
|
110
|
+
if not self.mark:
|
|
111
|
+
config["skip"].append("mark")
|
|
112
|
+
|
|
113
|
+
# Prosody is handled specially (selective attributes)
|
|
114
|
+
if not self.prosody:
|
|
115
|
+
config["skip"].append("prosody")
|
|
116
|
+
|
|
117
|
+
# Headings handled by modifying heading_levels
|
|
118
|
+
if not self.heading_emphasis:
|
|
119
|
+
config["heading_levels"] = {} # No heading processing
|
|
120
|
+
|
|
121
|
+
return config
|
|
122
|
+
|
|
123
|
+
def supports_extension(self, extension_name: str) -> bool:
|
|
124
|
+
"""Check if an extension is supported.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
extension_name: Name of the extension
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
True if supported
|
|
131
|
+
"""
|
|
132
|
+
return self.extensions.get(extension_name, False)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# Preset capability definitions for common TTS engines
|
|
136
|
+
ESPEAK_CAPABILITIES = TTSCapabilities(
|
|
137
|
+
emphasis=False, # eSpeak doesn't support emphasis
|
|
138
|
+
break_tags=True,
|
|
139
|
+
paragraph=False, # eSpeak treats paragraphs as plain text
|
|
140
|
+
language=True,
|
|
141
|
+
phoneme=True, # eSpeak has good phoneme support
|
|
142
|
+
substitution=False,
|
|
143
|
+
prosody=True,
|
|
144
|
+
prosody_volume=True,
|
|
145
|
+
prosody_rate=True,
|
|
146
|
+
prosody_pitch=True,
|
|
147
|
+
say_as=False,
|
|
148
|
+
audio=False, # No audio file support
|
|
149
|
+
mark=False,
|
|
150
|
+
sentence_tags=False,
|
|
151
|
+
heading_emphasis=False,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
PYTTSX3_CAPABILITIES = TTSCapabilities(
|
|
155
|
+
emphasis=False, # pyttsx3 has minimal SSML support
|
|
156
|
+
break_tags=False,
|
|
157
|
+
paragraph=False,
|
|
158
|
+
language=False, # Voice selection, not SSML
|
|
159
|
+
phoneme=False,
|
|
160
|
+
substitution=False,
|
|
161
|
+
prosody=True, # Via properties, not SSML
|
|
162
|
+
prosody_volume=True,
|
|
163
|
+
prosody_rate=True,
|
|
164
|
+
prosody_pitch=False,
|
|
165
|
+
say_as=False,
|
|
166
|
+
audio=False,
|
|
167
|
+
mark=False,
|
|
168
|
+
sentence_tags=False,
|
|
169
|
+
heading_emphasis=False,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
GOOGLE_TTS_CAPABILITIES = TTSCapabilities(
|
|
173
|
+
emphasis=True,
|
|
174
|
+
break_tags=True,
|
|
175
|
+
paragraph=True,
|
|
176
|
+
language=True,
|
|
177
|
+
phoneme=True,
|
|
178
|
+
substitution=True,
|
|
179
|
+
prosody=True,
|
|
180
|
+
prosody_volume=True,
|
|
181
|
+
prosody_rate=True,
|
|
182
|
+
prosody_pitch=True,
|
|
183
|
+
say_as=True,
|
|
184
|
+
audio=True,
|
|
185
|
+
mark=True,
|
|
186
|
+
sentence_tags=True,
|
|
187
|
+
heading_emphasis=True,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
AMAZON_POLLY_CAPABILITIES = TTSCapabilities(
|
|
191
|
+
emphasis=True,
|
|
192
|
+
break_tags=True,
|
|
193
|
+
paragraph=True,
|
|
194
|
+
language=True,
|
|
195
|
+
phoneme=True,
|
|
196
|
+
substitution=True,
|
|
197
|
+
prosody=True,
|
|
198
|
+
prosody_volume=True,
|
|
199
|
+
prosody_rate=True,
|
|
200
|
+
prosody_pitch=True,
|
|
201
|
+
say_as=True,
|
|
202
|
+
audio=False, # Limited audio support
|
|
203
|
+
mark=True,
|
|
204
|
+
extensions={"whisper": True, "drc": True}, # Amazon-specific
|
|
205
|
+
sentence_tags=True,
|
|
206
|
+
heading_emphasis=True,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
AZURE_TTS_CAPABILITIES = TTSCapabilities(
|
|
210
|
+
emphasis=True,
|
|
211
|
+
break_tags=True,
|
|
212
|
+
paragraph=True,
|
|
213
|
+
language=True,
|
|
214
|
+
phoneme=True,
|
|
215
|
+
substitution=True,
|
|
216
|
+
prosody=True,
|
|
217
|
+
prosody_volume=True,
|
|
218
|
+
prosody_rate=True,
|
|
219
|
+
prosody_pitch=True,
|
|
220
|
+
say_as=True,
|
|
221
|
+
audio=True,
|
|
222
|
+
mark=True,
|
|
223
|
+
sentence_tags=True,
|
|
224
|
+
heading_emphasis=True,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Minimal fallback (plain text only)
|
|
228
|
+
MINIMAL_CAPABILITIES = TTSCapabilities(
|
|
229
|
+
emphasis=False,
|
|
230
|
+
break_tags=False,
|
|
231
|
+
paragraph=False,
|
|
232
|
+
language=False,
|
|
233
|
+
phoneme=False,
|
|
234
|
+
substitution=False,
|
|
235
|
+
prosody=False,
|
|
236
|
+
say_as=False,
|
|
237
|
+
audio=False,
|
|
238
|
+
mark=False,
|
|
239
|
+
sentence_tags=False,
|
|
240
|
+
heading_emphasis=False,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# Full SSML support (reference)
|
|
244
|
+
FULL_CAPABILITIES = TTSCapabilities()
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# Preset lookup
|
|
248
|
+
PRESETS: dict[str, TTSCapabilities] = {
|
|
249
|
+
"espeak": ESPEAK_CAPABILITIES,
|
|
250
|
+
"pyttsx3": PYTTSX3_CAPABILITIES,
|
|
251
|
+
"google": GOOGLE_TTS_CAPABILITIES,
|
|
252
|
+
"polly": AMAZON_POLLY_CAPABILITIES,
|
|
253
|
+
"amazon": AMAZON_POLLY_CAPABILITIES,
|
|
254
|
+
"azure": AZURE_TTS_CAPABILITIES,
|
|
255
|
+
"microsoft": AZURE_TTS_CAPABILITIES,
|
|
256
|
+
"minimal": MINIMAL_CAPABILITIES,
|
|
257
|
+
"full": FULL_CAPABILITIES,
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def get_preset(name: str) -> TTSCapabilities:
|
|
262
|
+
"""Get a preset capability configuration.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
name: Preset name (espeak, pyttsx3, google, polly, azure, minimal, full)
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
TTSCapabilities instance
|
|
269
|
+
|
|
270
|
+
Raises:
|
|
271
|
+
ValueError: If preset not found
|
|
272
|
+
"""
|
|
273
|
+
if name.lower() not in PRESETS:
|
|
274
|
+
available = ", ".join(PRESETS.keys())
|
|
275
|
+
raise ValueError(f"Unknown preset '{name}'. Available: {available}")
|
|
276
|
+
|
|
277
|
+
return PRESETS[name.lower()]
|