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 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 API offers
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()}/audio/websocket?api_key={self.api_key}",
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
- self.websocket.send(json.dumps({"data": body, "context_id": uuid.uuid4().hex}))
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
- response = json.loads(self.websocket.recv())
290
- while not response["done"]:
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
- response = json.loads(self.websocket.recv())
296
- except Exception:
297
- raise RuntimeError(f"Failed to generate audio. {response}")
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.3"
1
+ __version__ = "0.0.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cartesia
3
- Version: 0.0.3
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
- We recommend using [`python-dotenv`](https://pypi.org/project/python-dotenv/) to add `CARTESIA_API_KEY="my-api-key"` to your .env file so that your API Key is not stored in the source code.
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,,
@@ -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,,