cartesia 0.0.3__py2.py3-none-any.whl → 0.0.4__py2.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.
- cartesia/tts.py +52 -12
- cartesia/version.py +1 -1
- {cartesia-0.0.3.dist-info → cartesia-0.0.4.dist-info}/METADATA +4 -2
- cartesia-0.0.4.dist-info/RECORD +7 -0
- cartesia-0.0.3.dist-info/RECORD +0 -7
- {cartesia-0.0.3.dist-info → cartesia-0.0.4.dist-info}/WHEEL +0 -0
- {cartesia-0.0.3.dist-info → cartesia-0.0.4.dist-info}/top_level.txt +0 -0
cartesia/tts.py
CHANGED
@@ -31,7 +31,11 @@ class CartesiaTTS:
|
|
31
31
|
"""The client for Cartesia's text-to-speech library.
|
32
32
|
|
33
33
|
This client contains methods to interact with the Cartesia text-to-speech API.
|
34
|
-
The
|
34
|
+
The client can be used to retrieve available voices, compute new voice embeddings,
|
35
|
+
and generate speech from text.
|
36
|
+
|
37
|
+
The client also supports generating audio using a websocket for lower latency.
|
38
|
+
To enable interrupt handling along the websocket, set `experimental_ws_handle_interrupts=True`.
|
35
39
|
|
36
40
|
Examples:
|
37
41
|
|
@@ -55,18 +59,22 @@ class CartesiaTTS:
|
|
55
59
|
... audio, sr = audio_chunk["audio"], audio_chunk["sampling_rate"]
|
56
60
|
"""
|
57
61
|
|
58
|
-
def __init__(self, *, api_key: str = None):
|
62
|
+
def __init__(self, *, api_key: str = None, experimental_ws_handle_interrupts: bool = False):
|
59
63
|
"""
|
60
64
|
Args:
|
61
65
|
api_key: The API key to use for authorization.
|
62
66
|
If not specified, the API key will be read from the environment variable
|
63
67
|
`CARTESIA_API_KEY`.
|
68
|
+
experimental_ws_handle_interrupts: Whether to handle interrupts when generating
|
69
|
+
audio using the websocket. This is an experimental feature and may have bugs
|
70
|
+
or be deprecated in the future.
|
64
71
|
"""
|
65
72
|
self.base_url = os.environ.get("CARTESIA_BASE_URL", DEFAULT_BASE_URL)
|
66
73
|
self.api_key = api_key or os.environ.get("CARTESIA_API_KEY")
|
67
74
|
self.api_version = os.environ.get("CARTESIA_API_VERSION", DEFAULT_API_VERSION)
|
68
75
|
self.headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
|
69
76
|
self.websocket = None
|
77
|
+
self.experimental_ws_handle_interrupts = experimental_ws_handle_interrupts
|
70
78
|
self.refresh_websocket()
|
71
79
|
|
72
80
|
def get_voices(self, skip_embeddings: bool = True) -> Dict[str, VoiceMetadata]:
|
@@ -167,8 +175,11 @@ class CartesiaTTS:
|
|
167
175
|
"""
|
168
176
|
if self.websocket and not self._is_websocket_closed():
|
169
177
|
self.websocket.close()
|
178
|
+
route = "audio/websocket"
|
179
|
+
if self.experimental_ws_handle_interrupts:
|
180
|
+
route = f"experimental/{route}"
|
170
181
|
self.websocket = connect(
|
171
|
-
f"{self._ws_url()}/
|
182
|
+
f"{self._ws_url()}/{route}?api_key={self.api_key}",
|
172
183
|
close_timeout=None,
|
173
184
|
)
|
174
185
|
|
@@ -280,21 +291,50 @@ class CartesiaTTS:
|
|
280
291
|
except json.JSONDecodeError:
|
281
292
|
pass
|
282
293
|
|
283
|
-
def _generate_ws(self, body: Dict[str, Any]):
|
294
|
+
def _generate_ws(self, body: Dict[str, Any], *, context_id: str = None):
|
295
|
+
"""Generate audio using the websocket connection.
|
296
|
+
|
297
|
+
Args:
|
298
|
+
body: The request body.
|
299
|
+
context_id: The context id for the request.
|
300
|
+
The context id must be globally unique for the duration this client exists.
|
301
|
+
If this is provided, the context id that is in the response will
|
302
|
+
also be returned as part of the dict. This is helpful for testing.
|
303
|
+
"""
|
284
304
|
if not self.websocket or self._is_websocket_closed():
|
285
305
|
self.refresh_websocket()
|
286
306
|
|
287
|
-
|
307
|
+
include_context_id = bool(context_id)
|
308
|
+
if context_id is None:
|
309
|
+
context_id = uuid.uuid4().hex
|
310
|
+
self.websocket.send(json.dumps({"data": body, "context_id": context_id}))
|
288
311
|
try:
|
289
|
-
|
290
|
-
|
312
|
+
while True:
|
313
|
+
response = json.loads(self.websocket.recv())
|
314
|
+
if response["done"]:
|
315
|
+
break
|
291
316
|
audio = base64.b64decode(response["data"])
|
292
|
-
# print("timing", time.perf_counter() - start)
|
293
|
-
yield {"audio": audio, "sampling_rate": response["sampling_rate"]}
|
294
317
|
|
295
|
-
|
296
|
-
|
297
|
-
|
318
|
+
optional_kwargs = {}
|
319
|
+
if include_context_id:
|
320
|
+
optional_kwargs["context_id"] = response["context_id"]
|
321
|
+
|
322
|
+
yield {
|
323
|
+
"audio": audio,
|
324
|
+
"sampling_rate": response["sampling_rate"],
|
325
|
+
**optional_kwargs,
|
326
|
+
}
|
327
|
+
|
328
|
+
if self.experimental_ws_handle_interrupts:
|
329
|
+
self.websocket.send(json.dumps({"context_id": context_id}))
|
330
|
+
except GeneratorExit:
|
331
|
+
# The exit is only called when the generator is garbage collected.
|
332
|
+
# It may not be called directly after a break statement.
|
333
|
+
# However, the generator will be automatically cancelled on the next request.
|
334
|
+
if self.experimental_ws_handle_interrupts:
|
335
|
+
self.websocket.send(json.dumps({"context_id": context_id, "action": "cancel"}))
|
336
|
+
except Exception as e:
|
337
|
+
raise RuntimeError(f"Failed to generate audio. {response}") from e
|
298
338
|
|
299
339
|
def _http_url(self):
|
300
340
|
prefix = "http" if "localhost" in self.base_url else "https"
|
cartesia/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.0.
|
1
|
+
__version__ = "0.0.4"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: cartesia
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.4
|
4
4
|
Summary: The official Python library for the Cartesia API.
|
5
5
|
Home-page:
|
6
6
|
Author: Cartesia, Inc.
|
@@ -110,4 +110,6 @@ audio = Audio(audio_data, rate=output["sampling_rate"])
|
|
110
110
|
display(audio)
|
111
111
|
```
|
112
112
|
|
113
|
-
|
113
|
+
To avoid storing your API key in the source code, we recommend doing one of the following:
|
114
|
+
1. Use [`python-dotenv`](https://pypi.org/project/python-dotenv/) to add `CARTESIA_API_KEY="my-api-key"` to your .env file.
|
115
|
+
1. Set the `CARTESIA_API_KEY` environment variable, preferably to a secure shell init file (e.g. `~/.zshrc`, `~/.bashrc`)
|
@@ -0,0 +1,7 @@
|
|
1
|
+
cartesia/__init__.py,sha256=m8BX-qLjsMoI_JZtgf3jNi8R3cBZqYy-z4oEhYeJLdI,64
|
2
|
+
cartesia/tts.py,sha256=9m9_kqscMY0yzUU0Ty5k2HoeMqfrIbHouaS-ymcr64s,14127
|
3
|
+
cartesia/version.py,sha256=1mptEzQihbdyqqzMgdns_j5ZGK9gz7hR2bsgA_TnjO4,22
|
4
|
+
cartesia-0.0.4.dist-info/METADATA,sha256=tLUrKLREJiXrW-pfd3k61i9CnElKHk5RAyidCMxpR-s,3752
|
5
|
+
cartesia-0.0.4.dist-info/WHEEL,sha256=iYlv5fX357PQyRT2o6tw1bN-YcKFFHKqB_LwHO5wP-g,110
|
6
|
+
cartesia-0.0.4.dist-info/top_level.txt,sha256=rTX4HnnCegMxl1FK9czpVC7GAvf3SwDzPG65qP-BS4w,9
|
7
|
+
cartesia-0.0.4.dist-info/RECORD,,
|
cartesia-0.0.3.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
cartesia/__init__.py,sha256=m8BX-qLjsMoI_JZtgf3jNi8R3cBZqYy-z4oEhYeJLdI,64
|
2
|
-
cartesia/tts.py,sha256=ABXW9rc8Pn0GTRvb_7DHZKMtbvhGUiqOgHmvztwlOnI,12033
|
3
|
-
cartesia/version.py,sha256=4GZKi13lDTD25YBkGakhZyEQZWTER_OWQMNPoH_UM2c,22
|
4
|
-
cartesia-0.0.3.dist-info/METADATA,sha256=VsCGL1sITbKqERihK2rzVm9WIY5EJ5nCS_CXQ0s14ns,3604
|
5
|
-
cartesia-0.0.3.dist-info/WHEEL,sha256=iYlv5fX357PQyRT2o6tw1bN-YcKFFHKqB_LwHO5wP-g,110
|
6
|
-
cartesia-0.0.3.dist-info/top_level.txt,sha256=rTX4HnnCegMxl1FK9czpVC7GAvf3SwDzPG65qP-BS4w,9
|
7
|
-
cartesia-0.0.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|