wyoming-microsoft-tts 1.3.5__py3-none-any.whl → 1.4.0__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.
- tests/conftest.py +5 -0
- tests/test_microsoft_tts.py +335 -0
- wyoming_microsoft_tts/__main__.py +26 -0
- wyoming_microsoft_tts/microsoft_tts.py +54 -1
- wyoming_microsoft_tts/version.py +1 -1
- {wyoming_microsoft_tts-1.3.5.dist-info → wyoming_microsoft_tts-1.4.0.dist-info}/METADATA +1 -1
- wyoming_microsoft_tts-1.4.0.dist-info/RECORD +17 -0
- {wyoming_microsoft_tts-1.3.5.dist-info → wyoming_microsoft_tts-1.4.0.dist-info}/WHEEL +1 -1
- wyoming_microsoft_tts-1.3.5.dist-info/RECORD +0 -17
- {wyoming_microsoft_tts-1.3.5.dist-info → wyoming_microsoft_tts-1.4.0.dist-info}/top_level.txt +0 -0
tests/conftest.py
CHANGED
|
@@ -21,6 +21,11 @@ def microsoft_tts(configuration):
|
|
|
21
21
|
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
22
22
|
service_region=os.environ.get("SPEECH_REGION"),
|
|
23
23
|
download_dir="/tmp/",
|
|
24
|
+
rate=None,
|
|
25
|
+
pitch=None,
|
|
26
|
+
volume=None,
|
|
27
|
+
style=None,
|
|
28
|
+
style_degree=None,
|
|
24
29
|
**configuration,
|
|
25
30
|
)
|
|
26
31
|
return MicrosoftTTS(args)
|
tests/test_microsoft_tts.py
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
"""Tests for the MicrosoftTTS class."""
|
|
2
2
|
|
|
3
|
+
from types import SimpleNamespace
|
|
4
|
+
import os
|
|
5
|
+
import pytest
|
|
6
|
+
from wyoming_microsoft_tts.microsoft_tts import MicrosoftTTS
|
|
7
|
+
|
|
3
8
|
|
|
4
9
|
def test_initialize(microsoft_tts, configuration):
|
|
5
10
|
"""Test initialization."""
|
|
@@ -8,6 +13,10 @@ def test_initialize(microsoft_tts, configuration):
|
|
|
8
13
|
assert microsoft_tts.output_dir is not None
|
|
9
14
|
|
|
10
15
|
|
|
16
|
+
@pytest.mark.skipif(
|
|
17
|
+
not os.environ.get("SPEECH_KEY") or not os.environ.get("SPEECH_REGION"),
|
|
18
|
+
reason="SPEECH_KEY and SPEECH_REGION environment variables required",
|
|
19
|
+
)
|
|
11
20
|
def test_synthesize(microsoft_tts):
|
|
12
21
|
"""Test synthesize."""
|
|
13
22
|
text = "Hello, world!"
|
|
@@ -15,3 +24,329 @@ def test_synthesize(microsoft_tts):
|
|
|
15
24
|
|
|
16
25
|
result = microsoft_tts.synthesize(text, voice)
|
|
17
26
|
assert result.endswith(".wav")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# SSML Building Tests
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_build_ssml_with_rate():
|
|
33
|
+
"""Test SSML generation with rate parameter."""
|
|
34
|
+
args = SimpleNamespace(
|
|
35
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
36
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
37
|
+
download_dir="/tmp/",
|
|
38
|
+
voice="en-US-JennyNeural",
|
|
39
|
+
rate="+30%",
|
|
40
|
+
pitch=None,
|
|
41
|
+
volume=None,
|
|
42
|
+
style=None,
|
|
43
|
+
style_degree=None,
|
|
44
|
+
)
|
|
45
|
+
tts = MicrosoftTTS(args)
|
|
46
|
+
ssml = tts._build_ssml("Hello, world!", "en-US-JennyNeural")
|
|
47
|
+
|
|
48
|
+
assert '<?xml version="1.0" encoding="UTF-8"?>' in ssml
|
|
49
|
+
assert '<speak version="1.0"' in ssml
|
|
50
|
+
assert '<prosody rate="+30%">' in ssml
|
|
51
|
+
assert "</prosody>" in ssml
|
|
52
|
+
assert "Hello, world!" in ssml
|
|
53
|
+
assert "xmlns:mstts" not in ssml # No style, so no mstts namespace
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_build_ssml_with_pitch():
|
|
57
|
+
"""Test SSML generation with pitch parameter."""
|
|
58
|
+
args = SimpleNamespace(
|
|
59
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
60
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
61
|
+
download_dir="/tmp/",
|
|
62
|
+
voice="en-US-JennyNeural",
|
|
63
|
+
rate=None,
|
|
64
|
+
pitch="+10%",
|
|
65
|
+
volume=None,
|
|
66
|
+
style=None,
|
|
67
|
+
style_degree=None,
|
|
68
|
+
)
|
|
69
|
+
tts = MicrosoftTTS(args)
|
|
70
|
+
ssml = tts._build_ssml("Testing pitch", "en-US-JennyNeural")
|
|
71
|
+
|
|
72
|
+
assert '<prosody pitch="+10%">' in ssml
|
|
73
|
+
assert "</prosody>" in ssml
|
|
74
|
+
assert "Testing pitch" in ssml
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_build_ssml_with_volume():
|
|
78
|
+
"""Test SSML generation with volume parameter."""
|
|
79
|
+
args = SimpleNamespace(
|
|
80
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
81
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
82
|
+
download_dir="/tmp/",
|
|
83
|
+
voice="en-US-JennyNeural",
|
|
84
|
+
rate=None,
|
|
85
|
+
pitch=None,
|
|
86
|
+
volume="loud",
|
|
87
|
+
style=None,
|
|
88
|
+
style_degree=None,
|
|
89
|
+
)
|
|
90
|
+
tts = MicrosoftTTS(args)
|
|
91
|
+
ssml = tts._build_ssml("Volume test", "en-US-JennyNeural")
|
|
92
|
+
|
|
93
|
+
assert '<prosody volume="loud">' in ssml
|
|
94
|
+
assert "</prosody>" in ssml
|
|
95
|
+
assert "Volume test" in ssml
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_build_ssml_with_all_prosody():
|
|
99
|
+
"""Test SSML generation with all prosody parameters."""
|
|
100
|
+
args = SimpleNamespace(
|
|
101
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
102
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
103
|
+
download_dir="/tmp/",
|
|
104
|
+
voice="en-US-JennyNeural",
|
|
105
|
+
rate="fast",
|
|
106
|
+
pitch="high",
|
|
107
|
+
volume="+20%",
|
|
108
|
+
style=None,
|
|
109
|
+
style_degree=None,
|
|
110
|
+
)
|
|
111
|
+
tts = MicrosoftTTS(args)
|
|
112
|
+
ssml = tts._build_ssml("All prosody", "en-US-JennyNeural")
|
|
113
|
+
|
|
114
|
+
assert '<prosody rate="fast" pitch="high" volume="+20%">' in ssml
|
|
115
|
+
assert "</prosody>" in ssml
|
|
116
|
+
assert "All prosody" in ssml
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_build_ssml_with_style():
|
|
120
|
+
"""Test SSML generation with style parameter."""
|
|
121
|
+
args = SimpleNamespace(
|
|
122
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
123
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
124
|
+
download_dir="/tmp/",
|
|
125
|
+
voice="en-US-JennyNeural",
|
|
126
|
+
rate=None,
|
|
127
|
+
pitch=None,
|
|
128
|
+
volume=None,
|
|
129
|
+
style="cheerful",
|
|
130
|
+
style_degree=None,
|
|
131
|
+
)
|
|
132
|
+
tts = MicrosoftTTS(args)
|
|
133
|
+
ssml = tts._build_ssml("Style test", "en-US-JennyNeural")
|
|
134
|
+
|
|
135
|
+
assert 'xmlns:mstts="https://www.w3.org/2001/mstts"' in ssml
|
|
136
|
+
assert '<mstts:express-as style="cheerful">' in ssml
|
|
137
|
+
assert "</mstts:express-as>" in ssml
|
|
138
|
+
assert "Style test" in ssml
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_build_ssml_with_style_and_degree():
|
|
142
|
+
"""Test SSML generation with style and style_degree parameters."""
|
|
143
|
+
args = SimpleNamespace(
|
|
144
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
145
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
146
|
+
download_dir="/tmp/",
|
|
147
|
+
voice="en-US-JennyNeural",
|
|
148
|
+
rate=None,
|
|
149
|
+
pitch=None,
|
|
150
|
+
volume=None,
|
|
151
|
+
style="sad",
|
|
152
|
+
style_degree=1.5,
|
|
153
|
+
)
|
|
154
|
+
tts = MicrosoftTTS(args)
|
|
155
|
+
ssml = tts._build_ssml("Sad voice", "en-US-JennyNeural")
|
|
156
|
+
|
|
157
|
+
assert 'xmlns:mstts="https://www.w3.org/2001/mstts"' in ssml
|
|
158
|
+
assert '<mstts:express-as style="sad" styledegree="1.5">' in ssml
|
|
159
|
+
assert "</mstts:express-as>" in ssml
|
|
160
|
+
assert "Sad voice" in ssml
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_build_ssml_with_prosody_and_style():
|
|
164
|
+
"""Test SSML generation with both prosody and style parameters."""
|
|
165
|
+
args = SimpleNamespace(
|
|
166
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
167
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
168
|
+
download_dir="/tmp/",
|
|
169
|
+
voice="en-US-JennyNeural",
|
|
170
|
+
rate="slow",
|
|
171
|
+
pitch="low",
|
|
172
|
+
volume="soft",
|
|
173
|
+
style="calm",
|
|
174
|
+
style_degree=0.5,
|
|
175
|
+
)
|
|
176
|
+
tts = MicrosoftTTS(args)
|
|
177
|
+
ssml = tts._build_ssml("Combined test", "en-US-JennyNeural")
|
|
178
|
+
|
|
179
|
+
assert 'xmlns:mstts="https://www.w3.org/2001/mstts"' in ssml
|
|
180
|
+
assert '<mstts:express-as style="calm" styledegree="0.5">' in ssml
|
|
181
|
+
assert '<prosody rate="slow" pitch="low" volume="soft">' in ssml
|
|
182
|
+
assert "</prosody>" in ssml
|
|
183
|
+
assert "</mstts:express-as>" in ssml
|
|
184
|
+
assert "Combined test" in ssml
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def test_build_ssml_voice_key_and_lang():
|
|
188
|
+
"""Test that SSML uses correct voice key and language."""
|
|
189
|
+
args = SimpleNamespace(
|
|
190
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
191
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
192
|
+
download_dir="/tmp/",
|
|
193
|
+
voice="en-GB-SoniaNeural",
|
|
194
|
+
rate="+10%",
|
|
195
|
+
pitch=None,
|
|
196
|
+
volume=None,
|
|
197
|
+
style=None,
|
|
198
|
+
style_degree=None,
|
|
199
|
+
)
|
|
200
|
+
tts = MicrosoftTTS(args)
|
|
201
|
+
ssml = tts._build_ssml("UK voice", "en-GB-SoniaNeural")
|
|
202
|
+
|
|
203
|
+
# Should contain the voice key from the voices.json
|
|
204
|
+
assert 'xml:lang="en-GB"' in ssml
|
|
205
|
+
assert '<voice name="en-GB-SoniaNeural">' in ssml
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
# Integration Tests with Synthesize
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@pytest.mark.skipif(
|
|
212
|
+
not os.environ.get("SPEECH_KEY") or not os.environ.get("SPEECH_REGION"),
|
|
213
|
+
reason="SPEECH_KEY and SPEECH_REGION environment variables required",
|
|
214
|
+
)
|
|
215
|
+
def test_synthesize_with_rate():
|
|
216
|
+
"""Test synthesize with rate parameter."""
|
|
217
|
+
args = SimpleNamespace(
|
|
218
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
219
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
220
|
+
download_dir="/tmp/",
|
|
221
|
+
voice="en-US-JennyNeural",
|
|
222
|
+
rate="+30%",
|
|
223
|
+
pitch=None,
|
|
224
|
+
volume=None,
|
|
225
|
+
style=None,
|
|
226
|
+
style_degree=None,
|
|
227
|
+
)
|
|
228
|
+
tts = MicrosoftTTS(args)
|
|
229
|
+
result = tts.synthesize("Testing rate parameter", "en-US-JennyNeural")
|
|
230
|
+
|
|
231
|
+
assert result is not None
|
|
232
|
+
assert result.endswith(".wav")
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@pytest.mark.skipif(
|
|
236
|
+
not os.environ.get("SPEECH_KEY") or not os.environ.get("SPEECH_REGION"),
|
|
237
|
+
reason="SPEECH_KEY and SPEECH_REGION environment variables required",
|
|
238
|
+
)
|
|
239
|
+
def test_synthesize_with_pitch():
|
|
240
|
+
"""Test synthesize with pitch parameter."""
|
|
241
|
+
args = SimpleNamespace(
|
|
242
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
243
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
244
|
+
download_dir="/tmp/",
|
|
245
|
+
voice="en-US-JennyNeural",
|
|
246
|
+
rate=None,
|
|
247
|
+
pitch="+5%",
|
|
248
|
+
volume=None,
|
|
249
|
+
style=None,
|
|
250
|
+
style_degree=None,
|
|
251
|
+
)
|
|
252
|
+
tts = MicrosoftTTS(args)
|
|
253
|
+
result = tts.synthesize("Testing pitch parameter", "en-US-JennyNeural")
|
|
254
|
+
|
|
255
|
+
assert result is not None
|
|
256
|
+
assert result.endswith(".wav")
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
@pytest.mark.skipif(
|
|
260
|
+
not os.environ.get("SPEECH_KEY") or not os.environ.get("SPEECH_REGION"),
|
|
261
|
+
reason="SPEECH_KEY and SPEECH_REGION environment variables required",
|
|
262
|
+
)
|
|
263
|
+
def test_synthesize_with_volume():
|
|
264
|
+
"""Test synthesize with volume parameter."""
|
|
265
|
+
args = SimpleNamespace(
|
|
266
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
267
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
268
|
+
download_dir="/tmp/",
|
|
269
|
+
voice="en-US-JennyNeural",
|
|
270
|
+
rate=None,
|
|
271
|
+
pitch=None,
|
|
272
|
+
volume="loud",
|
|
273
|
+
style=None,
|
|
274
|
+
style_degree=None,
|
|
275
|
+
)
|
|
276
|
+
tts = MicrosoftTTS(args)
|
|
277
|
+
result = tts.synthesize("Testing volume parameter", "en-US-JennyNeural")
|
|
278
|
+
|
|
279
|
+
assert result is not None
|
|
280
|
+
assert result.endswith(".wav")
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
@pytest.mark.skipif(
|
|
284
|
+
not os.environ.get("SPEECH_KEY") or not os.environ.get("SPEECH_REGION"),
|
|
285
|
+
reason="SPEECH_KEY and SPEECH_REGION environment variables required",
|
|
286
|
+
)
|
|
287
|
+
def test_synthesize_with_style():
|
|
288
|
+
"""Test synthesize with style parameter."""
|
|
289
|
+
args = SimpleNamespace(
|
|
290
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
291
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
292
|
+
download_dir="/tmp/",
|
|
293
|
+
voice="en-US-JennyNeural",
|
|
294
|
+
rate=None,
|
|
295
|
+
pitch=None,
|
|
296
|
+
volume=None,
|
|
297
|
+
style="cheerful",
|
|
298
|
+
style_degree=None,
|
|
299
|
+
)
|
|
300
|
+
tts = MicrosoftTTS(args)
|
|
301
|
+
result = tts.synthesize("Testing style parameter", "en-US-JennyNeural")
|
|
302
|
+
|
|
303
|
+
assert result is not None
|
|
304
|
+
assert result.endswith(".wav")
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
@pytest.mark.skipif(
|
|
308
|
+
not os.environ.get("SPEECH_KEY") or not os.environ.get("SPEECH_REGION"),
|
|
309
|
+
reason="SPEECH_KEY and SPEECH_REGION environment variables required",
|
|
310
|
+
)
|
|
311
|
+
def test_synthesize_with_combined_parameters():
|
|
312
|
+
"""Test synthesize with multiple parameters combined."""
|
|
313
|
+
args = SimpleNamespace(
|
|
314
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
315
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
316
|
+
download_dir="/tmp/",
|
|
317
|
+
voice="en-US-JennyNeural",
|
|
318
|
+
rate="fast",
|
|
319
|
+
pitch="+10%",
|
|
320
|
+
volume="loud",
|
|
321
|
+
style="excited",
|
|
322
|
+
style_degree=1.2,
|
|
323
|
+
)
|
|
324
|
+
tts = MicrosoftTTS(args)
|
|
325
|
+
result = tts.synthesize("Testing all parameters together", "en-US-JennyNeural")
|
|
326
|
+
|
|
327
|
+
assert result is not None
|
|
328
|
+
assert result.endswith(".wav")
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
@pytest.mark.skipif(
|
|
332
|
+
not os.environ.get("SPEECH_KEY") or not os.environ.get("SPEECH_REGION"),
|
|
333
|
+
reason="SPEECH_KEY and SPEECH_REGION environment variables required",
|
|
334
|
+
)
|
|
335
|
+
def test_synthesize_without_parameters_still_works():
|
|
336
|
+
"""Test that synthesize still works without any new parameters."""
|
|
337
|
+
args = SimpleNamespace(
|
|
338
|
+
subscription_key=os.environ.get("SPEECH_KEY"),
|
|
339
|
+
service_region=os.environ.get("SPEECH_REGION"),
|
|
340
|
+
download_dir="/tmp/",
|
|
341
|
+
voice="en-US-JennyNeural",
|
|
342
|
+
rate=None,
|
|
343
|
+
pitch=None,
|
|
344
|
+
volume=None,
|
|
345
|
+
style=None,
|
|
346
|
+
style_degree=None,
|
|
347
|
+
)
|
|
348
|
+
tts = MicrosoftTTS(args)
|
|
349
|
+
result = tts.synthesize("Testing without parameters", "en-US-JennyNeural")
|
|
350
|
+
|
|
351
|
+
assert result is not None
|
|
352
|
+
assert result.endswith(".wav")
|
|
@@ -68,6 +68,32 @@ def parse_arguments():
|
|
|
68
68
|
)
|
|
69
69
|
parser.add_argument("--samples-per-chunk", type=int, default=1024)
|
|
70
70
|
#
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"--rate",
|
|
73
|
+
type=str,
|
|
74
|
+
help="Speech rate (e.g., '+30%', '0.5', 'fast', 'slow')",
|
|
75
|
+
)
|
|
76
|
+
parser.add_argument(
|
|
77
|
+
"--pitch",
|
|
78
|
+
type=str,
|
|
79
|
+
help="Speech pitch (e.g., '+10%', 'high', 'low', '+80Hz')",
|
|
80
|
+
)
|
|
81
|
+
parser.add_argument(
|
|
82
|
+
"--volume",
|
|
83
|
+
type=str,
|
|
84
|
+
help="Speech volume (e.g., '+20%', 'loud', 'soft', '75')",
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
"--style",
|
|
88
|
+
type=str,
|
|
89
|
+
help="Speaking style (e.g., 'cheerful', 'sad', 'angry', 'calm')",
|
|
90
|
+
)
|
|
91
|
+
parser.add_argument(
|
|
92
|
+
"--style-degree",
|
|
93
|
+
type=float,
|
|
94
|
+
help="Style intensity from 0.01 to 2 (default: 1)",
|
|
95
|
+
)
|
|
96
|
+
#
|
|
71
97
|
parser.add_argument(
|
|
72
98
|
"--update-voices",
|
|
73
99
|
action="store_true",
|
|
@@ -30,6 +30,54 @@ class MicrosoftTTS:
|
|
|
30
30
|
|
|
31
31
|
self.voices = get_voices(args.download_dir)
|
|
32
32
|
|
|
33
|
+
def _build_ssml(self, text, voice):
|
|
34
|
+
"""Build SSML with prosody and style parameters."""
|
|
35
|
+
voice_key = self.voices[voice]["key"]
|
|
36
|
+
voice_lang = self.voices[voice]["language"]["code"]
|
|
37
|
+
|
|
38
|
+
ssml_parts = [
|
|
39
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
40
|
+
'<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis"',
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
if self.args.style or self.args.style_degree:
|
|
44
|
+
ssml_parts.append(' xmlns:mstts="https://www.w3.org/2001/mstts"')
|
|
45
|
+
|
|
46
|
+
ssml_parts.append(f' xml:lang="{voice_lang}">')
|
|
47
|
+
ssml_parts.append(f'<voice name="{voice_key}">')
|
|
48
|
+
|
|
49
|
+
has_style = self.args.style is not None
|
|
50
|
+
has_prosody = any([self.args.rate, self.args.pitch, self.args.volume])
|
|
51
|
+
|
|
52
|
+
if has_style:
|
|
53
|
+
style_attrs = [f'style="{self.args.style}"']
|
|
54
|
+
if self.args.style_degree is not None:
|
|
55
|
+
style_attrs.append(f'styledegree="{self.args.style_degree}"')
|
|
56
|
+
ssml_parts.append(f'<mstts:express-as {" ".join(style_attrs)}>')
|
|
57
|
+
|
|
58
|
+
if has_prosody:
|
|
59
|
+
prosody_attrs = []
|
|
60
|
+
if self.args.rate:
|
|
61
|
+
prosody_attrs.append(f'rate="{self.args.rate}"')
|
|
62
|
+
if self.args.pitch:
|
|
63
|
+
prosody_attrs.append(f'pitch="{self.args.pitch}"')
|
|
64
|
+
if self.args.volume:
|
|
65
|
+
prosody_attrs.append(f'volume="{self.args.volume}"')
|
|
66
|
+
ssml_parts.append(f'<prosody {" ".join(prosody_attrs)}>')
|
|
67
|
+
|
|
68
|
+
ssml_parts.append(text)
|
|
69
|
+
|
|
70
|
+
if has_prosody:
|
|
71
|
+
ssml_parts.append('</prosody>')
|
|
72
|
+
|
|
73
|
+
if has_style:
|
|
74
|
+
ssml_parts.append('</mstts:express-as>')
|
|
75
|
+
|
|
76
|
+
ssml_parts.append('</voice>')
|
|
77
|
+
ssml_parts.append('</speak>')
|
|
78
|
+
|
|
79
|
+
return ''.join(ssml_parts)
|
|
80
|
+
|
|
33
81
|
def synthesize(self, text, voice=None):
|
|
34
82
|
"""Synthesize text to speech."""
|
|
35
83
|
_LOGGER.debug(f"Requested TTS for [{text}]")
|
|
@@ -46,7 +94,12 @@ class MicrosoftTTS:
|
|
|
46
94
|
speech_config=self.speech_config, audio_config=audio_config
|
|
47
95
|
)
|
|
48
96
|
|
|
49
|
-
|
|
97
|
+
if any([self.args.rate, self.args.pitch, self.args.volume, self.args.style, self.args.style_degree]):
|
|
98
|
+
ssml = self._build_ssml(text, voice)
|
|
99
|
+
_LOGGER.debug(f"Using SSML: {ssml}")
|
|
100
|
+
speech_synthesis_result = speech_synthesizer.speak_ssml_async(ssml).get()
|
|
101
|
+
else:
|
|
102
|
+
speech_synthesis_result = speech_synthesizer.speak_text_async(text).get()
|
|
50
103
|
|
|
51
104
|
if (
|
|
52
105
|
speech_synthesis_result.reason
|
wyoming_microsoft_tts/version.py
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
tests/__init__.py,sha256=ZEU8_ARBRGIqaAOTcPRsjXxcfHSojBm-5-krYBN-68g,13
|
|
2
|
+
tests/conftest.py,sha256=urfFKfWMHPOEE-4iCLtlCfYrgGGzXx1d6xPQHGp4vvY,703
|
|
3
|
+
tests/test_download.py,sha256=HUyzGqKlDxUkJBTjUHDMNYvbUVfdx8QLjqhkJbd_UoQ,2689
|
|
4
|
+
tests/test_microsoft_tts.py,sha256=2yhV3xFhLZqg3JSVm7XciVp0t5xhFD0h15eX82V2Jrc,11040
|
|
5
|
+
tests/test_voice_parsing.py,sha256=omJl9N6A4e8SGtDSY9QE5WlzeYBHoh2F2pQsw5sScKU,5877
|
|
6
|
+
wyoming_microsoft_tts/__init__.py,sha256=pjzj_kylPQkVCdCNrV8Po_ficSmwWCmK-JNVn7SEI3U,40
|
|
7
|
+
wyoming_microsoft_tts/__main__.py,sha256=0a2CBue3mCSq5Wj-lZPaA3Zde2_b8XlrtdzGYpHZ7sM,7275
|
|
8
|
+
wyoming_microsoft_tts/download.py,sha256=gDelH36JU6nXLIwdkeSKLl2YbgdaPCNwWI87WZP2s4Y,6634
|
|
9
|
+
wyoming_microsoft_tts/handler.py,sha256=no4hzSccT6H9lQVzsDa6sCj6nBDeodsnbusFUJDIk04,6347
|
|
10
|
+
wyoming_microsoft_tts/microsoft_tts.py,sha256=l8XJADhwXTJpVr5V5mmWFZIkMuiZvv2h6HoafT2YHKc,4234
|
|
11
|
+
wyoming_microsoft_tts/sentence_boundary.py,sha256=zkQDjlpI0PIvdXyn-OA7sbxIQOcSRSZMt04R1Yyc6Ww,2102
|
|
12
|
+
wyoming_microsoft_tts/version.py,sha256=qxHWlb-iQ67EQiokkikRMGSKWQTuw9zhBqRC1vooji0,50
|
|
13
|
+
wyoming_microsoft_tts/voices.json,sha256=1msC7a0p7iUkNW31z_6o_PD8Ub_KD-of9ac7PqbT06M,291733
|
|
14
|
+
wyoming_microsoft_tts-1.4.0.dist-info/METADATA,sha256=pjSVSaJzhEyckA58Bhu7wIlLtk7i-HXUIyAbcgeuJLs,5544
|
|
15
|
+
wyoming_microsoft_tts-1.4.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
16
|
+
wyoming_microsoft_tts-1.4.0.dist-info/top_level.txt,sha256=Bz4WwowTNLkDogmWBnBXeOx0GgJGe2nLHX4h9HZRBf4,28
|
|
17
|
+
wyoming_microsoft_tts-1.4.0.dist-info/RECORD,,
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
tests/__init__.py,sha256=ZEU8_ARBRGIqaAOTcPRsjXxcfHSojBm-5-krYBN-68g,13
|
|
2
|
-
tests/conftest.py,sha256=a_yG0zphFIa5ITijg-KTeyI4EJVC2vfKqIuHnsFFKFo,596
|
|
3
|
-
tests/test_download.py,sha256=HUyzGqKlDxUkJBTjUHDMNYvbUVfdx8QLjqhkJbd_UoQ,2689
|
|
4
|
-
tests/test_microsoft_tts.py,sha256=5Bfhj4b_gfcTe3UhKVVxLDVXasqyx1dVadFfbrtijuU,496
|
|
5
|
-
tests/test_voice_parsing.py,sha256=omJl9N6A4e8SGtDSY9QE5WlzeYBHoh2F2pQsw5sScKU,5877
|
|
6
|
-
wyoming_microsoft_tts/__init__.py,sha256=pjzj_kylPQkVCdCNrV8Po_ficSmwWCmK-JNVn7SEI3U,40
|
|
7
|
-
wyoming_microsoft_tts/__main__.py,sha256=ahsN8gUlN8qNmz_-fcR68CjFPkhoVzYaYzz_PQ4SXQo,6585
|
|
8
|
-
wyoming_microsoft_tts/download.py,sha256=gDelH36JU6nXLIwdkeSKLl2YbgdaPCNwWI87WZP2s4Y,6634
|
|
9
|
-
wyoming_microsoft_tts/handler.py,sha256=no4hzSccT6H9lQVzsDa6sCj6nBDeodsnbusFUJDIk04,6347
|
|
10
|
-
wyoming_microsoft_tts/microsoft_tts.py,sha256=dkTP_dLc6GSipzHptRS7NHX1IWwunFs_EZa29p_7-l4,2172
|
|
11
|
-
wyoming_microsoft_tts/sentence_boundary.py,sha256=zkQDjlpI0PIvdXyn-OA7sbxIQOcSRSZMt04R1Yyc6Ww,2102
|
|
12
|
-
wyoming_microsoft_tts/version.py,sha256=gts4Ey8VuhlTJIs3BIfbiqe_Ow6m1nRUoVq7-gI9q6A,50
|
|
13
|
-
wyoming_microsoft_tts/voices.json,sha256=1msC7a0p7iUkNW31z_6o_PD8Ub_KD-of9ac7PqbT06M,291733
|
|
14
|
-
wyoming_microsoft_tts-1.3.5.dist-info/METADATA,sha256=1SwWHP9gcJADARyMvU-d3z6KttrJW7HMg8OkLTCdtyE,5544
|
|
15
|
-
wyoming_microsoft_tts-1.3.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
16
|
-
wyoming_microsoft_tts-1.3.5.dist-info/top_level.txt,sha256=Bz4WwowTNLkDogmWBnBXeOx0GgJGe2nLHX4h9HZRBf4,28
|
|
17
|
-
wyoming_microsoft_tts-1.3.5.dist-info/RECORD,,
|
{wyoming_microsoft_tts-1.3.5.dist-info → wyoming_microsoft_tts-1.4.0.dist-info}/top_level.txt
RENAMED
|
File without changes
|