murf 1.0.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.
- murf/__init__.py +49 -0
- murf/auth/__init__.py +2 -0
- murf/auth/client.py +175 -0
- murf/base_client.py +144 -0
- murf/client.py +118 -0
- murf/core/__init__.py +47 -0
- murf/core/api_error.py +15 -0
- murf/core/client_wrapper.py +65 -0
- murf/core/datetime_utils.py +28 -0
- murf/core/file.py +67 -0
- murf/core/http_client.py +499 -0
- murf/core/jsonable_encoder.py +101 -0
- murf/core/pydantic_utilities.py +296 -0
- murf/core/query_encoder.py +58 -0
- murf/core/remove_none_from_dict.py +11 -0
- murf/core/request_options.py +35 -0
- murf/core/serialization.py +272 -0
- murf/environment.py +7 -0
- murf/errors/__init__.py +17 -0
- murf/errors/bad_request_error.py +9 -0
- murf/errors/forbidden_error.py +9 -0
- murf/errors/internal_server_error.py +9 -0
- murf/errors/payment_required_error.py +9 -0
- murf/errors/service_unavailable_error.py +9 -0
- murf/errors/unauthorized_error.py +9 -0
- murf/py.typed +0 -0
- murf/text_to_speech/__init__.py +5 -0
- murf/text_to_speech/client.py +592 -0
- murf/text_to_speech/types/__init__.py +5 -0
- murf/text_to_speech/types/generate_speech_request_model_version.py +5 -0
- murf/types/__init__.py +21 -0
- murf/types/api_voice.py +49 -0
- murf/types/api_voice_gender.py +5 -0
- murf/types/auth_token_response.py +28 -0
- murf/types/generate_speech_response.py +44 -0
- murf/types/pronunciation_detail.py +29 -0
- murf/types/pronunciation_detail_type.py +5 -0
- murf/types/style_details.py +24 -0
- murf/types/word_duration.py +30 -0
- murf/version.py +3 -0
- murf-1.0.0.dist-info/METADATA +169 -0
- murf-1.0.0.dist-info/RECORD +43 -0
- murf-1.0.0.dist-info/WHEEL +4 -0
murf/errors/__init__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
from .bad_request_error import BadRequestError
|
|
4
|
+
from .forbidden_error import ForbiddenError
|
|
5
|
+
from .internal_server_error import InternalServerError
|
|
6
|
+
from .payment_required_error import PaymentRequiredError
|
|
7
|
+
from .service_unavailable_error import ServiceUnavailableError
|
|
8
|
+
from .unauthorized_error import UnauthorizedError
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"BadRequestError",
|
|
12
|
+
"ForbiddenError",
|
|
13
|
+
"InternalServerError",
|
|
14
|
+
"PaymentRequiredError",
|
|
15
|
+
"ServiceUnavailableError",
|
|
16
|
+
"UnauthorizedError",
|
|
17
|
+
]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
from ..core.api_error import ApiError
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BadRequestError(ApiError):
|
|
8
|
+
def __init__(self, body: typing.Optional[typing.Any]):
|
|
9
|
+
super().__init__(status_code=400, body=body)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
from ..core.api_error import ApiError
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class InternalServerError(ApiError):
|
|
8
|
+
def __init__(self, body: typing.Optional[typing.Any]):
|
|
9
|
+
super().__init__(status_code=500, body=body)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
from ..core.api_error import ApiError
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PaymentRequiredError(ApiError):
|
|
8
|
+
def __init__(self, body: typing.Optional[typing.Any]):
|
|
9
|
+
super().__init__(status_code=402, body=body)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
from ..core.api_error import ApiError
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ServiceUnavailableError(ApiError):
|
|
8
|
+
def __init__(self, body: typing.Optional[typing.Any]):
|
|
9
|
+
super().__init__(status_code=503, body=body)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
from ..core.api_error import ApiError
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class UnauthorizedError(ApiError):
|
|
8
|
+
def __init__(self, body: typing.Optional[typing.Any]):
|
|
9
|
+
super().__init__(status_code=401, body=body)
|
murf/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
|
|
3
|
+
import typing
|
|
4
|
+
from ..core.client_wrapper import SyncClientWrapper
|
|
5
|
+
from .types.generate_speech_request_model_version import GenerateSpeechRequestModelVersion
|
|
6
|
+
from ..types.pronunciation_detail import PronunciationDetail
|
|
7
|
+
from ..core.request_options import RequestOptions
|
|
8
|
+
from ..types.generate_speech_response import GenerateSpeechResponse
|
|
9
|
+
from ..core.serialization import convert_and_respect_annotation_metadata
|
|
10
|
+
from ..core.pydantic_utilities import parse_obj_as
|
|
11
|
+
from ..errors.bad_request_error import BadRequestError
|
|
12
|
+
from ..errors.payment_required_error import PaymentRequiredError
|
|
13
|
+
from ..errors.forbidden_error import ForbiddenError
|
|
14
|
+
from ..errors.internal_server_error import InternalServerError
|
|
15
|
+
from ..errors.service_unavailable_error import ServiceUnavailableError
|
|
16
|
+
from json.decoder import JSONDecodeError
|
|
17
|
+
from ..core.api_error import ApiError
|
|
18
|
+
from ..types.api_voice import ApiVoice
|
|
19
|
+
from ..core.client_wrapper import AsyncClientWrapper
|
|
20
|
+
|
|
21
|
+
# this is used as the default value for optional parameters
|
|
22
|
+
OMIT = typing.cast(typing.Any, ...)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TextToSpeechClient:
|
|
26
|
+
def __init__(self, *, client_wrapper: SyncClientWrapper):
|
|
27
|
+
self._client_wrapper = client_wrapper
|
|
28
|
+
|
|
29
|
+
def generate(
|
|
30
|
+
self,
|
|
31
|
+
*,
|
|
32
|
+
text: str,
|
|
33
|
+
voice_id: str,
|
|
34
|
+
audio_duration: typing.Optional[float] = OMIT,
|
|
35
|
+
channel_type: typing.Optional[str] = OMIT,
|
|
36
|
+
encode_as_base_64: typing.Optional[bool] = OMIT,
|
|
37
|
+
format: typing.Optional[str] = OMIT,
|
|
38
|
+
model_version: typing.Optional[GenerateSpeechRequestModelVersion] = OMIT,
|
|
39
|
+
multi_native_locale: typing.Optional[str] = OMIT,
|
|
40
|
+
pitch: typing.Optional[int] = OMIT,
|
|
41
|
+
pronunciation_dictionary: typing.Optional[typing.Dict[str, PronunciationDetail]] = OMIT,
|
|
42
|
+
rate: typing.Optional[int] = OMIT,
|
|
43
|
+
sample_rate: typing.Optional[float] = OMIT,
|
|
44
|
+
style: typing.Optional[str] = OMIT,
|
|
45
|
+
variation: typing.Optional[int] = OMIT,
|
|
46
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
47
|
+
) -> GenerateSpeechResponse:
|
|
48
|
+
"""
|
|
49
|
+
Returns a url to the generated audio file along with other associated properties.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
text : str
|
|
54
|
+
The text that is to be synthesised. e.g. 'Hello there [pause 1s] friend'
|
|
55
|
+
|
|
56
|
+
voice_id : str
|
|
57
|
+
|
|
58
|
+
audio_duration : typing.Optional[float]
|
|
59
|
+
This parameter allows specifying the duration (in seconds) for the generated audio. If the value is 0, this parameter will be ignored. Only available for Gen2 model.
|
|
60
|
+
|
|
61
|
+
channel_type : typing.Optional[str]
|
|
62
|
+
Valid values: STEREO, MONO
|
|
63
|
+
|
|
64
|
+
encode_as_base_64 : typing.Optional[bool]
|
|
65
|
+
Set to true to receive audio in response as a Base64 encoded string instead of a url.
|
|
66
|
+
|
|
67
|
+
format : typing.Optional[str]
|
|
68
|
+
Format of the generated audio file. Valid values: MP3, WAV, FLAC, ALAW, ULAW
|
|
69
|
+
|
|
70
|
+
model_version : typing.Optional[GenerateSpeechRequestModelVersion]
|
|
71
|
+
Valid values: GEN1, GEN2. Use GEN2 to generate audio using new and advanced model. Outputs from Gen 2 will sound better, but different from the old model
|
|
72
|
+
|
|
73
|
+
multi_native_locale : typing.Optional[str]
|
|
74
|
+
Specifies the language for the generated audio, enabling a voice to speak in multiple languages natively. Only available in the Gen2 model.
|
|
75
|
+
Valid values: "en-US", "en-UK", "es-ES", etc. Use the GET /v1/speed/voices endpoint to retrieve the list of available voices and languages.
|
|
76
|
+
|
|
77
|
+
pitch : typing.Optional[int]
|
|
78
|
+
Pitch of the voiceover
|
|
79
|
+
|
|
80
|
+
pronunciation_dictionary : typing.Optional[typing.Dict[str, PronunciationDetail]]
|
|
81
|
+
An object used to define custom pronunciations.
|
|
82
|
+
|
|
83
|
+
Example 1: {"live":{"type": "IPA", "pronunciation": "laɪv"}}.
|
|
84
|
+
|
|
85
|
+
Example 2: {"2022":{"type": "SAY_AS", "pronunciation": "twenty twenty two"}}
|
|
86
|
+
|
|
87
|
+
rate : typing.Optional[int]
|
|
88
|
+
Speed of the voiceover
|
|
89
|
+
|
|
90
|
+
sample_rate : typing.Optional[float]
|
|
91
|
+
Valid values are 8000, 24000, 44100, 48000
|
|
92
|
+
|
|
93
|
+
style : typing.Optional[str]
|
|
94
|
+
The voice style to be used for voiceover generation.
|
|
95
|
+
|
|
96
|
+
variation : typing.Optional[int]
|
|
97
|
+
Higher values will add more variation in terms of Pause, Pitch, and Speed to the voice. Only available for Gen2 model.
|
|
98
|
+
|
|
99
|
+
request_options : typing.Optional[RequestOptions]
|
|
100
|
+
Request-specific configuration.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
GenerateSpeechResponse
|
|
105
|
+
Ok
|
|
106
|
+
|
|
107
|
+
Examples
|
|
108
|
+
--------
|
|
109
|
+
from murf import Murf
|
|
110
|
+
|
|
111
|
+
client = Murf(
|
|
112
|
+
api_key="YOUR_API_KEY",
|
|
113
|
+
)
|
|
114
|
+
client.text_to_speech.generate(
|
|
115
|
+
text="Hello, world!",
|
|
116
|
+
voice_id="en-US-natalie",
|
|
117
|
+
)
|
|
118
|
+
"""
|
|
119
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
120
|
+
"v1/speech/generate",
|
|
121
|
+
method="POST",
|
|
122
|
+
json={
|
|
123
|
+
"audioDuration": audio_duration,
|
|
124
|
+
"channelType": channel_type,
|
|
125
|
+
"encodeAsBase64": encode_as_base_64,
|
|
126
|
+
"format": format,
|
|
127
|
+
"modelVersion": model_version,
|
|
128
|
+
"multiNativeLocale": multi_native_locale,
|
|
129
|
+
"pitch": pitch,
|
|
130
|
+
"pronunciationDictionary": convert_and_respect_annotation_metadata(
|
|
131
|
+
object_=pronunciation_dictionary,
|
|
132
|
+
annotation=typing.Dict[str, PronunciationDetail],
|
|
133
|
+
direction="write",
|
|
134
|
+
),
|
|
135
|
+
"rate": rate,
|
|
136
|
+
"sampleRate": sample_rate,
|
|
137
|
+
"style": style,
|
|
138
|
+
"text": text,
|
|
139
|
+
"variation": variation,
|
|
140
|
+
"voiceId": voice_id,
|
|
141
|
+
},
|
|
142
|
+
headers={
|
|
143
|
+
"content-type": "application/json",
|
|
144
|
+
},
|
|
145
|
+
request_options=request_options,
|
|
146
|
+
omit=OMIT,
|
|
147
|
+
)
|
|
148
|
+
try:
|
|
149
|
+
if 200 <= _response.status_code < 300:
|
|
150
|
+
return typing.cast(
|
|
151
|
+
GenerateSpeechResponse,
|
|
152
|
+
parse_obj_as(
|
|
153
|
+
type_=GenerateSpeechResponse, # type: ignore
|
|
154
|
+
object_=_response.json(),
|
|
155
|
+
),
|
|
156
|
+
)
|
|
157
|
+
if _response.status_code == 400:
|
|
158
|
+
raise BadRequestError(
|
|
159
|
+
typing.cast(
|
|
160
|
+
typing.Optional[typing.Any],
|
|
161
|
+
parse_obj_as(
|
|
162
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
163
|
+
object_=_response.json(),
|
|
164
|
+
),
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
if _response.status_code == 402:
|
|
168
|
+
raise PaymentRequiredError(
|
|
169
|
+
typing.cast(
|
|
170
|
+
typing.Optional[typing.Any],
|
|
171
|
+
parse_obj_as(
|
|
172
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
173
|
+
object_=_response.json(),
|
|
174
|
+
),
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
if _response.status_code == 403:
|
|
178
|
+
raise ForbiddenError(
|
|
179
|
+
typing.cast(
|
|
180
|
+
typing.Optional[typing.Any],
|
|
181
|
+
parse_obj_as(
|
|
182
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
183
|
+
object_=_response.json(),
|
|
184
|
+
),
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
if _response.status_code == 500:
|
|
188
|
+
raise InternalServerError(
|
|
189
|
+
typing.cast(
|
|
190
|
+
typing.Optional[typing.Any],
|
|
191
|
+
parse_obj_as(
|
|
192
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
193
|
+
object_=_response.json(),
|
|
194
|
+
),
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
if _response.status_code == 503:
|
|
198
|
+
raise ServiceUnavailableError(
|
|
199
|
+
typing.cast(
|
|
200
|
+
typing.Optional[typing.Any],
|
|
201
|
+
parse_obj_as(
|
|
202
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
203
|
+
object_=_response.json(),
|
|
204
|
+
),
|
|
205
|
+
)
|
|
206
|
+
)
|
|
207
|
+
_response_json = _response.json()
|
|
208
|
+
except JSONDecodeError:
|
|
209
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
210
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
211
|
+
|
|
212
|
+
def get_voices(
|
|
213
|
+
self, *, token: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None
|
|
214
|
+
) -> typing.List[ApiVoice]:
|
|
215
|
+
"""
|
|
216
|
+
Returns a list of available voices for speech synthesis
|
|
217
|
+
|
|
218
|
+
Parameters
|
|
219
|
+
----------
|
|
220
|
+
token : typing.Optional[str]
|
|
221
|
+
|
|
222
|
+
request_options : typing.Optional[RequestOptions]
|
|
223
|
+
Request-specific configuration.
|
|
224
|
+
|
|
225
|
+
Returns
|
|
226
|
+
-------
|
|
227
|
+
typing.List[ApiVoice]
|
|
228
|
+
Ok
|
|
229
|
+
|
|
230
|
+
Examples
|
|
231
|
+
--------
|
|
232
|
+
from murf import Murf
|
|
233
|
+
|
|
234
|
+
client = Murf(
|
|
235
|
+
api_key="YOUR_API_KEY",
|
|
236
|
+
)
|
|
237
|
+
client.text_to_speech.get_voices()
|
|
238
|
+
"""
|
|
239
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
240
|
+
"v1/speech/voices",
|
|
241
|
+
method="GET",
|
|
242
|
+
headers={
|
|
243
|
+
"token": str(token) if token is not None else None,
|
|
244
|
+
},
|
|
245
|
+
request_options=request_options,
|
|
246
|
+
)
|
|
247
|
+
try:
|
|
248
|
+
if 200 <= _response.status_code < 300:
|
|
249
|
+
return typing.cast(
|
|
250
|
+
typing.List[ApiVoice],
|
|
251
|
+
parse_obj_as(
|
|
252
|
+
type_=typing.List[ApiVoice], # type: ignore
|
|
253
|
+
object_=_response.json(),
|
|
254
|
+
),
|
|
255
|
+
)
|
|
256
|
+
if _response.status_code == 400:
|
|
257
|
+
raise BadRequestError(
|
|
258
|
+
typing.cast(
|
|
259
|
+
typing.Optional[typing.Any],
|
|
260
|
+
parse_obj_as(
|
|
261
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
262
|
+
object_=_response.json(),
|
|
263
|
+
),
|
|
264
|
+
)
|
|
265
|
+
)
|
|
266
|
+
if _response.status_code == 403:
|
|
267
|
+
raise ForbiddenError(
|
|
268
|
+
typing.cast(
|
|
269
|
+
typing.Optional[typing.Any],
|
|
270
|
+
parse_obj_as(
|
|
271
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
272
|
+
object_=_response.json(),
|
|
273
|
+
),
|
|
274
|
+
)
|
|
275
|
+
)
|
|
276
|
+
if _response.status_code == 500:
|
|
277
|
+
raise InternalServerError(
|
|
278
|
+
typing.cast(
|
|
279
|
+
typing.Optional[typing.Any],
|
|
280
|
+
parse_obj_as(
|
|
281
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
282
|
+
object_=_response.json(),
|
|
283
|
+
),
|
|
284
|
+
)
|
|
285
|
+
)
|
|
286
|
+
if _response.status_code == 503:
|
|
287
|
+
raise ServiceUnavailableError(
|
|
288
|
+
typing.cast(
|
|
289
|
+
typing.Optional[typing.Any],
|
|
290
|
+
parse_obj_as(
|
|
291
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
292
|
+
object_=_response.json(),
|
|
293
|
+
),
|
|
294
|
+
)
|
|
295
|
+
)
|
|
296
|
+
_response_json = _response.json()
|
|
297
|
+
except JSONDecodeError:
|
|
298
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
299
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
class AsyncTextToSpeechClient:
|
|
303
|
+
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
|
304
|
+
self._client_wrapper = client_wrapper
|
|
305
|
+
|
|
306
|
+
async def generate(
|
|
307
|
+
self,
|
|
308
|
+
*,
|
|
309
|
+
text: str,
|
|
310
|
+
voice_id: str,
|
|
311
|
+
audio_duration: typing.Optional[float] = OMIT,
|
|
312
|
+
channel_type: typing.Optional[str] = OMIT,
|
|
313
|
+
encode_as_base_64: typing.Optional[bool] = OMIT,
|
|
314
|
+
format: typing.Optional[str] = OMIT,
|
|
315
|
+
model_version: typing.Optional[GenerateSpeechRequestModelVersion] = OMIT,
|
|
316
|
+
multi_native_locale: typing.Optional[str] = OMIT,
|
|
317
|
+
pitch: typing.Optional[int] = OMIT,
|
|
318
|
+
pronunciation_dictionary: typing.Optional[typing.Dict[str, PronunciationDetail]] = OMIT,
|
|
319
|
+
rate: typing.Optional[int] = OMIT,
|
|
320
|
+
sample_rate: typing.Optional[float] = OMIT,
|
|
321
|
+
style: typing.Optional[str] = OMIT,
|
|
322
|
+
variation: typing.Optional[int] = OMIT,
|
|
323
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
324
|
+
) -> GenerateSpeechResponse:
|
|
325
|
+
"""
|
|
326
|
+
Returns a url to the generated audio file along with other associated properties.
|
|
327
|
+
|
|
328
|
+
Parameters
|
|
329
|
+
----------
|
|
330
|
+
text : str
|
|
331
|
+
The text that is to be synthesised. e.g. 'Hello there [pause 1s] friend'
|
|
332
|
+
|
|
333
|
+
voice_id : str
|
|
334
|
+
|
|
335
|
+
audio_duration : typing.Optional[float]
|
|
336
|
+
This parameter allows specifying the duration (in seconds) for the generated audio. If the value is 0, this parameter will be ignored. Only available for Gen2 model.
|
|
337
|
+
|
|
338
|
+
channel_type : typing.Optional[str]
|
|
339
|
+
Valid values: STEREO, MONO
|
|
340
|
+
|
|
341
|
+
encode_as_base_64 : typing.Optional[bool]
|
|
342
|
+
Set to true to receive audio in response as a Base64 encoded string instead of a url.
|
|
343
|
+
|
|
344
|
+
format : typing.Optional[str]
|
|
345
|
+
Format of the generated audio file. Valid values: MP3, WAV, FLAC, ALAW, ULAW
|
|
346
|
+
|
|
347
|
+
model_version : typing.Optional[GenerateSpeechRequestModelVersion]
|
|
348
|
+
Valid values: GEN1, GEN2. Use GEN2 to generate audio using new and advanced model. Outputs from Gen 2 will sound better, but different from the old model
|
|
349
|
+
|
|
350
|
+
multi_native_locale : typing.Optional[str]
|
|
351
|
+
Specifies the language for the generated audio, enabling a voice to speak in multiple languages natively. Only available in the Gen2 model.
|
|
352
|
+
Valid values: "en-US", "en-UK", "es-ES", etc. Use the GET /v1/speed/voices endpoint to retrieve the list of available voices and languages.
|
|
353
|
+
|
|
354
|
+
pitch : typing.Optional[int]
|
|
355
|
+
Pitch of the voiceover
|
|
356
|
+
|
|
357
|
+
pronunciation_dictionary : typing.Optional[typing.Dict[str, PronunciationDetail]]
|
|
358
|
+
An object used to define custom pronunciations.
|
|
359
|
+
|
|
360
|
+
Example 1: {"live":{"type": "IPA", "pronunciation": "laɪv"}}.
|
|
361
|
+
|
|
362
|
+
Example 2: {"2022":{"type": "SAY_AS", "pronunciation": "twenty twenty two"}}
|
|
363
|
+
|
|
364
|
+
rate : typing.Optional[int]
|
|
365
|
+
Speed of the voiceover
|
|
366
|
+
|
|
367
|
+
sample_rate : typing.Optional[float]
|
|
368
|
+
Valid values are 8000, 24000, 44100, 48000
|
|
369
|
+
|
|
370
|
+
style : typing.Optional[str]
|
|
371
|
+
The voice style to be used for voiceover generation.
|
|
372
|
+
|
|
373
|
+
variation : typing.Optional[int]
|
|
374
|
+
Higher values will add more variation in terms of Pause, Pitch, and Speed to the voice. Only available for Gen2 model.
|
|
375
|
+
|
|
376
|
+
request_options : typing.Optional[RequestOptions]
|
|
377
|
+
Request-specific configuration.
|
|
378
|
+
|
|
379
|
+
Returns
|
|
380
|
+
-------
|
|
381
|
+
GenerateSpeechResponse
|
|
382
|
+
Ok
|
|
383
|
+
|
|
384
|
+
Examples
|
|
385
|
+
--------
|
|
386
|
+
import asyncio
|
|
387
|
+
|
|
388
|
+
from murf import AsyncMurf
|
|
389
|
+
|
|
390
|
+
client = AsyncMurf(
|
|
391
|
+
api_key="YOUR_API_KEY",
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
async def main() -> None:
|
|
396
|
+
await client.text_to_speech.generate(
|
|
397
|
+
text="Hello, world!",
|
|
398
|
+
voice_id="en-US-natalie",
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
asyncio.run(main())
|
|
403
|
+
"""
|
|
404
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
405
|
+
"v1/speech/generate",
|
|
406
|
+
method="POST",
|
|
407
|
+
json={
|
|
408
|
+
"audioDuration": audio_duration,
|
|
409
|
+
"channelType": channel_type,
|
|
410
|
+
"encodeAsBase64": encode_as_base_64,
|
|
411
|
+
"format": format,
|
|
412
|
+
"modelVersion": model_version,
|
|
413
|
+
"multiNativeLocale": multi_native_locale,
|
|
414
|
+
"pitch": pitch,
|
|
415
|
+
"pronunciationDictionary": convert_and_respect_annotation_metadata(
|
|
416
|
+
object_=pronunciation_dictionary,
|
|
417
|
+
annotation=typing.Dict[str, PronunciationDetail],
|
|
418
|
+
direction="write",
|
|
419
|
+
),
|
|
420
|
+
"rate": rate,
|
|
421
|
+
"sampleRate": sample_rate,
|
|
422
|
+
"style": style,
|
|
423
|
+
"text": text,
|
|
424
|
+
"variation": variation,
|
|
425
|
+
"voiceId": voice_id,
|
|
426
|
+
},
|
|
427
|
+
headers={
|
|
428
|
+
"content-type": "application/json",
|
|
429
|
+
},
|
|
430
|
+
request_options=request_options,
|
|
431
|
+
omit=OMIT,
|
|
432
|
+
)
|
|
433
|
+
try:
|
|
434
|
+
if 200 <= _response.status_code < 300:
|
|
435
|
+
return typing.cast(
|
|
436
|
+
GenerateSpeechResponse,
|
|
437
|
+
parse_obj_as(
|
|
438
|
+
type_=GenerateSpeechResponse, # type: ignore
|
|
439
|
+
object_=_response.json(),
|
|
440
|
+
),
|
|
441
|
+
)
|
|
442
|
+
if _response.status_code == 400:
|
|
443
|
+
raise BadRequestError(
|
|
444
|
+
typing.cast(
|
|
445
|
+
typing.Optional[typing.Any],
|
|
446
|
+
parse_obj_as(
|
|
447
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
448
|
+
object_=_response.json(),
|
|
449
|
+
),
|
|
450
|
+
)
|
|
451
|
+
)
|
|
452
|
+
if _response.status_code == 402:
|
|
453
|
+
raise PaymentRequiredError(
|
|
454
|
+
typing.cast(
|
|
455
|
+
typing.Optional[typing.Any],
|
|
456
|
+
parse_obj_as(
|
|
457
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
458
|
+
object_=_response.json(),
|
|
459
|
+
),
|
|
460
|
+
)
|
|
461
|
+
)
|
|
462
|
+
if _response.status_code == 403:
|
|
463
|
+
raise ForbiddenError(
|
|
464
|
+
typing.cast(
|
|
465
|
+
typing.Optional[typing.Any],
|
|
466
|
+
parse_obj_as(
|
|
467
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
468
|
+
object_=_response.json(),
|
|
469
|
+
),
|
|
470
|
+
)
|
|
471
|
+
)
|
|
472
|
+
if _response.status_code == 500:
|
|
473
|
+
raise InternalServerError(
|
|
474
|
+
typing.cast(
|
|
475
|
+
typing.Optional[typing.Any],
|
|
476
|
+
parse_obj_as(
|
|
477
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
478
|
+
object_=_response.json(),
|
|
479
|
+
),
|
|
480
|
+
)
|
|
481
|
+
)
|
|
482
|
+
if _response.status_code == 503:
|
|
483
|
+
raise ServiceUnavailableError(
|
|
484
|
+
typing.cast(
|
|
485
|
+
typing.Optional[typing.Any],
|
|
486
|
+
parse_obj_as(
|
|
487
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
488
|
+
object_=_response.json(),
|
|
489
|
+
),
|
|
490
|
+
)
|
|
491
|
+
)
|
|
492
|
+
_response_json = _response.json()
|
|
493
|
+
except JSONDecodeError:
|
|
494
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
495
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
496
|
+
|
|
497
|
+
async def get_voices(
|
|
498
|
+
self, *, token: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None
|
|
499
|
+
) -> typing.List[ApiVoice]:
|
|
500
|
+
"""
|
|
501
|
+
Returns a list of available voices for speech synthesis
|
|
502
|
+
|
|
503
|
+
Parameters
|
|
504
|
+
----------
|
|
505
|
+
token : typing.Optional[str]
|
|
506
|
+
|
|
507
|
+
request_options : typing.Optional[RequestOptions]
|
|
508
|
+
Request-specific configuration.
|
|
509
|
+
|
|
510
|
+
Returns
|
|
511
|
+
-------
|
|
512
|
+
typing.List[ApiVoice]
|
|
513
|
+
Ok
|
|
514
|
+
|
|
515
|
+
Examples
|
|
516
|
+
--------
|
|
517
|
+
import asyncio
|
|
518
|
+
|
|
519
|
+
from murf import AsyncMurf
|
|
520
|
+
|
|
521
|
+
client = AsyncMurf(
|
|
522
|
+
api_key="YOUR_API_KEY",
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
async def main() -> None:
|
|
527
|
+
await client.text_to_speech.get_voices()
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
asyncio.run(main())
|
|
531
|
+
"""
|
|
532
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
533
|
+
"v1/speech/voices",
|
|
534
|
+
method="GET",
|
|
535
|
+
headers={
|
|
536
|
+
"token": str(token) if token is not None else None,
|
|
537
|
+
},
|
|
538
|
+
request_options=request_options,
|
|
539
|
+
)
|
|
540
|
+
try:
|
|
541
|
+
if 200 <= _response.status_code < 300:
|
|
542
|
+
return typing.cast(
|
|
543
|
+
typing.List[ApiVoice],
|
|
544
|
+
parse_obj_as(
|
|
545
|
+
type_=typing.List[ApiVoice], # type: ignore
|
|
546
|
+
object_=_response.json(),
|
|
547
|
+
),
|
|
548
|
+
)
|
|
549
|
+
if _response.status_code == 400:
|
|
550
|
+
raise BadRequestError(
|
|
551
|
+
typing.cast(
|
|
552
|
+
typing.Optional[typing.Any],
|
|
553
|
+
parse_obj_as(
|
|
554
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
555
|
+
object_=_response.json(),
|
|
556
|
+
),
|
|
557
|
+
)
|
|
558
|
+
)
|
|
559
|
+
if _response.status_code == 403:
|
|
560
|
+
raise ForbiddenError(
|
|
561
|
+
typing.cast(
|
|
562
|
+
typing.Optional[typing.Any],
|
|
563
|
+
parse_obj_as(
|
|
564
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
565
|
+
object_=_response.json(),
|
|
566
|
+
),
|
|
567
|
+
)
|
|
568
|
+
)
|
|
569
|
+
if _response.status_code == 500:
|
|
570
|
+
raise InternalServerError(
|
|
571
|
+
typing.cast(
|
|
572
|
+
typing.Optional[typing.Any],
|
|
573
|
+
parse_obj_as(
|
|
574
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
575
|
+
object_=_response.json(),
|
|
576
|
+
),
|
|
577
|
+
)
|
|
578
|
+
)
|
|
579
|
+
if _response.status_code == 503:
|
|
580
|
+
raise ServiceUnavailableError(
|
|
581
|
+
typing.cast(
|
|
582
|
+
typing.Optional[typing.Any],
|
|
583
|
+
parse_obj_as(
|
|
584
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
|
585
|
+
object_=_response.json(),
|
|
586
|
+
),
|
|
587
|
+
)
|
|
588
|
+
)
|
|
589
|
+
_response_json = _response.json()
|
|
590
|
+
except JSONDecodeError:
|
|
591
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
592
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|