python-terminusgps 34.0.0__py3-none-any.whl → 35.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.
Potentially problematic release.
This version of python-terminusgps might be problematic. Click here for more details.
- {python_terminusgps-34.0.0.dist-info → python_terminusgps-35.0.0.dist-info}/METADATA +1 -1
- {python_terminusgps-34.0.0.dist-info → python_terminusgps-35.0.0.dist-info}/RECORD +7 -6
- terminusgps/aws/notifications.py +177 -59
- terminusgps/aws/speech.py +146 -0
- terminusgps/django/validators.py +1 -1
- {python_terminusgps-34.0.0.dist-info → python_terminusgps-35.0.0.dist-info}/WHEEL +0 -0
- {python_terminusgps-34.0.0.dist-info → python_terminusgps-35.0.0.dist-info}/licenses/COPYING +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-terminusgps
|
|
3
|
-
Version:
|
|
3
|
+
Version: 35.0.0
|
|
4
4
|
Summary: Provides abstractions/utilities for working with Wialon API, Authorize.NET API, AWS API, and more.
|
|
5
5
|
Project-URL: Documentation, https://docs.terminusgps.com
|
|
6
6
|
Project-URL: Repository, https://github.com/terminusgps/python-terminusgps
|
|
@@ -15,8 +15,9 @@ terminusgps/authorizenet/tests/test_auth.py,sha256=sdByYrcv8RKjcJckOHbyHH1z_M4qr
|
|
|
15
15
|
terminusgps/authorizenet/tests/test_profiles.py,sha256=tvLBY0iSAC33RlWiBP_NSnPskUQBjfrf0YHMpR-m22k,7566
|
|
16
16
|
terminusgps/authorizenet/tests/test_utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
terminusgps/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
-
terminusgps/aws/notifications.py,sha256=
|
|
18
|
+
terminusgps/aws/notifications.py,sha256=HQDsxvFh_8vpAvoOo0K_3nteV0ArM-kgSeMhNzBx3es,9618
|
|
19
19
|
terminusgps/aws/secrets.py,sha256=MxQEmmBLpMUQ2tYAsHdCYf-7RZ84LiogdKcTsACX5dw,361
|
|
20
|
+
terminusgps/aws/speech.py,sha256=8d4kLzc1obzW7uAhlSBmPWh_hw92d1eydcIiQROTj7A,4563
|
|
20
21
|
terminusgps/aws/utils.py,sha256=68GWcllu4h41qzFiKdUkWOAA4LDsTPqRY446VRMxYsY,116
|
|
21
22
|
terminusgps/aws/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
23
|
terminusgps/aws/tests/test_notifications.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -26,7 +27,7 @@ terminusgps/django/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
|
26
27
|
terminusgps/django/mixins.py,sha256=Q9ZJuzpk3d9lDnlVA8ZTVvnZWxB13p08EQ8yVJcztn4,1034
|
|
27
28
|
terminusgps/django/settings.py,sha256=yJIcBE0xjY60AXF_gonY5hS3ofseqPW2k9uSoELgoho,639
|
|
28
29
|
terminusgps/django/utils.py,sha256=SYDQyHA5tTuVwdpZGsCtf0LpTTD0ilRKoxa8StfSTpQ,156
|
|
29
|
-
terminusgps/django/validators.py,sha256=
|
|
30
|
+
terminusgps/django/validators.py,sha256=Gx-bpWkfI0fM4WXVRUpoC2ihPqs7agjdHAFO6gralCs,3341
|
|
30
31
|
terminusgps/django/forms/__init__.py,sha256=hh8Z9AC_u2m2bu3h6sdmPyndfQneCEVovENPHmoTDC0,21
|
|
31
32
|
terminusgps/django/forms/fields.py,sha256=BfuPzOZyGvWsEzONW2h4i01fhoL0IS0-gDdBKW4jHgI,2225
|
|
32
33
|
terminusgps/django/forms/forms.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -54,7 +55,7 @@ terminusgps/wialon/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
54
55
|
terminusgps/wialon/tests/test_items.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
55
56
|
terminusgps/wialon/tests/test_session.py,sha256=9mBlYchMo9NeqRIZsmxYzrM1zBHorqu4ooxqSNppLpI,1336
|
|
56
57
|
terminusgps/wialon/tests/test_utils.py,sha256=SK4PxJQGECFnzx_EQeRAQfsQ5_3FLaVcis2W9u_ibuI,1730
|
|
57
|
-
python_terminusgps-
|
|
58
|
-
python_terminusgps-
|
|
59
|
-
python_terminusgps-
|
|
60
|
-
python_terminusgps-
|
|
58
|
+
python_terminusgps-35.0.0.dist-info/METADATA,sha256=FJGCV_uc4f3OcIqAv0Lyl2w9jSFw2X6a-0Ev1wNU3xc,1616
|
|
59
|
+
python_terminusgps-35.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
60
|
+
python_terminusgps-35.0.0.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
61
|
+
python_terminusgps-35.0.0.dist-info/RECORD,,
|
terminusgps/aws/notifications.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import os
|
|
2
3
|
import uuid
|
|
3
4
|
from collections.abc import Sequence
|
|
4
5
|
from contextlib import AsyncExitStack
|
|
@@ -8,12 +9,138 @@ from aiobotocore.session import AioSession
|
|
|
8
9
|
from terminusgps.django.validators import validate_e164_phone_number
|
|
9
10
|
|
|
10
11
|
|
|
12
|
+
class AsyncPollyManager:
|
|
13
|
+
def __init__(
|
|
14
|
+
self, bucket_name: str | None = None, region_name: str = "us-east-1"
|
|
15
|
+
) -> None:
|
|
16
|
+
self._exit_stack = AsyncExitStack()
|
|
17
|
+
self._polly_client = None
|
|
18
|
+
self._region_name = region_name
|
|
19
|
+
self._bucket_name = bucket_name or os.getenv("AWS_POLLY_BUCKET_NAME", "")
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def region_name(self) -> str:
|
|
23
|
+
"""
|
|
24
|
+
An AWS region name.
|
|
25
|
+
|
|
26
|
+
:type: :py:obj:`str`
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
return self._region_name
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def bucket_name(self) -> str:
|
|
33
|
+
"""
|
|
34
|
+
The AWS bucket that will host audio files.
|
|
35
|
+
|
|
36
|
+
:type: :py:obj:`str`
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
return self._bucket_name
|
|
40
|
+
|
|
41
|
+
async def __aenter__(self) -> "AsyncPollyManager":
|
|
42
|
+
"""
|
|
43
|
+
Creates an asyncronous session and client.
|
|
44
|
+
|
|
45
|
+
:returns: The polly manager.
|
|
46
|
+
:rtype: :py:obj:`~terminusgps.aws.notifications.AsyncPollyManager`
|
|
47
|
+
|
|
48
|
+
"""
|
|
49
|
+
session = AioSession()
|
|
50
|
+
self._polly_client = await self._exit_stack.enter_async_context(
|
|
51
|
+
session.create_client("polly", region_name=self.region_name)
|
|
52
|
+
)
|
|
53
|
+
return self
|
|
54
|
+
|
|
55
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Destroys the asyncronous session.
|
|
58
|
+
|
|
59
|
+
:param exc_type: Exception type.
|
|
60
|
+
:param exc_val: Exception value.
|
|
61
|
+
:param exc_tb: Exception traceback.
|
|
62
|
+
:returns: Nothing.
|
|
63
|
+
:rtype: :py:obj:`None`
|
|
64
|
+
|
|
65
|
+
"""
|
|
66
|
+
await self._exit_stack.__aexit__(exc_type, exc_val, exc_tb)
|
|
67
|
+
|
|
68
|
+
async def synthesize_speech(
|
|
69
|
+
self,
|
|
70
|
+
message: str,
|
|
71
|
+
format: str = "ogg_vorbis",
|
|
72
|
+
sample_rate: int = 22050,
|
|
73
|
+
language_code: str = "en-US",
|
|
74
|
+
) -> None:
|
|
75
|
+
"""
|
|
76
|
+
Synthesizes the message into an audio file and saves it to the S3 bucket.
|
|
77
|
+
|
|
78
|
+
:param message: A message to be read aloud.
|
|
79
|
+
:type message: :py:obj:`str`
|
|
80
|
+
:param format: A file format. Default is ``"ogg_vorbis"``.
|
|
81
|
+
:type format: :py:obj:`str`
|
|
82
|
+
:param sample_rate: The audio frequency in Hz. Default is ``22050``.
|
|
83
|
+
:type sample_rate: :py:obj:`int`
|
|
84
|
+
:param language_code: The language to use in the synthesis. Default is ``"en-US"``.
|
|
85
|
+
:type language_code: :py:obj:`str`
|
|
86
|
+
:returns: Nothing.
|
|
87
|
+
:rtype: :py:obj:`None`
|
|
88
|
+
|
|
89
|
+
"""
|
|
90
|
+
await self._polly_client.start_speech_synthesis_task(
|
|
91
|
+
**{
|
|
92
|
+
"Engine": "standard",
|
|
93
|
+
"LanguageCode": language_code,
|
|
94
|
+
"OutputFormat": format,
|
|
95
|
+
"OutputS3BucketName": self.bucket_name,
|
|
96
|
+
"SampleRate": str(sample_rate),
|
|
97
|
+
"Text": f"<speak>{message}</speak>",
|
|
98
|
+
"TextType": "ssml",
|
|
99
|
+
"VoiceId": "Joanna",
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
async def synthesize_speech_batch(
|
|
104
|
+
self,
|
|
105
|
+
messages: Sequence[str],
|
|
106
|
+
format: str = "ogg_vorbis",
|
|
107
|
+
sample_rate: int = 22050,
|
|
108
|
+
language_code: str = "en-US",
|
|
109
|
+
) -> None:
|
|
110
|
+
"""
|
|
111
|
+
Synthesizes a sequence of messages into audio files and saves them to the S3 bucket.
|
|
112
|
+
|
|
113
|
+
:param messages: A sequence of messages to be read aloud.
|
|
114
|
+
:type messages: :py:obj:`Sequence`
|
|
115
|
+
:param format: A file format. Default is ``"ogg_vorbis"``.
|
|
116
|
+
:type format: :py:obj:`str`
|
|
117
|
+
:param sample_rate: The audio frequency in Hz. Default is ``22050``.
|
|
118
|
+
:type sample_rate: :py:obj:`int`
|
|
119
|
+
:param language_code: The language to use in the synthesis. Default is ``"en-US"``.
|
|
120
|
+
:type language_code: :py:obj:`str`
|
|
121
|
+
:returns: Nothing.
|
|
122
|
+
:rtype: :py:obj:`None`
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
await asyncio.gather(
|
|
126
|
+
*[
|
|
127
|
+
self.synthesize_speech(
|
|
128
|
+
message=message,
|
|
129
|
+
format=format,
|
|
130
|
+
sample_rate=sample_rate,
|
|
131
|
+
language_code=language_code,
|
|
132
|
+
)
|
|
133
|
+
for message in messages
|
|
134
|
+
]
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
11
138
|
class AsyncNotificationManager:
|
|
12
139
|
def __init__(
|
|
13
140
|
self, group_id: str | None = None, region_name: str = "us-east-1"
|
|
14
141
|
) -> None:
|
|
15
142
|
"""
|
|
16
|
-
Sets :py:attr:`group_id` and :py:attr:`region_name
|
|
143
|
+
Sets :py:attr:`group_id` and :py:attr:`region_name`.
|
|
17
144
|
|
|
18
145
|
:returns: Nothing.
|
|
19
146
|
:rtype: :py:obj:`None`
|
|
@@ -76,6 +203,8 @@ class AsyncNotificationManager:
|
|
|
76
203
|
"""
|
|
77
204
|
Sets :py:attr:`group_id` to ``other``.
|
|
78
205
|
|
|
206
|
+
If ``other`` isn't provided, instead set :py:attr:`group_id` to :py:func:`~uuid.uuid4`.
|
|
207
|
+
|
|
79
208
|
:param other: A message group id.
|
|
80
209
|
:type other: :py:obj:`str` | :py:obj:`None`
|
|
81
210
|
:returns: Nothing.
|
|
@@ -86,53 +215,9 @@ class AsyncNotificationManager:
|
|
|
86
215
|
other = str(uuid.uuid4())
|
|
87
216
|
self._group_id = other
|
|
88
217
|
|
|
89
|
-
async def
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
:param target_arns: A sequence of AWS resource ARNs.
|
|
94
|
-
:type target_arns: :py:obj:`~collections.abc.Sequence`
|
|
95
|
-
:param message: A message body.
|
|
96
|
-
:type message: :py:obj:`str`
|
|
97
|
-
:returns: Nothing.
|
|
98
|
-
:rtype: :py:obj:`None`
|
|
99
|
-
|
|
100
|
-
"""
|
|
101
|
-
await asyncio.gather(
|
|
102
|
-
*[
|
|
103
|
-
self.send_push(
|
|
104
|
-
target_arn=arn, message=message, message_id=str(uuid.uuid4())
|
|
105
|
-
)
|
|
106
|
-
for arn in target_arns
|
|
107
|
-
]
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
async def send_sms_batch(self, to_numbers: Sequence[str], message: str) -> None:
|
|
111
|
-
"""
|
|
112
|
-
Sends an sms message to each phone number in ``to_numbers``.
|
|
113
|
-
|
|
114
|
-
:param to_numbers: A sequence of phone numbers.
|
|
115
|
-
:type to_numbers: :py:obj:`~collections.abc.Sequence`
|
|
116
|
-
:param message: A message body.
|
|
117
|
-
:type message: :py:obj:`str`
|
|
118
|
-
:raises ValidationError: If a ``to_number`` wasn't a valid E.164 formatted phone number.
|
|
119
|
-
:returns: Nothing.
|
|
120
|
-
:rtype: :py:obj:`None`
|
|
121
|
-
|
|
122
|
-
"""
|
|
123
|
-
for to_number in to_numbers:
|
|
124
|
-
validate_e164_phone_number(to_number)
|
|
125
|
-
|
|
126
|
-
await asyncio.gather(
|
|
127
|
-
*[
|
|
128
|
-
self.send_sms(
|
|
129
|
-
to_number=num, message=message, message_id=str(uuid.uuid4())
|
|
130
|
-
)
|
|
131
|
-
for num in to_numbers
|
|
132
|
-
]
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
async def send_sms(self, to_number: str, message: str, message_id: str) -> None:
|
|
218
|
+
async def send_sms(
|
|
219
|
+
self, to_number: str, message: str, message_id: str | None = None
|
|
220
|
+
) -> None:
|
|
136
221
|
"""
|
|
137
222
|
Sends an sms to ``to_number``.
|
|
138
223
|
|
|
@@ -140,8 +225,8 @@ class AsyncNotificationManager:
|
|
|
140
225
|
:type to_number: :py:obj:`str`
|
|
141
226
|
:param message: A message body.
|
|
142
227
|
:type message: :py:obj:`str`
|
|
143
|
-
:param message_id: A message deduplication id.
|
|
144
|
-
:type message_id: :py:obj:`str`
|
|
228
|
+
:param message_id: A message deduplication id. :py:func:`~uuid.uuid4` is used if ``message_id`` was not provided.
|
|
229
|
+
:type message_id: :py:obj:`str` | :py:obj:`None`
|
|
145
230
|
:raises ValidationError: If ``to_number`` wasn't a valid E.164 formatted phone number.
|
|
146
231
|
:returns: Nothing.
|
|
147
232
|
:rtype: :py:obj:`None`
|
|
@@ -149,6 +234,9 @@ class AsyncNotificationManager:
|
|
|
149
234
|
"""
|
|
150
235
|
validate_e164_phone_number(to_number)
|
|
151
236
|
|
|
237
|
+
if not message_id:
|
|
238
|
+
message_id = str(uuid.uuid4())
|
|
239
|
+
|
|
152
240
|
await self._sns_client.publish(
|
|
153
241
|
**{
|
|
154
242
|
"PhoneNumber": to_number,
|
|
@@ -158,7 +246,9 @@ class AsyncNotificationManager:
|
|
|
158
246
|
}
|
|
159
247
|
)
|
|
160
248
|
|
|
161
|
-
async def send_push(
|
|
249
|
+
async def send_push(
|
|
250
|
+
self, target_arn: str, message: str, message_id: str | None = None
|
|
251
|
+
) -> None:
|
|
162
252
|
"""
|
|
163
253
|
Sends a push notification to ``target_arn``.
|
|
164
254
|
|
|
@@ -166,12 +256,15 @@ class AsyncNotificationManager:
|
|
|
166
256
|
:type target_arn: :py:obj:`str`
|
|
167
257
|
:param message: A message body.
|
|
168
258
|
:type message: :py:obj:`str`
|
|
169
|
-
:param message_id: A message deduplication id.
|
|
170
|
-
:type message_id: :py:obj:`str`
|
|
259
|
+
:param message_id: A message deduplication id. :py:func:`~uuid.uuid4` is used if ``message_id`` was not provided.
|
|
260
|
+
:type message_id: :py:obj:`str` | :py:obj:`None`
|
|
171
261
|
:returns: Nothing.
|
|
172
262
|
:rtype: :py:obj:`None`
|
|
173
263
|
|
|
174
264
|
"""
|
|
265
|
+
if not message_id:
|
|
266
|
+
message_id = str(uuid.uuid4())
|
|
267
|
+
|
|
175
268
|
await self._sns_client.publish(
|
|
176
269
|
**{
|
|
177
270
|
"TargetArn": target_arn,
|
|
@@ -181,13 +274,38 @@ class AsyncNotificationManager:
|
|
|
181
274
|
}
|
|
182
275
|
)
|
|
183
276
|
|
|
277
|
+
async def send_sms_batch(self, to_numbers: Sequence[str], message: str) -> None:
|
|
278
|
+
"""
|
|
279
|
+
Sends an sms message to each phone number in ``to_numbers``.
|
|
280
|
+
|
|
281
|
+
:param to_numbers: A sequence of phone numbers.
|
|
282
|
+
:type to_numbers: :py:obj:`~collections.abc.Sequence`
|
|
283
|
+
:param message: A message body.
|
|
284
|
+
:type message: :py:obj:`str`
|
|
285
|
+
:raises ValidationError: If a ``to_number`` wasn't a valid E.164 formatted phone number.
|
|
286
|
+
:returns: Nothing.
|
|
287
|
+
:rtype: :py:obj:`None`
|
|
184
288
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
289
|
+
"""
|
|
290
|
+
for to_number in to_numbers:
|
|
291
|
+
validate_e164_phone_number(to_number)
|
|
292
|
+
|
|
293
|
+
await asyncio.gather(
|
|
294
|
+
*[self.send_sms(to_number=num, message=message) for num in to_numbers]
|
|
189
295
|
)
|
|
190
296
|
|
|
297
|
+
async def send_push_batch(self, target_arns: Sequence[str], message: str) -> None:
|
|
298
|
+
"""
|
|
299
|
+
Sends a push notification to each AWS resource by ARN in ``target_arns``.
|
|
191
300
|
|
|
192
|
-
|
|
193
|
-
|
|
301
|
+
:param target_arns: A sequence of AWS resource ARNs.
|
|
302
|
+
:type target_arns: :py:obj:`~collections.abc.Sequence`
|
|
303
|
+
:param message: A message body.
|
|
304
|
+
:type message: :py:obj:`str`
|
|
305
|
+
:returns: Nothing.
|
|
306
|
+
:rtype: :py:obj:`None`
|
|
307
|
+
|
|
308
|
+
"""
|
|
309
|
+
await asyncio.gather(
|
|
310
|
+
*[self.send_push(target_arn=arn, message=message) for arn in target_arns]
|
|
311
|
+
)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import os
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from contextlib import AsyncExitStack
|
|
5
|
+
|
|
6
|
+
from aiobotocore.session import AioSession
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AsyncSpeechSynthesisManager:
|
|
10
|
+
def __init__(
|
|
11
|
+
self, bucket_name: str | None = None, region_name: str = "us-east-1"
|
|
12
|
+
) -> None:
|
|
13
|
+
self._exit_stack = AsyncExitStack()
|
|
14
|
+
self._polly_client = None
|
|
15
|
+
self._region_name = region_name
|
|
16
|
+
self._bucket_name = bucket_name or os.getenv("AWS_POLLY_BUCKET_NAME", "")
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def region_name(self) -> str:
|
|
20
|
+
"""
|
|
21
|
+
An AWS region name.
|
|
22
|
+
|
|
23
|
+
:type: :py:obj:`str`
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
return self._region_name
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def bucket_name(self) -> str:
|
|
30
|
+
"""
|
|
31
|
+
The AWS bucket that will host audio files.
|
|
32
|
+
|
|
33
|
+
:type: :py:obj:`str`
|
|
34
|
+
|
|
35
|
+
"""
|
|
36
|
+
return self._bucket_name
|
|
37
|
+
|
|
38
|
+
async def __aenter__(self) -> "AsyncSpeechSynthesisManager":
|
|
39
|
+
"""
|
|
40
|
+
Creates an asyncronous session and client.
|
|
41
|
+
|
|
42
|
+
:returns: The polly manager.
|
|
43
|
+
:rtype: :py:obj:`~terminusgps.aws.notifications.AsyncPollyManager`
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
session = AioSession()
|
|
47
|
+
self._polly_client = await self._exit_stack.enter_async_context(
|
|
48
|
+
session.create_client("polly", region_name=self.region_name)
|
|
49
|
+
)
|
|
50
|
+
return self
|
|
51
|
+
|
|
52
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
53
|
+
"""
|
|
54
|
+
Destroys the asyncronous session.
|
|
55
|
+
|
|
56
|
+
:param exc_type: Exception type.
|
|
57
|
+
:param exc_val: Exception value.
|
|
58
|
+
:param exc_tb: Exception traceback.
|
|
59
|
+
:returns: Nothing.
|
|
60
|
+
:rtype: :py:obj:`None`
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
await self._exit_stack.__aexit__(exc_type, exc_val, exc_tb)
|
|
64
|
+
|
|
65
|
+
async def synthesize_speech(
|
|
66
|
+
self,
|
|
67
|
+
message: str,
|
|
68
|
+
format: str = "ogg_vorbis",
|
|
69
|
+
sample_rate: int = 22050,
|
|
70
|
+
language_code: str = "en-US",
|
|
71
|
+
) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Synthesizes the message into an audio file and saves it to the S3 bucket.
|
|
74
|
+
|
|
75
|
+
:param message: A message to be read aloud.
|
|
76
|
+
:type message: :py:obj:`str`
|
|
77
|
+
:param format: A file format. Default is ``"ogg_vorbis"``.
|
|
78
|
+
:type format: :py:obj:`str`
|
|
79
|
+
:param sample_rate: The audio frequency in Hz. Default is ``22050``.
|
|
80
|
+
:type sample_rate: :py:obj:`int`
|
|
81
|
+
:param language_code: The language to use in the synthesis. Default is ``"en-US"``.
|
|
82
|
+
:type language_code: :py:obj:`str`
|
|
83
|
+
:returns: The audio file URI.
|
|
84
|
+
:rtype: :py:obj:`str`
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
response = await self._polly_client.start_speech_synthesis_task(
|
|
88
|
+
**{
|
|
89
|
+
"Engine": "standard",
|
|
90
|
+
"LanguageCode": language_code,
|
|
91
|
+
"OutputFormat": format,
|
|
92
|
+
"OutputS3BucketName": self.bucket_name,
|
|
93
|
+
"SampleRate": str(sample_rate),
|
|
94
|
+
"Text": f"<speak>{message}</speak>",
|
|
95
|
+
"TextType": "ssml",
|
|
96
|
+
"VoiceId": "Joanna",
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
print(f"{response = }")
|
|
100
|
+
return response.get("SynthesisTask", {}).get("OutputUri", "")
|
|
101
|
+
|
|
102
|
+
async def synthesize_speech_batch(
|
|
103
|
+
self,
|
|
104
|
+
messages: Sequence[str],
|
|
105
|
+
format: str = "ogg_vorbis",
|
|
106
|
+
sample_rate: int = 22050,
|
|
107
|
+
language_code: str = "en-US",
|
|
108
|
+
) -> None:
|
|
109
|
+
"""
|
|
110
|
+
Synthesizes a sequence of messages into audio files and saves them to the S3 bucket.
|
|
111
|
+
|
|
112
|
+
:param messages: A sequence of messages to be read aloud.
|
|
113
|
+
:type messages: :py:obj:`Sequence`
|
|
114
|
+
:param format: A file format. Default is ``"ogg_vorbis"``.
|
|
115
|
+
:type format: :py:obj:`str`
|
|
116
|
+
:param sample_rate: The audio frequency in Hz. Default is ``22050``.
|
|
117
|
+
:type sample_rate: :py:obj:`int`
|
|
118
|
+
:param language_code: The language to use in the synthesis. Default is ``"en-US"``.
|
|
119
|
+
:type language_code: :py:obj:`str`
|
|
120
|
+
:returns: A list of audio file URIs.
|
|
121
|
+
:rtype: :py:obj:`list`
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
await asyncio.gather(
|
|
125
|
+
*[
|
|
126
|
+
self.synthesize_speech(
|
|
127
|
+
message=message,
|
|
128
|
+
format=format,
|
|
129
|
+
sample_rate=sample_rate,
|
|
130
|
+
language_code=language_code,
|
|
131
|
+
)
|
|
132
|
+
for message in messages
|
|
133
|
+
]
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
async def main() -> None:
|
|
138
|
+
async with AsyncSpeechSynthesisManager() as manager:
|
|
139
|
+
uri = await manager.synthesize_speech(
|
|
140
|
+
"Oh yeah, I'm creating another test audio file."
|
|
141
|
+
)
|
|
142
|
+
print(f"{uri = }")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
asyncio.run(main())
|
terminusgps/django/validators.py
CHANGED
|
@@ -5,7 +5,7 @@ VALID_COUNTRY_CODES = ("+1", "+52")
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def validate_e164_phone_number(value: str) -> None:
|
|
8
|
-
"""Raises :py:
|
|
8
|
+
"""Raises :py:exc:`~django.core.exceptions.ValidationError` if the value is not a valid `E.164 <https://en.wikipedia.org/wiki/E.164>`_ formatted phone number."""
|
|
9
9
|
if not value.startswith("+"):
|
|
10
10
|
raise ValidationError(
|
|
11
11
|
_("E.164 phone number must begin with a '+', got '%(char)s'."),
|
|
File without changes
|
{python_terminusgps-34.0.0.dist-info → python_terminusgps-35.0.0.dist-info}/licenses/COPYING
RENAMED
|
File without changes
|