murf 1.1.1__tar.gz → 1.2.1__tar.gz

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.

Potentially problematic release.


This version of murf might be problematic. Click here for more details.

Files changed (77) hide show
  1. {murf-1.1.1 → murf-1.2.1}/PKG-INFO +4 -4
  2. {murf-1.1.1 → murf-1.2.1}/README.md +3 -3
  3. {murf-1.1.1 → murf-1.2.1}/pyproject.toml +1 -1
  4. {murf-1.1.1 → murf-1.2.1}/src/murf/__init__.py +14 -2
  5. {murf-1.1.1 → murf-1.2.1}/src/murf/core/client_wrapper.py +1 -1
  6. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/jobs/client.py +25 -11
  7. {murf-1.1.1 → murf-1.2.1}/src/murf/text_to_speech/client.py +296 -2
  8. {murf-1.1.1 → murf-1.2.1}/src/murf/types/__init__.py +14 -2
  9. murf-1.2.1/src/murf/types/character_count.py +20 -0
  10. {murf-1.1.1 → murf-1.2.1}/src/murf/types/generate_speech_response.py +11 -15
  11. murf-1.2.1/src/murf/types/metadata.py +22 -0
  12. murf-1.2.1/src/murf/types/murf_api_translation_request.py +29 -0
  13. murf-1.2.1/src/murf/types/murf_api_translation_response.py +22 -0
  14. murf-1.2.1/src/murf/types/speech_to_speech_response.py +47 -0
  15. murf-1.2.1/src/murf/types/translation.py +20 -0
  16. murf-1.1.1/src/murf/types/word_duration.py → murf-1.2.1/src/murf/types/word_duration_response.py +19 -5
  17. murf-1.2.1/src/murf/utils.py +31 -0
  18. {murf-1.1.1 → murf-1.2.1}/LICENSE +0 -0
  19. {murf-1.1.1 → murf-1.2.1}/src/murf/auth/__init__.py +0 -0
  20. {murf-1.1.1 → murf-1.2.1}/src/murf/auth/client.py +0 -0
  21. {murf-1.1.1 → murf-1.2.1}/src/murf/base_client.py +0 -0
  22. {murf-1.1.1 → murf-1.2.1}/src/murf/client.py +0 -0
  23. {murf-1.1.1 → murf-1.2.1}/src/murf/core/__init__.py +0 -0
  24. {murf-1.1.1 → murf-1.2.1}/src/murf/core/api_error.py +0 -0
  25. {murf-1.1.1 → murf-1.2.1}/src/murf/core/datetime_utils.py +0 -0
  26. {murf-1.1.1 → murf-1.2.1}/src/murf/core/file.py +0 -0
  27. {murf-1.1.1 → murf-1.2.1}/src/murf/core/http_client.py +0 -0
  28. {murf-1.1.1 → murf-1.2.1}/src/murf/core/jsonable_encoder.py +0 -0
  29. {murf-1.1.1 → murf-1.2.1}/src/murf/core/pydantic_utilities.py +0 -0
  30. {murf-1.1.1 → murf-1.2.1}/src/murf/core/query_encoder.py +0 -0
  31. {murf-1.1.1 → murf-1.2.1}/src/murf/core/remove_none_from_dict.py +0 -0
  32. {murf-1.1.1 → murf-1.2.1}/src/murf/core/request_options.py +0 -0
  33. {murf-1.1.1 → murf-1.2.1}/src/murf/core/serialization.py +0 -0
  34. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/__init__.py +0 -0
  35. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/client.py +0 -0
  36. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/jobs/__init__.py +0 -0
  37. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/jobs/types/__init__.py +0 -0
  38. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/jobs/types/jobs_create_request_priority.py +0 -0
  39. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/jobs/types/jobs_create_with_project_id_request_priority.py +0 -0
  40. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/languages/__init__.py +0 -0
  41. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/languages/client.py +0 -0
  42. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/projects/__init__.py +0 -0
  43. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/projects/client.py +0 -0
  44. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/projects/types/__init__.py +0 -0
  45. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing/projects/types/api_create_project_request_dubbing_type.py +0 -0
  46. {murf-1.1.1 → murf-1.2.1}/src/murf/dubbing_client.py +0 -0
  47. {murf-1.1.1 → murf-1.2.1}/src/murf/environment.py +0 -0
  48. {murf-1.1.1 → murf-1.2.1}/src/murf/errors/__init__.py +0 -0
  49. {murf-1.1.1 → murf-1.2.1}/src/murf/errors/bad_request_error.py +0 -0
  50. {murf-1.1.1 → murf-1.2.1}/src/murf/errors/forbidden_error.py +0 -0
  51. {murf-1.1.1 → murf-1.2.1}/src/murf/errors/internal_server_error.py +0 -0
  52. {murf-1.1.1 → murf-1.2.1}/src/murf/errors/payment_required_error.py +0 -0
  53. {murf-1.1.1 → murf-1.2.1}/src/murf/errors/service_unavailable_error.py +0 -0
  54. {murf-1.1.1 → murf-1.2.1}/src/murf/errors/unauthorized_error.py +0 -0
  55. {murf-1.1.1 → murf-1.2.1}/src/murf/py.typed +0 -0
  56. {murf-1.1.1 → murf-1.2.1}/src/murf/text_to_speech/__init__.py +0 -0
  57. {murf-1.1.1 → murf-1.2.1}/src/murf/text_to_speech/types/__init__.py +0 -0
  58. {murf-1.1.1 → murf-1.2.1}/src/murf/text_to_speech/types/generate_speech_request_model_version.py +0 -0
  59. {murf-1.1.1 → murf-1.2.1}/src/murf/types/api_job_response.py +0 -0
  60. {murf-1.1.1 → murf-1.2.1}/src/murf/types/api_job_response_dubbing_type.py +0 -0
  61. {murf-1.1.1 → murf-1.2.1}/src/murf/types/api_job_response_priority.py +0 -0
  62. {murf-1.1.1 → murf-1.2.1}/src/murf/types/api_project_response.py +0 -0
  63. {murf-1.1.1 → murf-1.2.1}/src/murf/types/api_project_response_dubbing_type.py +0 -0
  64. {murf-1.1.1 → murf-1.2.1}/src/murf/types/api_voice.py +0 -0
  65. {murf-1.1.1 → murf-1.2.1}/src/murf/types/api_voice_gender.py +0 -0
  66. {murf-1.1.1 → murf-1.2.1}/src/murf/types/auth_token_response.py +0 -0
  67. {murf-1.1.1 → murf-1.2.1}/src/murf/types/dub_api_detail_response.py +0 -0
  68. {murf-1.1.1 → murf-1.2.1}/src/murf/types/dub_job_status_response.py +0 -0
  69. {murf-1.1.1 → murf-1.2.1}/src/murf/types/form_data_content_disposition.py +0 -0
  70. {murf-1.1.1 → murf-1.2.1}/src/murf/types/group_api_project_response.py +0 -0
  71. {murf-1.1.1 → murf-1.2.1}/src/murf/types/locale_response.py +0 -0
  72. {murf-1.1.1 → murf-1.2.1}/src/murf/types/locale_response_supports_item.py +0 -0
  73. {murf-1.1.1 → murf-1.2.1}/src/murf/types/pronunciation_detail.py +0 -0
  74. {murf-1.1.1 → murf-1.2.1}/src/murf/types/pronunciation_detail_type.py +0 -0
  75. {murf-1.1.1 → murf-1.2.1}/src/murf/types/source_locale_response.py +0 -0
  76. {murf-1.1.1 → murf-1.2.1}/src/murf/types/style_details.py +0 -0
  77. {murf-1.1.1 → murf-1.2.1}/src/murf/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: murf
3
- Version: 1.1.1
3
+ Version: 1.2.1
4
4
  Summary:
5
5
  Requires-Python: >=3.8,<4.0
6
6
  Classifier: Intended Audience :: Developers
@@ -48,7 +48,7 @@ Description-Content-Type: text/markdown
48
48
 
49
49
  ## Overview
50
50
 
51
- The Murf Python SDK offers seamless integration with the [Murf AI](https://murf.ai/) [text-to-speech software](https://murf.ai/text-to-speech), enabling developers and creators to convert text into lifelike speech effortlessly. With over 130 natural-sounding voices across 13+ languages and 20+ speaking styles, Murf provides unparalleled speech customization for a wide range of applications. The SDK is designed for both synchronous and asynchronous workflows, featuring robust error handling, advanced configuration options, and support for real-time applications.
51
+ The Murf Python SDK offers seamless integration with the [Murf AI](https://murf.ai/) [text-to-speech software](https://murf.ai/text-to-speech), enabling developers and creators to convert text into lifelike speech effortlessly. With over 130 natural-sounding voices across 21 languages and 20+ speaking styles, Murf provides unparalleled speech customization for a wide range of applications. The SDK is designed for both synchronous and asynchronous workflows, featuring robust error handling, advanced configuration options, and support for real-time applications.
52
52
 
53
53
  ---
54
54
 
@@ -89,9 +89,9 @@ For more detailed information, refer to the [official documentation](https://mur
89
89
  ## Features
90
90
 
91
91
  - **Text-to-Speech Conversion:** Transform text into natural-sounding speech.
92
- - **Multilingual Support:** Access voices in over 13 languages, including English, French, German, Spanish, Italian, Hindi, Portuguese, Dutch, Korean, Chinese (Mandarin), Bengali, Tamil, and Polish.
92
+ - **Multilingual Support:** Access voices in over 21 languages, including English, French, German, Spanish, Italian, Hindi, Portuguese, Dutch, Korean, Chinese (Mandarin), Bengali, Tamil, Polish, Japanese, Turkish, Indonesian, Croatian, Greek, Romanian, Slovak, and Bulgarian.
93
93
 
94
- ![Murf AI Languages](https://murf.ai/public-assets/home/Murf_Lang.png)
94
+ ![Murf AI Languages](https://murf.ai/public-assets/home/Murf_Languages_21.jpg)
95
95
 
96
96
  - **Multiple Voice Styles:** Choose from 20+ speaking styles to suit your application's needs.
97
97
  - **Advanced Voice Customization:** Adjust parameters like pitch, speed, pauses, and pronunciation for optimal output. Fine-grained controls let you tailor the voice output to match your specific requirements.
@@ -22,7 +22,7 @@
22
22
 
23
23
  ## Overview
24
24
 
25
- The Murf Python SDK offers seamless integration with the [Murf AI](https://murf.ai/) [text-to-speech software](https://murf.ai/text-to-speech), enabling developers and creators to convert text into lifelike speech effortlessly. With over 130 natural-sounding voices across 13+ languages and 20+ speaking styles, Murf provides unparalleled speech customization for a wide range of applications. The SDK is designed for both synchronous and asynchronous workflows, featuring robust error handling, advanced configuration options, and support for real-time applications.
25
+ The Murf Python SDK offers seamless integration with the [Murf AI](https://murf.ai/) [text-to-speech software](https://murf.ai/text-to-speech), enabling developers and creators to convert text into lifelike speech effortlessly. With over 130 natural-sounding voices across 21 languages and 20+ speaking styles, Murf provides unparalleled speech customization for a wide range of applications. The SDK is designed for both synchronous and asynchronous workflows, featuring robust error handling, advanced configuration options, and support for real-time applications.
26
26
 
27
27
  ---
28
28
 
@@ -63,9 +63,9 @@ For more detailed information, refer to the [official documentation](https://mur
63
63
  ## Features
64
64
 
65
65
  - **Text-to-Speech Conversion:** Transform text into natural-sounding speech.
66
- - **Multilingual Support:** Access voices in over 13 languages, including English, French, German, Spanish, Italian, Hindi, Portuguese, Dutch, Korean, Chinese (Mandarin), Bengali, Tamil, and Polish.
66
+ - **Multilingual Support:** Access voices in over 21 languages, including English, French, German, Spanish, Italian, Hindi, Portuguese, Dutch, Korean, Chinese (Mandarin), Bengali, Tamil, Polish, Japanese, Turkish, Indonesian, Croatian, Greek, Romanian, Slovak, and Bulgarian.
67
67
 
68
- ![Murf AI Languages](https://murf.ai/public-assets/home/Murf_Lang.png)
68
+ ![Murf AI Languages](https://murf.ai/public-assets/home/Murf_Languages_21.jpg)
69
69
 
70
70
  - **Multiple Voice Styles:** Choose from 20+ speaking styles to suit your application's needs.
71
71
  - **Advanced Voice Customization:** Adjust parameters like pitch, speed, pauses, and pronunciation for optimal output. Fine-grained controls let you tailor the voice output to match your specific requirements.
@@ -3,7 +3,7 @@ name = "murf"
3
3
 
4
4
  [tool.poetry]
5
5
  name = "murf"
6
- version = "1.1.1"
6
+ version = "1.2.1"
7
7
  description = ""
8
8
  readme = "README.md"
9
9
  authors = []
@@ -9,6 +9,7 @@ from .types import (
9
9
  ApiVoice,
10
10
  ApiVoiceGender,
11
11
  AuthTokenResponse,
12
+ CharacterCount,
12
13
  DubApiDetailResponse,
13
14
  DubJobStatusResponse,
14
15
  FormDataContentDisposition,
@@ -16,11 +17,16 @@ from .types import (
16
17
  GroupApiProjectResponse,
17
18
  LocaleResponse,
18
19
  LocaleResponseSupportsItem,
20
+ Metadata,
21
+ MurfApiTranslationRequest,
22
+ MurfApiTranslationResponse,
19
23
  PronunciationDetail,
20
24
  PronunciationDetailType,
21
25
  SourceLocaleResponse,
26
+ SpeechToSpeechResponse,
22
27
  StyleDetails,
23
- WordDuration,
28
+ Translation,
29
+ WordDurationResponse,
24
30
  )
25
31
  from .errors import (
26
32
  BadRequestError,
@@ -48,6 +54,7 @@ __all__ = [
48
54
  "AsyncMurf",
49
55
  "AuthTokenResponse",
50
56
  "BadRequestError",
57
+ "CharacterCount",
51
58
  "DubApiDetailResponse",
52
59
  "DubJobStatusResponse",
53
60
  "ForbiddenError",
@@ -58,7 +65,10 @@ __all__ = [
58
65
  "InternalServerError",
59
66
  "LocaleResponse",
60
67
  "LocaleResponseSupportsItem",
68
+ "Metadata",
61
69
  "Murf",
70
+ "MurfApiTranslationRequest",
71
+ "MurfApiTranslationResponse",
62
72
  "MurfDub",
63
73
  "MurfEnvironment",
64
74
  "PaymentRequiredError",
@@ -66,9 +76,11 @@ __all__ = [
66
76
  "PronunciationDetailType",
67
77
  "ServiceUnavailableError",
68
78
  "SourceLocaleResponse",
79
+ "SpeechToSpeechResponse",
69
80
  "StyleDetails",
81
+ "Translation",
70
82
  "UnauthorizedError",
71
- "WordDuration",
83
+ "WordDurationResponse",
72
84
  "__version__",
73
85
  "auth",
74
86
  "dubbing",
@@ -16,7 +16,7 @@ class BaseClientWrapper:
16
16
  headers: typing.Dict[str, str] = {
17
17
  "X-Fern-Language": "Python",
18
18
  "X-Fern-SDK-Name": "murf",
19
- "X-Fern-SDK-Version": "1.1.1",
19
+ "X-Fern-SDK-Version": "1.2.1",
20
20
  }
21
21
  if self._api_key is not None:
22
22
  headers["api-key"] = self._api_key
@@ -2,8 +2,8 @@
2
2
 
3
3
  import typing
4
4
  from ...core.client_wrapper import SyncClientWrapper
5
- from .types.jobs_create_request_priority import JobsCreateRequestPriority
6
5
  from ... import core
6
+ from .types.jobs_create_request_priority import JobsCreateRequestPriority
7
7
  from ...core.request_options import RequestOptions
8
8
  from ...types.api_job_response import ApiJobResponse
9
9
  from ...core.pydantic_utilities import parse_obj_as
@@ -30,12 +30,13 @@ class JobsClient:
30
30
  self,
31
31
  *,
32
32
  target_locales: typing.List[str],
33
- priority: JobsCreateRequestPriority,
34
33
  file: typing.Optional[core.File] = OMIT,
35
34
  file_url: typing.Optional[str] = OMIT,
36
35
  source_locale: typing.Optional[str] = OMIT,
37
36
  webhook_url: typing.Optional[str] = OMIT,
38
37
  file_name: typing.Optional[str] = OMIT,
38
+ priority: typing.Optional[JobsCreateRequestPriority] = OMIT,
39
+ webhook_secret: typing.Optional[str] = OMIT,
39
40
  request_options: typing.Optional[RequestOptions] = None,
40
41
  ) -> ApiJobResponse:
41
42
  """
@@ -44,9 +45,6 @@ class JobsClient:
44
45
  target_locales : typing.List[str]
45
46
  List of target locales
46
47
 
47
- priority : JobsCreateRequestPriority
48
- Priority of the job. Allowed values: LOW, NORMAL, HIGH
49
-
50
48
  file : typing.Optional[core.File]
51
49
  See core.File for more documentation
52
50
 
@@ -59,6 +57,11 @@ class JobsClient:
59
57
 
60
58
  file_name : typing.Optional[str]
61
59
 
60
+ priority : typing.Optional[JobsCreateRequestPriority]
61
+ Priority of the job. Allowed values: LOW, NORMAL, HIGH
62
+
63
+ webhook_secret : typing.Optional[str]
64
+
62
65
  request_options : typing.Optional[RequestOptions]
63
66
  Request-specific configuration.
64
67
 
@@ -76,7 +79,6 @@ class JobsClient:
76
79
  )
77
80
  client.dubbing.jobs.create(
78
81
  target_locales=["target_locales"],
79
- priority="LOW",
80
82
  )
81
83
  """
82
84
  _response = self._client_wrapper.httpx_client.request(
@@ -89,6 +91,7 @@ class JobsClient:
89
91
  "webhook_url": webhook_url,
90
92
  "file_name": file_name,
91
93
  "priority": priority,
94
+ "webhook_secret": webhook_secret,
92
95
  },
93
96
  files={
94
97
  "file": file,
@@ -159,6 +162,7 @@ class JobsClient:
159
162
  webhook_url: typing.Optional[str] = OMIT,
160
163
  file_name: typing.Optional[str] = OMIT,
161
164
  priority: typing.Optional[JobsCreateWithProjectIdRequestPriority] = OMIT,
165
+ webhook_secret: typing.Optional[str] = OMIT,
162
166
  request_options: typing.Optional[RequestOptions] = None,
163
167
  ) -> ApiJobResponse:
164
168
  """
@@ -179,6 +183,8 @@ class JobsClient:
179
183
  priority : typing.Optional[JobsCreateWithProjectIdRequestPriority]
180
184
  Priority of the job. Allowed values: LOW, NORMAL, HIGH
181
185
 
186
+ webhook_secret : typing.Optional[str]
187
+
182
188
  request_options : typing.Optional[RequestOptions]
183
189
  Request-specific configuration.
184
190
 
@@ -207,6 +213,7 @@ class JobsClient:
207
213
  "webhook_url": webhook_url,
208
214
  "file_name": file_name,
209
215
  "priority": priority,
216
+ "webhook_secret": webhook_secret,
210
217
  },
211
218
  files={
212
219
  "file": file,
@@ -363,12 +370,13 @@ class AsyncJobsClient:
363
370
  self,
364
371
  *,
365
372
  target_locales: typing.List[str],
366
- priority: JobsCreateRequestPriority,
367
373
  file: typing.Optional[core.File] = OMIT,
368
374
  file_url: typing.Optional[str] = OMIT,
369
375
  source_locale: typing.Optional[str] = OMIT,
370
376
  webhook_url: typing.Optional[str] = OMIT,
371
377
  file_name: typing.Optional[str] = OMIT,
378
+ priority: typing.Optional[JobsCreateRequestPriority] = OMIT,
379
+ webhook_secret: typing.Optional[str] = OMIT,
372
380
  request_options: typing.Optional[RequestOptions] = None,
373
381
  ) -> ApiJobResponse:
374
382
  """
@@ -377,9 +385,6 @@ class AsyncJobsClient:
377
385
  target_locales : typing.List[str]
378
386
  List of target locales
379
387
 
380
- priority : JobsCreateRequestPriority
381
- Priority of the job. Allowed values: LOW, NORMAL, HIGH
382
-
383
388
  file : typing.Optional[core.File]
384
389
  See core.File for more documentation
385
390
 
@@ -392,6 +397,11 @@ class AsyncJobsClient:
392
397
 
393
398
  file_name : typing.Optional[str]
394
399
 
400
+ priority : typing.Optional[JobsCreateRequestPriority]
401
+ Priority of the job. Allowed values: LOW, NORMAL, HIGH
402
+
403
+ webhook_secret : typing.Optional[str]
404
+
395
405
  request_options : typing.Optional[RequestOptions]
396
406
  Request-specific configuration.
397
407
 
@@ -414,7 +424,6 @@ class AsyncJobsClient:
414
424
  async def main() -> None:
415
425
  await client.dubbing.jobs.create(
416
426
  target_locales=["target_locales"],
417
- priority="LOW",
418
427
  )
419
428
 
420
429
 
@@ -430,6 +439,7 @@ class AsyncJobsClient:
430
439
  "webhook_url": webhook_url,
431
440
  "file_name": file_name,
432
441
  "priority": priority,
442
+ "webhook_secret": webhook_secret,
433
443
  },
434
444
  files={
435
445
  "file": file,
@@ -500,6 +510,7 @@ class AsyncJobsClient:
500
510
  webhook_url: typing.Optional[str] = OMIT,
501
511
  file_name: typing.Optional[str] = OMIT,
502
512
  priority: typing.Optional[JobsCreateWithProjectIdRequestPriority] = OMIT,
513
+ webhook_secret: typing.Optional[str] = OMIT,
503
514
  request_options: typing.Optional[RequestOptions] = None,
504
515
  ) -> ApiJobResponse:
505
516
  """
@@ -520,6 +531,8 @@ class AsyncJobsClient:
520
531
  priority : typing.Optional[JobsCreateWithProjectIdRequestPriority]
521
532
  Priority of the job. Allowed values: LOW, NORMAL, HIGH
522
533
 
534
+ webhook_secret : typing.Optional[str]
535
+
523
536
  request_options : typing.Optional[RequestOptions]
524
537
  Request-specific configuration.
525
538
 
@@ -556,6 +569,7 @@ class AsyncJobsClient:
556
569
  "webhook_url": webhook_url,
557
570
  "file_name": file_name,
558
571
  "priority": priority,
572
+ "webhook_secret": webhook_secret,
559
573
  },
560
574
  files={
561
575
  "file": file,
@@ -54,6 +54,7 @@ class TextToSpeechClient:
54
54
  The text that is to be synthesised. e.g. 'Hello there [pause 1s] friend'
55
55
 
56
56
  voice_id : str
57
+ Use the GET /v1/speech/voices api to find supported voiceIds.
57
58
 
58
59
  audio_duration : typing.Optional[float]
59
60
  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.
@@ -72,7 +73,7 @@ class TextToSpeechClient:
72
73
 
73
74
  multi_native_locale : typing.Optional[str]
74
75
  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
+ Valid values: "en-US", "en-UK", "es-ES", etc. Use the GET /v1/speech/voices endpoint to retrieve the list of available voices and languages.
76
77
 
77
78
  pitch : typing.Optional[int]
78
79
  Pitch of the voiceover
@@ -209,6 +210,152 @@ class TextToSpeechClient:
209
210
  raise ApiError(status_code=_response.status_code, body=_response.text)
210
211
  raise ApiError(status_code=_response.status_code, body=_response_json)
211
212
 
213
+ def stream(
214
+ self,
215
+ *,
216
+ text: str,
217
+ voice_id: str,
218
+ token: typing.Optional[str] = None,
219
+ channel_type: typing.Optional[str] = OMIT,
220
+ format: typing.Optional[str] = OMIT,
221
+ multi_native_locale: typing.Optional[str] = OMIT,
222
+ pitch: typing.Optional[int] = OMIT,
223
+ rate: typing.Optional[int] = OMIT,
224
+ sample_rate: typing.Optional[float] = OMIT,
225
+ style: typing.Optional[str] = OMIT,
226
+ variation: typing.Optional[int] = OMIT,
227
+ request_options: typing.Optional[RequestOptions] = None,
228
+ ) -> typing.Iterator[bytes]:
229
+ """
230
+ Returns a streaming output of generated audio
231
+
232
+ Parameters
233
+ ----------
234
+ text : str
235
+ The text that is to be synthesised. e.g. 'Hello there [pause 1s] friend'
236
+
237
+ voice_id : str
238
+ Use the GET /v1/speech/voices api to find supported voiceIds.
239
+
240
+ token : typing.Optional[str]
241
+
242
+ channel_type : typing.Optional[str]
243
+ Valid values: STEREO, MONO
244
+
245
+ format : typing.Optional[str]
246
+ Format of the generated audio file. Valid values: MP3, WAV
247
+
248
+ multi_native_locale : typing.Optional[str]
249
+ Specifies the language for the generated audio, enabling a voice to speak in multiple languages natively. Only available in the Gen2 model.
250
+ Valid values: "en-US", "en-UK", "es-ES", etc. Use the GET /v1/speech/voices endpoint to retrieve the list of available voices and languages.
251
+
252
+ pitch : typing.Optional[int]
253
+ Pitch of the voiceover
254
+
255
+ rate : typing.Optional[int]
256
+ Speed of the voiceover
257
+
258
+ sample_rate : typing.Optional[float]
259
+ Valid values are 8000, 24000, 44100, 48000
260
+
261
+ style : typing.Optional[str]
262
+ The voice style to be used for voiceover generation.
263
+
264
+ variation : typing.Optional[int]
265
+ Higher values will add more variation in terms of Pause, Pitch, and Speed to the voice. Only available for Gen2 model.
266
+
267
+ request_options : typing.Optional[RequestOptions]
268
+ Request-specific configuration. You can pass in configuration such as `chunk_size`, and more to customize the request and response.
269
+
270
+ Yields
271
+ ------
272
+ typing.Iterator[bytes]
273
+ Ok
274
+ """
275
+ with self._client_wrapper.httpx_client.stream(
276
+ "v1/speech/stream",
277
+ method="POST",
278
+ json={
279
+ "channelType": channel_type,
280
+ "format": format,
281
+ "multiNativeLocale": multi_native_locale,
282
+ "pitch": pitch,
283
+ "rate": rate,
284
+ "sampleRate": sample_rate,
285
+ "style": style,
286
+ "text": text,
287
+ "variation": variation,
288
+ "voiceId": voice_id,
289
+ },
290
+ headers={
291
+ "content-type": "application/json",
292
+ "token": str(token) if token is not None else None,
293
+ },
294
+ request_options=request_options,
295
+ omit=OMIT,
296
+ ) as _response:
297
+ try:
298
+ if 200 <= _response.status_code < 300:
299
+ _chunk_size = request_options.get("chunk_size", None) if request_options is not None else None
300
+ for _chunk in _response.iter_bytes(chunk_size=_chunk_size):
301
+ yield _chunk
302
+ return
303
+ _response.read()
304
+ if _response.status_code == 400:
305
+ raise BadRequestError(
306
+ typing.cast(
307
+ typing.Optional[typing.Any],
308
+ parse_obj_as(
309
+ type_=typing.Optional[typing.Any], # type: ignore
310
+ object_=_response.json(),
311
+ ),
312
+ )
313
+ )
314
+ if _response.status_code == 402:
315
+ raise PaymentRequiredError(
316
+ typing.cast(
317
+ typing.Optional[typing.Any],
318
+ parse_obj_as(
319
+ type_=typing.Optional[typing.Any], # type: ignore
320
+ object_=_response.json(),
321
+ ),
322
+ )
323
+ )
324
+ if _response.status_code == 403:
325
+ raise ForbiddenError(
326
+ typing.cast(
327
+ typing.Optional[typing.Any],
328
+ parse_obj_as(
329
+ type_=typing.Optional[typing.Any], # type: ignore
330
+ object_=_response.json(),
331
+ ),
332
+ )
333
+ )
334
+ if _response.status_code == 500:
335
+ raise InternalServerError(
336
+ typing.cast(
337
+ typing.Optional[typing.Any],
338
+ parse_obj_as(
339
+ type_=typing.Optional[typing.Any], # type: ignore
340
+ object_=_response.json(),
341
+ ),
342
+ )
343
+ )
344
+ if _response.status_code == 503:
345
+ raise ServiceUnavailableError(
346
+ typing.cast(
347
+ typing.Optional[typing.Any],
348
+ parse_obj_as(
349
+ type_=typing.Optional[typing.Any], # type: ignore
350
+ object_=_response.json(),
351
+ ),
352
+ )
353
+ )
354
+ _response_json = _response.json()
355
+ except JSONDecodeError:
356
+ raise ApiError(status_code=_response.status_code, body=_response.text)
357
+ raise ApiError(status_code=_response.status_code, body=_response_json)
358
+
212
359
  def get_voices(
213
360
  self, *, token: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None
214
361
  ) -> typing.List[ApiVoice]:
@@ -331,6 +478,7 @@ class AsyncTextToSpeechClient:
331
478
  The text that is to be synthesised. e.g. 'Hello there [pause 1s] friend'
332
479
 
333
480
  voice_id : str
481
+ Use the GET /v1/speech/voices api to find supported voiceIds.
334
482
 
335
483
  audio_duration : typing.Optional[float]
336
484
  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.
@@ -349,7 +497,7 @@ class AsyncTextToSpeechClient:
349
497
 
350
498
  multi_native_locale : typing.Optional[str]
351
499
  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.
500
+ Valid values: "en-US", "en-UK", "es-ES", etc. Use the GET /v1/speech/voices endpoint to retrieve the list of available voices and languages.
353
501
 
354
502
  pitch : typing.Optional[int]
355
503
  Pitch of the voiceover
@@ -494,6 +642,152 @@ class AsyncTextToSpeechClient:
494
642
  raise ApiError(status_code=_response.status_code, body=_response.text)
495
643
  raise ApiError(status_code=_response.status_code, body=_response_json)
496
644
 
645
+ async def stream(
646
+ self,
647
+ *,
648
+ text: str,
649
+ voice_id: str,
650
+ token: typing.Optional[str] = None,
651
+ channel_type: typing.Optional[str] = OMIT,
652
+ format: typing.Optional[str] = OMIT,
653
+ multi_native_locale: typing.Optional[str] = OMIT,
654
+ pitch: typing.Optional[int] = OMIT,
655
+ rate: typing.Optional[int] = OMIT,
656
+ sample_rate: typing.Optional[float] = OMIT,
657
+ style: typing.Optional[str] = OMIT,
658
+ variation: typing.Optional[int] = OMIT,
659
+ request_options: typing.Optional[RequestOptions] = None,
660
+ ) -> typing.AsyncIterator[bytes]:
661
+ """
662
+ Returns a streaming output of generated audio
663
+
664
+ Parameters
665
+ ----------
666
+ text : str
667
+ The text that is to be synthesised. e.g. 'Hello there [pause 1s] friend'
668
+
669
+ voice_id : str
670
+ Use the GET /v1/speech/voices api to find supported voiceIds.
671
+
672
+ token : typing.Optional[str]
673
+
674
+ channel_type : typing.Optional[str]
675
+ Valid values: STEREO, MONO
676
+
677
+ format : typing.Optional[str]
678
+ Format of the generated audio file. Valid values: MP3, WAV
679
+
680
+ multi_native_locale : typing.Optional[str]
681
+ Specifies the language for the generated audio, enabling a voice to speak in multiple languages natively. Only available in the Gen2 model.
682
+ Valid values: "en-US", "en-UK", "es-ES", etc. Use the GET /v1/speech/voices endpoint to retrieve the list of available voices and languages.
683
+
684
+ pitch : typing.Optional[int]
685
+ Pitch of the voiceover
686
+
687
+ rate : typing.Optional[int]
688
+ Speed of the voiceover
689
+
690
+ sample_rate : typing.Optional[float]
691
+ Valid values are 8000, 24000, 44100, 48000
692
+
693
+ style : typing.Optional[str]
694
+ The voice style to be used for voiceover generation.
695
+
696
+ variation : typing.Optional[int]
697
+ Higher values will add more variation in terms of Pause, Pitch, and Speed to the voice. Only available for Gen2 model.
698
+
699
+ request_options : typing.Optional[RequestOptions]
700
+ Request-specific configuration. You can pass in configuration such as `chunk_size`, and more to customize the request and response.
701
+
702
+ Yields
703
+ ------
704
+ typing.AsyncIterator[bytes]
705
+ Ok
706
+ """
707
+ async with self._client_wrapper.httpx_client.stream(
708
+ "v1/speech/stream",
709
+ method="POST",
710
+ json={
711
+ "channelType": channel_type,
712
+ "format": format,
713
+ "multiNativeLocale": multi_native_locale,
714
+ "pitch": pitch,
715
+ "rate": rate,
716
+ "sampleRate": sample_rate,
717
+ "style": style,
718
+ "text": text,
719
+ "variation": variation,
720
+ "voiceId": voice_id,
721
+ },
722
+ headers={
723
+ "content-type": "application/json",
724
+ "token": str(token) if token is not None else None,
725
+ },
726
+ request_options=request_options,
727
+ omit=OMIT,
728
+ ) as _response:
729
+ try:
730
+ if 200 <= _response.status_code < 300:
731
+ _chunk_size = request_options.get("chunk_size", None) if request_options is not None else None
732
+ async for _chunk in _response.aiter_bytes(chunk_size=_chunk_size):
733
+ yield _chunk
734
+ return
735
+ await _response.aread()
736
+ if _response.status_code == 400:
737
+ raise BadRequestError(
738
+ typing.cast(
739
+ typing.Optional[typing.Any],
740
+ parse_obj_as(
741
+ type_=typing.Optional[typing.Any], # type: ignore
742
+ object_=_response.json(),
743
+ ),
744
+ )
745
+ )
746
+ if _response.status_code == 402:
747
+ raise PaymentRequiredError(
748
+ typing.cast(
749
+ typing.Optional[typing.Any],
750
+ parse_obj_as(
751
+ type_=typing.Optional[typing.Any], # type: ignore
752
+ object_=_response.json(),
753
+ ),
754
+ )
755
+ )
756
+ if _response.status_code == 403:
757
+ raise ForbiddenError(
758
+ typing.cast(
759
+ typing.Optional[typing.Any],
760
+ parse_obj_as(
761
+ type_=typing.Optional[typing.Any], # type: ignore
762
+ object_=_response.json(),
763
+ ),
764
+ )
765
+ )
766
+ if _response.status_code == 500:
767
+ raise InternalServerError(
768
+ typing.cast(
769
+ typing.Optional[typing.Any],
770
+ parse_obj_as(
771
+ type_=typing.Optional[typing.Any], # type: ignore
772
+ object_=_response.json(),
773
+ ),
774
+ )
775
+ )
776
+ if _response.status_code == 503:
777
+ raise ServiceUnavailableError(
778
+ typing.cast(
779
+ typing.Optional[typing.Any],
780
+ parse_obj_as(
781
+ type_=typing.Optional[typing.Any], # type: ignore
782
+ object_=_response.json(),
783
+ ),
784
+ )
785
+ )
786
+ _response_json = _response.json()
787
+ except JSONDecodeError:
788
+ raise ApiError(status_code=_response.status_code, body=_response.text)
789
+ raise ApiError(status_code=_response.status_code, body=_response_json)
790
+
497
791
  async def get_voices(
498
792
  self, *, token: typing.Optional[str] = None, request_options: typing.Optional[RequestOptions] = None
499
793
  ) -> typing.List[ApiVoice]:
@@ -8,6 +8,7 @@ from .api_project_response_dubbing_type import ApiProjectResponseDubbingType
8
8
  from .api_voice import ApiVoice
9
9
  from .api_voice_gender import ApiVoiceGender
10
10
  from .auth_token_response import AuthTokenResponse
11
+ from .character_count import CharacterCount
11
12
  from .dub_api_detail_response import DubApiDetailResponse
12
13
  from .dub_job_status_response import DubJobStatusResponse
13
14
  from .form_data_content_disposition import FormDataContentDisposition
@@ -15,11 +16,16 @@ from .generate_speech_response import GenerateSpeechResponse
15
16
  from .group_api_project_response import GroupApiProjectResponse
16
17
  from .locale_response import LocaleResponse
17
18
  from .locale_response_supports_item import LocaleResponseSupportsItem
19
+ from .metadata import Metadata
20
+ from .murf_api_translation_request import MurfApiTranslationRequest
21
+ from .murf_api_translation_response import MurfApiTranslationResponse
18
22
  from .pronunciation_detail import PronunciationDetail
19
23
  from .pronunciation_detail_type import PronunciationDetailType
20
24
  from .source_locale_response import SourceLocaleResponse
25
+ from .speech_to_speech_response import SpeechToSpeechResponse
21
26
  from .style_details import StyleDetails
22
- from .word_duration import WordDuration
27
+ from .translation import Translation
28
+ from .word_duration_response import WordDurationResponse
23
29
 
24
30
  __all__ = [
25
31
  "ApiJobResponse",
@@ -30,6 +36,7 @@ __all__ = [
30
36
  "ApiVoice",
31
37
  "ApiVoiceGender",
32
38
  "AuthTokenResponse",
39
+ "CharacterCount",
33
40
  "DubApiDetailResponse",
34
41
  "DubJobStatusResponse",
35
42
  "FormDataContentDisposition",
@@ -37,9 +44,14 @@ __all__ = [
37
44
  "GroupApiProjectResponse",
38
45
  "LocaleResponse",
39
46
  "LocaleResponseSupportsItem",
47
+ "Metadata",
48
+ "MurfApiTranslationRequest",
49
+ "MurfApiTranslationResponse",
40
50
  "PronunciationDetail",
41
51
  "PronunciationDetailType",
42
52
  "SourceLocaleResponse",
53
+ "SpeechToSpeechResponse",
43
54
  "StyleDetails",
44
- "WordDuration",
55
+ "Translation",
56
+ "WordDurationResponse",
45
57
  ]
@@ -0,0 +1,20 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import typing
5
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
6
+ import pydantic
7
+
8
+
9
+ class CharacterCount(UniversalBaseModel):
10
+ total_source_text_length: typing.Optional[int] = None
11
+ total_translated_text_length: typing.Optional[int] = None
12
+
13
+ if IS_PYDANTIC_V2:
14
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
15
+ else:
16
+
17
+ class Config:
18
+ frozen = True
19
+ smart_union = True
20
+ extra = pydantic.Extra.allow
@@ -2,37 +2,33 @@
2
2
 
3
3
  from ..core.pydantic_utilities import UniversalBaseModel
4
4
  import typing_extensions
5
- import typing
6
5
  from ..core.serialization import FieldMetadata
7
6
  import pydantic
8
- from .word_duration import WordDuration
7
+ import typing
8
+ from .word_duration_response import WordDurationResponse
9
9
  from ..core.pydantic_utilities import IS_PYDANTIC_V2
10
10
 
11
11
 
12
12
  class GenerateSpeechResponse(UniversalBaseModel):
13
- audio_file: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="audioFile")] = None
14
- audio_length_in_seconds: typing_extensions.Annotated[
15
- typing.Optional[float], FieldMetadata(alias="audioLengthInSeconds")
16
- ] = None
17
- consumed_character_count: typing_extensions.Annotated[
18
- typing.Optional[int], FieldMetadata(alias="consumedCharacterCount")
19
- ] = pydantic.Field(default=None)
13
+ audio_file: typing_extensions.Annotated[str, FieldMetadata(alias="audioFile")]
14
+ audio_length_in_seconds: typing_extensions.Annotated[float, FieldMetadata(alias="audioLengthInSeconds")]
15
+ consumed_character_count: typing_extensions.Annotated[int, FieldMetadata(alias="consumedCharacterCount")] = (
16
+ pydantic.Field()
17
+ )
20
18
  """
21
19
  Number of characters consumed so far in the current billing cycle.
22
20
  """
23
21
 
24
22
  encoded_audio: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="encodedAudio")] = None
25
- remaining_character_count: typing_extensions.Annotated[
26
- typing.Optional[int], FieldMetadata(alias="remainingCharacterCount")
27
- ] = pydantic.Field(default=None)
23
+ remaining_character_count: typing_extensions.Annotated[int, FieldMetadata(alias="remainingCharacterCount")] = (
24
+ pydantic.Field()
25
+ )
28
26
  """
29
27
  Remaining number of characters available for synthesis in the current billing cycle.
30
28
  """
31
29
 
32
30
  warning: typing.Optional[str] = None
33
- word_durations: typing_extensions.Annotated[
34
- typing.Optional[typing.List[WordDuration]], FieldMetadata(alias="wordDurations")
35
- ] = None
31
+ word_durations: typing_extensions.Annotated[typing.List[WordDurationResponse], FieldMetadata(alias="wordDurations")]
36
32
 
37
33
  if IS_PYDANTIC_V2:
38
34
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -0,0 +1,22 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import typing
5
+ from .character_count import CharacterCount
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
7
+ import pydantic
8
+
9
+
10
+ class Metadata(UniversalBaseModel):
11
+ character_count: typing.Optional[CharacterCount] = None
12
+ credits_used: typing.Optional[float] = None
13
+ target_language: typing.Optional[str] = None
14
+
15
+ if IS_PYDANTIC_V2:
16
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
17
+ else:
18
+
19
+ class Config:
20
+ frozen = True
21
+ smart_union = True
22
+ extra = pydantic.Extra.allow
@@ -0,0 +1,29 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import typing_extensions
5
+ from ..core.serialization import FieldMetadata
6
+ import pydantic
7
+ import typing
8
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
9
+
10
+
11
+ class MurfApiTranslationRequest(UniversalBaseModel):
12
+ target_language: typing_extensions.Annotated[str, FieldMetadata(alias="targetLanguage")] = pydantic.Field()
13
+ """
14
+ The language code for the target translation
15
+ """
16
+
17
+ texts: typing.List[str] = pydantic.Field()
18
+ """
19
+ List of texts to translate
20
+ """
21
+
22
+ if IS_PYDANTIC_V2:
23
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
24
+ else:
25
+
26
+ class Config:
27
+ frozen = True
28
+ smart_union = True
29
+ extra = pydantic.Extra.allow
@@ -0,0 +1,22 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import typing
5
+ from .metadata import Metadata
6
+ from .translation import Translation
7
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
8
+ import pydantic
9
+
10
+
11
+ class MurfApiTranslationResponse(UniversalBaseModel):
12
+ metadata: typing.Optional[Metadata] = None
13
+ translations: typing.Optional[typing.List[Translation]] = None
14
+
15
+ if IS_PYDANTIC_V2:
16
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
17
+ else:
18
+
19
+ class Config:
20
+ frozen = True
21
+ smart_union = True
22
+ extra = pydantic.Extra.allow
@@ -0,0 +1,47 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import pydantic
5
+ import typing
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
7
+
8
+
9
+ class SpeechToSpeechResponse(UniversalBaseModel):
10
+ audio_file: str = pydantic.Field()
11
+ """
12
+ The URL or path of the generated audio file.
13
+ """
14
+
15
+ audio_length_in_seconds: float = pydantic.Field()
16
+ """
17
+ Length of the generated audio in seconds.
18
+ """
19
+
20
+ encoded_audio: typing.Optional[str] = pydantic.Field(default=None)
21
+ """
22
+ Base64 encoded string of the generated audio. Used when audio is returned directly in the response.
23
+ """
24
+
25
+ remaining_character_count: int = pydantic.Field()
26
+ """
27
+ Remaining number of characters available for synthesis in the current billing cycle.
28
+ """
29
+
30
+ transcription: typing.Optional[str] = pydantic.Field(default=None)
31
+ """
32
+ Transcript of the generated audio, if transcription was requested.
33
+ """
34
+
35
+ warning: typing.Optional[str] = pydantic.Field(default=None)
36
+ """
37
+ Any warning or informational message related to the audio generation process.
38
+ """
39
+
40
+ if IS_PYDANTIC_V2:
41
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
42
+ else:
43
+
44
+ class Config:
45
+ frozen = True
46
+ smart_union = True
47
+ extra = pydantic.Extra.allow
@@ -0,0 +1,20 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import typing
5
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
6
+ import pydantic
7
+
8
+
9
+ class Translation(UniversalBaseModel):
10
+ source_text: typing.Optional[str] = None
11
+ translated_text: typing.Optional[str] = None
12
+
13
+ if IS_PYDANTIC_V2:
14
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
15
+ else:
16
+
17
+ class Config:
18
+ frozen = True
19
+ smart_union = True
20
+ extra = pydantic.Extra.allow
@@ -4,19 +4,33 @@ from ..core.pydantic_utilities import UniversalBaseModel
4
4
  import typing_extensions
5
5
  import typing
6
6
  from ..core.serialization import FieldMetadata
7
- from ..core.pydantic_utilities import IS_PYDANTIC_V2
8
7
  import pydantic
8
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
9
9
 
10
10
 
11
- class WordDuration(UniversalBaseModel):
11
+ class WordDurationResponse(UniversalBaseModel):
12
12
  end_ms: typing_extensions.Annotated[typing.Optional[int], FieldMetadata(alias="endMs")] = None
13
13
  pitch_scale_maximum: typing_extensions.Annotated[
14
14
  typing.Optional[float], FieldMetadata(alias="pitchScaleMaximum")
15
- ] = None
15
+ ] = pydantic.Field(default=None)
16
+ """
17
+ This field has been deprecated.
18
+ """
19
+
16
20
  pitch_scale_minimum: typing_extensions.Annotated[
17
21
  typing.Optional[float], FieldMetadata(alias="pitchScaleMinimum")
18
- ] = None
19
- source_word_index: typing_extensions.Annotated[typing.Optional[int], FieldMetadata(alias="sourceWordIndex")] = None
22
+ ] = pydantic.Field(default=None)
23
+ """
24
+ This field has been deprecated.
25
+ """
26
+
27
+ source_word_index: typing_extensions.Annotated[typing.Optional[int], FieldMetadata(alias="sourceWordIndex")] = (
28
+ pydantic.Field(default=None)
29
+ )
30
+ """
31
+ This field has been deprecated.
32
+ """
33
+
20
34
  start_ms: typing_extensions.Annotated[typing.Optional[int], FieldMetadata(alias="startMs")] = None
21
35
  word: typing.Optional[str] = None
22
36
 
@@ -0,0 +1,31 @@
1
+ import hmac
2
+ import hashlib
3
+ import time
4
+
5
+ def validate_hmac(secret: str, payload: str, timestamp_header: str, hmac_signature: str, tolerance_seconds: int):
6
+ """
7
+ Validate the HMAC signature of a payload against a secret key and timestamp.
8
+
9
+ Args:
10
+ secret (str): The secret key used for HMAC generation.
11
+ payload (str): The payload to validate.
12
+ timestamp_header (str): The timestamp header from the request.
13
+ hmac_signature (str): The HMAC signature to validate against.
14
+ tolerance_seconds (int): The allowed time tolerance in seconds.
15
+ """
16
+ try:
17
+ received_timestamp = int(timestamp_header)
18
+ current_timestamp = int(time.time()) * 1000
19
+ if (abs(current_timestamp - received_timestamp) / 1000) > tolerance_seconds:
20
+ print("Timestamp is outside the allowed tolerance window.")
21
+ return False
22
+ data_to_sign = f"{payload}.{timestamp_header}"
23
+ calculated_hmac = hmac.new(
24
+ secret.encode('utf-8'),
25
+ data_to_sign.encode('utf-8'),
26
+ hashlib.sha256
27
+ ).hexdigest()
28
+ return hmac.compare_digest(calculated_hmac, hmac_signature)
29
+ except Exception as e:
30
+ print(f"Error validating HMAC: {e}")
31
+ return False
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes