@cartesia/cartesia-js 1.0.0-alpha.3 → 1.0.0

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.
@@ -8,21 +8,21 @@ $ tsup src/ --format cjs,esm --dts
8
8
  ESM dist/index.js 437.00 B
9
9
  ESM dist/chunk-FXPGR372.js 0 B
10
10
  ESM dist/lib/client.js 132.00 B
11
- ESM dist/react/index.js 6.22 KB
11
+ ESM dist/react/index.js 6.35 KB
12
12
  ESM dist/tts/index.js 261.00 B
13
13
  ESM dist/lib/constants.js 183.00 B
14
14
  ESM dist/lib/index.js 322.00 B
15
- ESM dist/chunk-ISRU7PLL.js 353.00 B
15
+ ESM dist/chunk-IEN4NCER.js 353.00 B
16
16
  ESM dist/chunk-SGXUEFII.js 1.35 KB
17
17
  ESM dist/react/utils.js 109.00 B
18
18
  ESM dist/chunk-3FL2SNIR.js 337.00 B
19
- ESM dist/chunk-VK7LBMVI.js 439.00 B
20
- ESM dist/chunk-IQAXBRHU.js 5.84 KB
19
+ ESM dist/chunk-F4QWVJY3.js 439.00 B
20
+ ESM dist/chunk-FN7BK4PS.js 6.11 KB
21
21
  ESM dist/chunk-PQ6CIPFW.js 4.02 KB
22
22
  ESM dist/chunk-PQ5EVEEH.js 841.00 B
23
23
  ESM dist/chunk-2BFEKY3F.js 366.00 B
24
24
  ESM dist/tts/player.js 143.00 B
25
- ESM dist/chunk-36JBKJUN.js 3.52 KB
25
+ ESM dist/chunk-JYLAM6VU.js 3.76 KB
26
26
  ESM dist/chunk-RO7TY474.js 1.95 KB
27
27
  ESM dist/chunk-WIFMLPT5.js 2.27 KB
28
28
  ESM dist/types/index.js 31.00 B
@@ -30,32 +30,32 @@ $ tsup src/ --format cjs,esm --dts
30
30
  ESM dist/tts/source.js 112.00 B
31
31
  ESM dist/tts/utils.js 395.00 B
32
32
  ESM dist/tts/websocket.js 242.00 B
33
- ESM ⚡️ Build success in 97ms
34
- CJS dist/index.cjs 21.01 KB
33
+ ESM ⚡️ Build success in 108ms
34
+ CJS dist/index.cjs 21.48 KB
35
35
  CJS dist/lib/client.cjs 3.34 KB
36
36
  CJS dist/lib/constants.cjs 1.43 KB
37
- CJS dist/lib/index.cjs 17.18 KB
38
- CJS dist/react/index.cjs 27.24 KB
37
+ CJS dist/lib/index.cjs 17.45 KB
38
+ CJS dist/react/index.cjs 27.85 KB
39
39
  CJS dist/react/utils.cjs 1.80 KB
40
- CJS dist/tts/index.cjs 15.66 KB
41
- CJS dist/tts/player.cjs 6.66 KB
40
+ CJS dist/tts/index.cjs 15.93 KB
41
+ CJS dist/tts/player.cjs 6.87 KB
42
42
  CJS dist/tts/source.cjs 6.63 KB
43
43
  CJS dist/tts/utils.cjs 3.87 KB
44
- CJS dist/tts/websocket.cjs 15.34 KB
44
+ CJS dist/tts/websocket.cjs 15.62 KB
45
45
  CJS dist/types/index.cjs 764.00 B
46
46
  CJS dist/voices/index.cjs 5.04 KB
47
- CJS ⚡️ Build success in 101ms
47
+ CJS ⚡️ Build success in 111ms
48
48
  DTS Build start
49
- DTS ⚡️ Build success in 6609ms
49
+ DTS ⚡️ Build success in 6545ms
50
50
  DTS dist/index.d.cts 509.00 B
51
51
  DTS dist/lib/constants.d.cts 564.00 B
52
52
  DTS dist/lib/index.d.cts 410.00 B
53
53
  DTS dist/react/index.d.cts 1018.00 B
54
54
  DTS dist/react/utils.d.cts 240.00 B
55
55
  DTS dist/tts/index.d.cts 471.00 B
56
- DTS dist/tts/player.d.cts 1.06 KB
56
+ DTS dist/tts/player.d.cts 1.20 KB
57
57
  DTS dist/tts/utils.d.cts 2.56 KB
58
- DTS dist/tts/websocket.d.cts 2.39 KB
58
+ DTS dist/tts/websocket.d.cts 2.66 KB
59
59
  DTS dist/tts/source.d.cts 2.17 KB
60
60
  DTS dist/voices/index.d.cts 399.00 B
61
61
  DTS dist/lib/client.d.cts 267.00 B
@@ -66,9 +66,9 @@ $ tsup src/ --format cjs,esm --dts
66
66
  DTS dist/react/index.d.ts 1016.00 B
67
67
  DTS dist/react/utils.d.ts 240.00 B
68
68
  DTS dist/tts/index.d.ts 467.00 B
69
- DTS dist/tts/player.d.ts 1.06 KB
69
+ DTS dist/tts/player.d.ts 1.20 KB
70
70
  DTS dist/tts/utils.d.ts 2.55 KB
71
- DTS dist/tts/websocket.d.ts 2.39 KB
71
+ DTS dist/tts/websocket.d.ts 2.65 KB
72
72
  DTS dist/tts/source.d.ts 2.16 KB
73
73
  DTS dist/voices/index.d.ts 397.00 B
74
74
  DTS dist/lib/client.d.ts 266.00 B
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @cartesia/cartesia-js
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 3ee5bfc: Initial release of Cartesia client with voices and WebSocket support
8
+
9
+ ### Minor Changes
10
+
11
+ - e49f73a: Stabilize audio playback in the browser to support play/pause functionality.
12
+
13
+ ### Patch Changes
14
+
15
+ - c98a0c7: Fix typo in README
16
+ - 38af01f: Fix how URLs are constructed, solving WebSocket connection failure
17
+ - 8ecf940: Add provisional Node.js support
18
+ - 585d2c9: Makes JS client compatible with the Cartesia Stable API (2024-06-10)
19
+
20
+ ## 1.0.0-alpha.4
21
+
22
+ ### Patch Changes
23
+
24
+ - c98a0c7: Fix typo in README
25
+
3
26
  ## 1.0.0-alpha.3
4
27
 
5
28
  ### Patch Changes
package/README.md CHANGED
@@ -1,4 +1,12 @@
1
- # JavaScript Client for Cartesia
1
+ # Cartesia JavaScript Client
2
+
3
+ ![NPM Version](https://img.shields.io/npm/v/%40cartesia%2Fcartesia-js?logo=npm)
4
+ [![Discord](https://badgen.net/badge/black/Cartesia/icon?icon=discord&label)](https://discord.gg/ZVxavqHB9X)
5
+
6
+ This client provides convenient access to [Cartesia's TTS models](https://cartesia.ai/). Sonic is the fastest text-to-speech model around—it can generate a second of audio in just 650ms, and it can stream out the first audio chunk in just 135ms. Alongside Sonic, we also offer an extensive prebuilt voice library for a variety of use cases.
7
+
8
+ The full API documentation can be found on docs.cartesia.ai.
9
+
2
10
 
3
11
  ## Installation
4
12
 
@@ -98,10 +106,10 @@ for await (const message of response.events('message')) {
98
106
 
99
107
  #### Playing audio in the browser
100
108
 
101
- (We currently only support playing audio in the browser. Support for other JS environments is coming soon.)
109
+ (The `WebPlayer` class only supports playing audio in the browser.)
102
110
 
103
111
  ```js
104
- // If you're using the client in the browser, you can play the audio like this:
112
+ // If you're using the client in the browser, you can control audio playback using our WebPlayer:
105
113
  import { WebPlayer } from "@cartesia/cartesia-js";
106
114
 
107
115
  console.log("Playing stream...");
@@ -118,7 +126,7 @@ console.log("Done playing.");
118
126
 
119
127
  ## React
120
128
 
121
- We export a React hook that simplifies the process of using the TTS API. The hook manages the WebSocket connection and provides a simple interface for buffering and playing audio.
129
+ We export a React hook that simplifies the process of using the TTS API. The hook manages the WebSocket connection and provides a simple interface for buffering, playing, pausing and restarting audio.
122
130
 
123
131
  ```jsx
124
132
  import { useTTS } from '@cartesia/cartesia-js/react';
@@ -126,7 +134,7 @@ import { useTTS } from '@cartesia/cartesia-js/react';
126
134
  function TextToSpeech() {
127
135
  const tts = useTTS({
128
136
  apiKey: "your-api-key",
129
- samplingRate: 44100,
137
+ sampleRate: 44100,
130
138
  })
131
139
 
132
140
  const [text, setText] = useState("");
@@ -134,7 +142,7 @@ function TextToSpeech() {
134
142
  const handlePlay = async () => {
135
143
  // Begin buffering the audio.
136
144
  const response = await tts.buffer({
137
- model: "upbeat-moon",
145
+ model_id: "upbeat-moon",
138
146
  voice: {
139
147
  mode: "embedding",
140
148
  embedding: Array(192).fill(1.0),
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  WebSocket
3
- } from "./chunk-IQAXBRHU.js";
3
+ } from "./chunk-FN7BK4PS.js";
4
4
  import {
5
5
  Client
6
6
  } from "./chunk-PQ5EVEEH.js";
@@ -51,13 +51,15 @@ var WebSocket = class extends Client {
51
51
  __privateSet(this, _sampleRate, sampleRate);
52
52
  }
53
53
  /**
54
- * Send a message over the WebSocket in order to start a stream.
54
+ * Send a message over the WebSocket to start a stream.
55
55
  *
56
56
  * @param inputs - Stream options.
57
57
  * @param options - Options for the stream.
58
58
  * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
59
- * If `0`, the stream will not time out.
59
+ * If set to `0`, the stream will not time out.
60
60
  * @returns A Source object that can be passed to a Player to play the audio.
61
+ * @returns An Emittery instance that emits messages from the WebSocket.
62
+ * @returns An abort function that can be called to cancel the stream.
61
63
  */
62
64
  send(inputs, { timeout = 0 } = {}) {
63
65
  var _a, _b, _c, _d;
@@ -128,7 +130,11 @@ var WebSocket = class extends Client {
128
130
  clearTimeout(timeoutId);
129
131
  }
130
132
  });
131
- return __spreadValues({ source }, getEmitteryCallbacks(emitter));
133
+ return __spreadProps(__spreadValues({
134
+ source
135
+ }, getEmitteryCallbacks(emitter)), {
136
+ stop: streamCompleteController.abort.bind(streamCompleteController)
137
+ });
132
138
  }
133
139
  /**
134
140
  * Authenticate and connect to a Cartesia streaming WebSocket.
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-SGXUEFII.js";
4
4
  import {
5
5
  TTS
6
- } from "./chunk-VK7LBMVI.js";
6
+ } from "./chunk-F4QWVJY3.js";
7
7
  import {
8
8
  Client
9
9
  } from "./chunk-PQ5EVEEH.js";
@@ -10,8 +10,7 @@ import {
10
10
  } from "./chunk-WIFMLPT5.js";
11
11
 
12
12
  // src/tts/player.ts
13
- import Emittery from "emittery";
14
- var _context, _startNextPlaybackAt, _bufferDuration, _emitter, _playBuffer, playBuffer_fn;
13
+ var _context, _startNextPlaybackAt, _bufferDuration, _playBuffer, playBuffer_fn;
15
14
  var Player = class {
16
15
  /**
17
16
  * Create a new Player.
@@ -24,7 +23,6 @@ var Player = class {
24
23
  __privateAdd(this, _context, null);
25
24
  __privateAdd(this, _startNextPlaybackAt, 0);
26
25
  __privateAdd(this, _bufferDuration, void 0);
27
- __privateAdd(this, _emitter, new Emittery());
28
26
  __privateSet(this, _bufferDuration, bufferDuration);
29
27
  }
30
28
  /**
@@ -46,7 +44,6 @@ var Player = class {
46
44
  const playableAudio = buffer.subarray(0, read);
47
45
  plays.push(__privateMethod(this, _playBuffer, playBuffer_fn).call(this, playableAudio, source.sampleRate));
48
46
  if (read < buffer.length) {
49
- yield __privateGet(this, _emitter).emit("finish");
50
47
  break;
51
48
  }
52
49
  }
@@ -96,17 +93,33 @@ var Player = class {
96
93
  }
97
94
  });
98
95
  }
96
+ /**
97
+ * Stop the audio.
98
+ *
99
+ * @returns A promise that resolves when the audio has been stopped.
100
+ */
101
+ stop() {
102
+ return __async(this, null, function* () {
103
+ var _a;
104
+ if (!__privateGet(this, _context)) {
105
+ throw new Error("AudioContext not initialized.");
106
+ }
107
+ yield (_a = __privateGet(this, _context)) == null ? void 0 : _a.close();
108
+ });
109
+ }
99
110
  };
100
111
  _context = new WeakMap();
101
112
  _startNextPlaybackAt = new WeakMap();
102
113
  _bufferDuration = new WeakMap();
103
- _emitter = new WeakMap();
104
114
  _playBuffer = new WeakSet();
105
115
  playBuffer_fn = function(buf, sampleRate) {
106
116
  return __async(this, null, function* () {
107
117
  if (!__privateGet(this, _context)) {
108
118
  throw new Error("AudioContext not initialized.");
109
119
  }
120
+ if (buf.length === 0) {
121
+ return;
122
+ }
110
123
  const startAt = __privateGet(this, _startNextPlaybackAt);
111
124
  const duration = buf.length / sampleRate;
112
125
  __privateSet(this, _startNextPlaybackAt, duration + Math.max(__privateGet(this, _context).currentTime, __privateGet(this, _startNextPlaybackAt)));
package/dist/index.cjs CHANGED
@@ -336,13 +336,15 @@ var WebSocket = class extends Client {
336
336
  __privateSet(this, _sampleRate2, sampleRate);
337
337
  }
338
338
  /**
339
- * Send a message over the WebSocket in order to start a stream.
339
+ * Send a message over the WebSocket to start a stream.
340
340
  *
341
341
  * @param inputs - Stream options.
342
342
  * @param options - Options for the stream.
343
343
  * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
344
- * If `0`, the stream will not time out.
344
+ * If set to `0`, the stream will not time out.
345
345
  * @returns A Source object that can be passed to a Player to play the audio.
346
+ * @returns An Emittery instance that emits messages from the WebSocket.
347
+ * @returns An abort function that can be called to cancel the stream.
346
348
  */
347
349
  send(inputs, { timeout = 0 } = {}) {
348
350
  var _a, _b, _c, _d;
@@ -413,7 +415,11 @@ var WebSocket = class extends Client {
413
415
  clearTimeout(timeoutId);
414
416
  }
415
417
  });
416
- return __spreadValues({ source }, getEmitteryCallbacks(emitter));
418
+ return __spreadProps(__spreadValues({
419
+ source
420
+ }, getEmitteryCallbacks(emitter)), {
421
+ stop: streamCompleteController.abort.bind(streamCompleteController)
422
+ });
417
423
  }
418
424
  /**
419
425
  * Authenticate and connect to a Cartesia streaming WebSocket.
@@ -564,8 +570,7 @@ var Cartesia = class extends Client {
564
570
  };
565
571
 
566
572
  // src/tts/player.ts
567
- var import_emittery3 = __toESM(require("emittery"), 1);
568
- var _context, _startNextPlaybackAt, _bufferDuration, _emitter2, _playBuffer, playBuffer_fn;
573
+ var _context, _startNextPlaybackAt, _bufferDuration, _playBuffer, playBuffer_fn;
569
574
  var Player = class {
570
575
  /**
571
576
  * Create a new Player.
@@ -578,7 +583,6 @@ var Player = class {
578
583
  __privateAdd(this, _context, null);
579
584
  __privateAdd(this, _startNextPlaybackAt, 0);
580
585
  __privateAdd(this, _bufferDuration, void 0);
581
- __privateAdd(this, _emitter2, new import_emittery3.default());
582
586
  __privateSet(this, _bufferDuration, bufferDuration);
583
587
  }
584
588
  /**
@@ -600,7 +604,6 @@ var Player = class {
600
604
  const playableAudio = buffer.subarray(0, read);
601
605
  plays.push(__privateMethod(this, _playBuffer, playBuffer_fn).call(this, playableAudio, source.sampleRate));
602
606
  if (read < buffer.length) {
603
- yield __privateGet(this, _emitter2).emit("finish");
604
607
  break;
605
608
  }
606
609
  }
@@ -650,17 +653,33 @@ var Player = class {
650
653
  }
651
654
  });
652
655
  }
656
+ /**
657
+ * Stop the audio.
658
+ *
659
+ * @returns A promise that resolves when the audio has been stopped.
660
+ */
661
+ stop() {
662
+ return __async(this, null, function* () {
663
+ var _a;
664
+ if (!__privateGet(this, _context)) {
665
+ throw new Error("AudioContext not initialized.");
666
+ }
667
+ yield (_a = __privateGet(this, _context)) == null ? void 0 : _a.close();
668
+ });
669
+ }
653
670
  };
654
671
  _context = new WeakMap();
655
672
  _startNextPlaybackAt = new WeakMap();
656
673
  _bufferDuration = new WeakMap();
657
- _emitter2 = new WeakMap();
658
674
  _playBuffer = new WeakSet();
659
675
  playBuffer_fn = function(buf, sampleRate) {
660
676
  return __async(this, null, function* () {
661
677
  if (!__privateGet(this, _context)) {
662
678
  throw new Error("AudioContext not initialized.");
663
679
  }
680
+ if (buf.length === 0) {
681
+ return;
682
+ }
664
683
  const startAt = __privateGet(this, _startNextPlaybackAt);
665
684
  const duration = buf.length / sampleRate;
666
685
  __privateSet(this, _startNextPlaybackAt, duration + Math.max(__privateGet(this, _context).currentTime, __privateGet(this, _startNextPlaybackAt)));
package/dist/index.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import "./chunk-FXPGR372.js";
2
2
  import {
3
3
  Cartesia
4
- } from "./chunk-ISRU7PLL.js";
4
+ } from "./chunk-IEN4NCER.js";
5
5
  import "./chunk-SGXUEFII.js";
6
- import "./chunk-VK7LBMVI.js";
7
- import "./chunk-IQAXBRHU.js";
6
+ import "./chunk-F4QWVJY3.js";
7
+ import "./chunk-FN7BK4PS.js";
8
8
  import "./chunk-PQ6CIPFW.js";
9
9
  import "./chunk-PQ5EVEEH.js";
10
10
  import "./chunk-2BFEKY3F.js";
11
11
  import {
12
12
  Player
13
- } from "./chunk-36JBKJUN.js";
13
+ } from "./chunk-JYLAM6VU.js";
14
14
  import "./chunk-RO7TY474.js";
15
15
  import "./chunk-WIFMLPT5.js";
16
16
  export {
@@ -321,13 +321,15 @@ var WebSocket = class extends Client {
321
321
  __privateSet(this, _sampleRate2, sampleRate);
322
322
  }
323
323
  /**
324
- * Send a message over the WebSocket in order to start a stream.
324
+ * Send a message over the WebSocket to start a stream.
325
325
  *
326
326
  * @param inputs - Stream options.
327
327
  * @param options - Options for the stream.
328
328
  * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
329
- * If `0`, the stream will not time out.
329
+ * If set to `0`, the stream will not time out.
330
330
  * @returns A Source object that can be passed to a Player to play the audio.
331
+ * @returns An Emittery instance that emits messages from the WebSocket.
332
+ * @returns An abort function that can be called to cancel the stream.
331
333
  */
332
334
  send(inputs, { timeout = 0 } = {}) {
333
335
  var _a, _b, _c, _d;
@@ -398,7 +400,11 @@ var WebSocket = class extends Client {
398
400
  clearTimeout(timeoutId);
399
401
  }
400
402
  });
401
- return __spreadValues({ source }, getEmitteryCallbacks(emitter));
403
+ return __spreadProps(__spreadValues({
404
+ source
405
+ }, getEmitteryCallbacks(emitter)), {
406
+ stop: streamCompleteController.abort.bind(streamCompleteController)
407
+ });
402
408
  }
403
409
  /**
404
410
  * Authenticate and connect to a Cartesia streaming WebSocket.
package/dist/lib/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  Cartesia
3
- } from "../chunk-ISRU7PLL.js";
3
+ } from "../chunk-IEN4NCER.js";
4
4
  import "../chunk-SGXUEFII.js";
5
- import "../chunk-VK7LBMVI.js";
6
- import "../chunk-IQAXBRHU.js";
5
+ import "../chunk-F4QWVJY3.js";
6
+ import "../chunk-FN7BK4PS.js";
7
7
  import "../chunk-PQ6CIPFW.js";
8
8
  import "../chunk-PQ5EVEEH.js";
9
9
  import "../chunk-2BFEKY3F.js";
@@ -335,13 +335,15 @@ var WebSocket = class extends Client {
335
335
  __privateSet(this, _sampleRate2, sampleRate);
336
336
  }
337
337
  /**
338
- * Send a message over the WebSocket in order to start a stream.
338
+ * Send a message over the WebSocket to start a stream.
339
339
  *
340
340
  * @param inputs - Stream options.
341
341
  * @param options - Options for the stream.
342
342
  * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
343
- * If `0`, the stream will not time out.
343
+ * If set to `0`, the stream will not time out.
344
344
  * @returns A Source object that can be passed to a Player to play the audio.
345
+ * @returns An Emittery instance that emits messages from the WebSocket.
346
+ * @returns An abort function that can be called to cancel the stream.
345
347
  */
346
348
  send(inputs, { timeout = 0 } = {}) {
347
349
  var _a, _b, _c, _d;
@@ -412,7 +414,11 @@ var WebSocket = class extends Client {
412
414
  clearTimeout(timeoutId);
413
415
  }
414
416
  });
415
- return __spreadValues({ source }, getEmitteryCallbacks(emitter));
417
+ return __spreadProps(__spreadValues({
418
+ source
419
+ }, getEmitteryCallbacks(emitter)), {
420
+ stop: streamCompleteController.abort.bind(streamCompleteController)
421
+ });
416
422
  }
417
423
  /**
418
424
  * Authenticate and connect to a Cartesia streaming WebSocket.
@@ -563,8 +569,7 @@ var Cartesia = class extends Client {
563
569
  };
564
570
 
565
571
  // src/tts/player.ts
566
- var import_emittery3 = __toESM(require("emittery"), 1);
567
- var _context, _startNextPlaybackAt, _bufferDuration, _emitter2, _playBuffer, playBuffer_fn;
572
+ var _context, _startNextPlaybackAt, _bufferDuration, _playBuffer, playBuffer_fn;
568
573
  var Player = class {
569
574
  /**
570
575
  * Create a new Player.
@@ -577,7 +582,6 @@ var Player = class {
577
582
  __privateAdd(this, _context, null);
578
583
  __privateAdd(this, _startNextPlaybackAt, 0);
579
584
  __privateAdd(this, _bufferDuration, void 0);
580
- __privateAdd(this, _emitter2, new import_emittery3.default());
581
585
  __privateSet(this, _bufferDuration, bufferDuration);
582
586
  }
583
587
  /**
@@ -599,7 +603,6 @@ var Player = class {
599
603
  const playableAudio = buffer.subarray(0, read);
600
604
  plays.push(__privateMethod(this, _playBuffer, playBuffer_fn).call(this, playableAudio, source.sampleRate));
601
605
  if (read < buffer.length) {
602
- yield __privateGet(this, _emitter2).emit("finish");
603
606
  break;
604
607
  }
605
608
  }
@@ -649,17 +652,33 @@ var Player = class {
649
652
  }
650
653
  });
651
654
  }
655
+ /**
656
+ * Stop the audio.
657
+ *
658
+ * @returns A promise that resolves when the audio has been stopped.
659
+ */
660
+ stop() {
661
+ return __async(this, null, function* () {
662
+ var _a;
663
+ if (!__privateGet(this, _context)) {
664
+ throw new Error("AudioContext not initialized.");
665
+ }
666
+ yield (_a = __privateGet(this, _context)) == null ? void 0 : _a.close();
667
+ });
668
+ }
652
669
  };
653
670
  _context = new WeakMap();
654
671
  _startNextPlaybackAt = new WeakMap();
655
672
  _bufferDuration = new WeakMap();
656
- _emitter2 = new WeakMap();
657
673
  _playBuffer = new WeakSet();
658
674
  playBuffer_fn = function(buf, sampleRate) {
659
675
  return __async(this, null, function* () {
660
676
  if (!__privateGet(this, _context)) {
661
677
  throw new Error("AudioContext not initialized.");
662
678
  }
679
+ if (buf.length === 0) {
680
+ return;
681
+ }
663
682
  const startAt = __privateGet(this, _startNextPlaybackAt);
664
683
  const duration = buf.length / sampleRate;
665
684
  __privateSet(this, _startNextPlaybackAt, duration + Math.max(__privateGet(this, _context).currentTime, __privateGet(this, _startNextPlaybackAt)));
@@ -726,10 +745,11 @@ function useTTS({
726
745
  const [messages, setMessages] = (0, import_react.useState)([]);
727
746
  const buffer = (0, import_react.useCallback)(
728
747
  (options) => __async(this, null, function* () {
729
- var _a2;
748
+ var _a2, _b2;
749
+ (_a2 = websocketReturn.current) == null ? void 0 : _a2.stop();
730
750
  setMessages([]);
731
751
  setBufferStatus("buffering");
732
- websocketReturn.current = (_a2 = websocket == null ? void 0 : websocket.send(options)) != null ? _a2 : null;
752
+ websocketReturn.current = (_b2 = websocket == null ? void 0 : websocket.send(options)) != null ? _b2 : null;
733
753
  if (!websocketReturn.current) {
734
754
  return;
735
755
  }
@@ -812,6 +832,9 @@ function useTTS({
812
832
  if (playbackStatus === "playing" || !websocketReturn.current) {
813
833
  return;
814
834
  }
835
+ if (player.current) {
836
+ yield player.current.stop();
837
+ }
815
838
  setPlaybackStatus("playing");
816
839
  const unsubscribes = [];
817
840
  unsubscribes.push(
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  Cartesia
3
- } from "../chunk-ISRU7PLL.js";
3
+ } from "../chunk-IEN4NCER.js";
4
4
  import "../chunk-SGXUEFII.js";
5
5
  import {
6
6
  pingServer
7
7
  } from "../chunk-3FL2SNIR.js";
8
- import "../chunk-VK7LBMVI.js";
9
- import "../chunk-IQAXBRHU.js";
8
+ import "../chunk-F4QWVJY3.js";
9
+ import "../chunk-FN7BK4PS.js";
10
10
  import "../chunk-PQ6CIPFW.js";
11
11
  import "../chunk-PQ5EVEEH.js";
12
12
  import "../chunk-2BFEKY3F.js";
13
13
  import {
14
14
  Player
15
- } from "../chunk-36JBKJUN.js";
15
+ } from "../chunk-JYLAM6VU.js";
16
16
  import "../chunk-RO7TY474.js";
17
17
  import {
18
18
  __async
@@ -68,10 +68,11 @@ function useTTS({
68
68
  const [messages, setMessages] = useState([]);
69
69
  const buffer = useCallback(
70
70
  (options) => __async(this, null, function* () {
71
- var _a2;
71
+ var _a2, _b2;
72
+ (_a2 = websocketReturn.current) == null ? void 0 : _a2.stop();
72
73
  setMessages([]);
73
74
  setBufferStatus("buffering");
74
- websocketReturn.current = (_a2 = websocket == null ? void 0 : websocket.send(options)) != null ? _a2 : null;
75
+ websocketReturn.current = (_b2 = websocket == null ? void 0 : websocket.send(options)) != null ? _b2 : null;
75
76
  if (!websocketReturn.current) {
76
77
  return;
77
78
  }
@@ -154,6 +155,9 @@ function useTTS({
154
155
  if (playbackStatus === "playing" || !websocketReturn.current) {
155
156
  return;
156
157
  }
158
+ if (player.current) {
159
+ yield player.current.stop();
160
+ }
157
161
  setPlaybackStatus("playing");
158
162
  const unsubscribes = [];
159
163
  unsubscribes.push(
@@ -321,13 +321,15 @@ var WebSocket = class extends Client {
321
321
  __privateSet(this, _sampleRate2, sampleRate);
322
322
  }
323
323
  /**
324
- * Send a message over the WebSocket in order to start a stream.
324
+ * Send a message over the WebSocket to start a stream.
325
325
  *
326
326
  * @param inputs - Stream options.
327
327
  * @param options - Options for the stream.
328
328
  * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
329
- * If `0`, the stream will not time out.
329
+ * If set to `0`, the stream will not time out.
330
330
  * @returns A Source object that can be passed to a Player to play the audio.
331
+ * @returns An Emittery instance that emits messages from the WebSocket.
332
+ * @returns An abort function that can be called to cancel the stream.
331
333
  */
332
334
  send(inputs, { timeout = 0 } = {}) {
333
335
  var _a, _b, _c, _d;
@@ -398,7 +400,11 @@ var WebSocket = class extends Client {
398
400
  clearTimeout(timeoutId);
399
401
  }
400
402
  });
401
- return __spreadValues({ source }, getEmitteryCallbacks(emitter));
403
+ return __spreadProps(__spreadValues({
404
+ source
405
+ }, getEmitteryCallbacks(emitter)), {
406
+ stop: streamCompleteController.abort.bind(streamCompleteController)
407
+ });
402
408
  }
403
409
  /**
404
410
  * Authenticate and connect to a Cartesia streaming WebSocket.
package/dist/tts/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TTS
3
- } from "../chunk-VK7LBMVI.js";
4
- import "../chunk-IQAXBRHU.js";
3
+ } from "../chunk-F4QWVJY3.js";
4
+ import "../chunk-FN7BK4PS.js";
5
5
  import "../chunk-PQ6CIPFW.js";
6
6
  import "../chunk-PQ5EVEEH.js";
7
7
  import "../chunk-2BFEKY3F.js";
@@ -75,7 +75,6 @@ __export(player_exports, {
75
75
  default: () => Player
76
76
  });
77
77
  module.exports = __toCommonJS(player_exports);
78
- var import_emittery = __toESM(require("emittery"), 1);
79
78
 
80
79
  // src/tts/utils.ts
81
80
  var import_base64_js = __toESM(require("base64-js"), 1);
@@ -94,7 +93,7 @@ function playAudioBuffer(floats, context, startAt, sampleRate) {
94
93
  }
95
94
 
96
95
  // src/tts/player.ts
97
- var _context, _startNextPlaybackAt, _bufferDuration, _emitter, _playBuffer, playBuffer_fn;
96
+ var _context, _startNextPlaybackAt, _bufferDuration, _playBuffer, playBuffer_fn;
98
97
  var Player = class {
99
98
  /**
100
99
  * Create a new Player.
@@ -107,7 +106,6 @@ var Player = class {
107
106
  __privateAdd(this, _context, null);
108
107
  __privateAdd(this, _startNextPlaybackAt, 0);
109
108
  __privateAdd(this, _bufferDuration, void 0);
110
- __privateAdd(this, _emitter, new import_emittery.default());
111
109
  __privateSet(this, _bufferDuration, bufferDuration);
112
110
  }
113
111
  /**
@@ -129,7 +127,6 @@ var Player = class {
129
127
  const playableAudio = buffer.subarray(0, read);
130
128
  plays.push(__privateMethod(this, _playBuffer, playBuffer_fn).call(this, playableAudio, source.sampleRate));
131
129
  if (read < buffer.length) {
132
- yield __privateGet(this, _emitter).emit("finish");
133
130
  break;
134
131
  }
135
132
  }
@@ -179,17 +176,33 @@ var Player = class {
179
176
  }
180
177
  });
181
178
  }
179
+ /**
180
+ * Stop the audio.
181
+ *
182
+ * @returns A promise that resolves when the audio has been stopped.
183
+ */
184
+ stop() {
185
+ return __async(this, null, function* () {
186
+ var _a;
187
+ if (!__privateGet(this, _context)) {
188
+ throw new Error("AudioContext not initialized.");
189
+ }
190
+ yield (_a = __privateGet(this, _context)) == null ? void 0 : _a.close();
191
+ });
192
+ }
182
193
  };
183
194
  _context = new WeakMap();
184
195
  _startNextPlaybackAt = new WeakMap();
185
196
  _bufferDuration = new WeakMap();
186
- _emitter = new WeakMap();
187
197
  _playBuffer = new WeakSet();
188
198
  playBuffer_fn = function(buf, sampleRate) {
189
199
  return __async(this, null, function* () {
190
200
  if (!__privateGet(this, _context)) {
191
201
  throw new Error("AudioContext not initialized.");
192
202
  }
203
+ if (buf.length === 0) {
204
+ return;
205
+ }
193
206
  const startAt = __privateGet(this, _startNextPlaybackAt);
194
207
  const duration = buf.length / sampleRate;
195
208
  __privateSet(this, _startNextPlaybackAt, duration + Math.max(__privateGet(this, _context).currentTime, __privateGet(this, _startNextPlaybackAt)));
@@ -38,6 +38,12 @@ declare class Player {
38
38
  * @returns A promise that resolves when the audio has been toggled.
39
39
  */
40
40
  toggle(): Promise<void>;
41
+ /**
42
+ * Stop the audio.
43
+ *
44
+ * @returns A promise that resolves when the audio has been stopped.
45
+ */
46
+ stop(): Promise<void>;
41
47
  }
42
48
 
43
49
  export { Player as default };
@@ -38,6 +38,12 @@ declare class Player {
38
38
  * @returns A promise that resolves when the audio has been toggled.
39
39
  */
40
40
  toggle(): Promise<void>;
41
+ /**
42
+ * Stop the audio.
43
+ *
44
+ * @returns A promise that resolves when the audio has been stopped.
45
+ */
46
+ stop(): Promise<void>;
41
47
  }
42
48
 
43
49
  export { Player as default };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Player
3
- } from "../chunk-36JBKJUN.js";
3
+ } from "../chunk-JYLAM6VU.js";
4
4
  import "../chunk-RO7TY474.js";
5
5
  import "../chunk-WIFMLPT5.js";
6
6
  export {
@@ -319,13 +319,15 @@ var WebSocket = class extends Client {
319
319
  __privateSet(this, _sampleRate2, sampleRate);
320
320
  }
321
321
  /**
322
- * Send a message over the WebSocket in order to start a stream.
322
+ * Send a message over the WebSocket to start a stream.
323
323
  *
324
324
  * @param inputs - Stream options.
325
325
  * @param options - Options for the stream.
326
326
  * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
327
- * If `0`, the stream will not time out.
327
+ * If set to `0`, the stream will not time out.
328
328
  * @returns A Source object that can be passed to a Player to play the audio.
329
+ * @returns An Emittery instance that emits messages from the WebSocket.
330
+ * @returns An abort function that can be called to cancel the stream.
329
331
  */
330
332
  send(inputs, { timeout = 0 } = {}) {
331
333
  var _a, _b, _c, _d;
@@ -396,7 +398,11 @@ var WebSocket = class extends Client {
396
398
  clearTimeout(timeoutId);
397
399
  }
398
400
  });
399
- return __spreadValues({ source }, getEmitteryCallbacks(emitter));
401
+ return __spreadProps(__spreadValues({
402
+ source
403
+ }, getEmitteryCallbacks(emitter)), {
404
+ stop: streamCompleteController.abort.bind(streamCompleteController)
405
+ });
400
406
  }
401
407
  /**
402
408
  * Authenticate and connect to a Cartesia streaming WebSocket.
@@ -14,15 +14,21 @@ declare class WebSocket extends Client {
14
14
  */
15
15
  constructor({ sampleRate }: WebSocketOptions, ...args: ConstructorParameters<typeof Client>);
16
16
  /**
17
- * Send a message over the WebSocket in order to start a stream.
17
+ * Send a message over the WebSocket to start a stream.
18
18
  *
19
19
  * @param inputs - Stream options.
20
20
  * @param options - Options for the stream.
21
21
  * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
22
- * If `0`, the stream will not time out.
22
+ * If set to `0`, the stream will not time out.
23
23
  * @returns A Source object that can be passed to a Player to play the audio.
24
+ * @returns An Emittery instance that emits messages from the WebSocket.
25
+ * @returns An abort function that can be called to cancel the stream.
24
26
  */
25
27
  send(inputs: StreamRequest["inputs"], { timeout }?: StreamRequest["options"]): {
28
+ stop: {
29
+ (reason?: any): void;
30
+ (reason?: any): void;
31
+ };
26
32
  on: <Name extends keyof emittery.OmnipresentEventData | "message">(eventName: Name | readonly Name[], listener: (eventData: ({
27
33
  message: string;
28
34
  } & emittery.OmnipresentEventData)[Name]) => void | Promise<void>) => emittery.UnsubscribeFunction;
@@ -14,15 +14,21 @@ declare class WebSocket extends Client {
14
14
  */
15
15
  constructor({ sampleRate }: WebSocketOptions, ...args: ConstructorParameters<typeof Client>);
16
16
  /**
17
- * Send a message over the WebSocket in order to start a stream.
17
+ * Send a message over the WebSocket to start a stream.
18
18
  *
19
19
  * @param inputs - Stream options.
20
20
  * @param options - Options for the stream.
21
21
  * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
22
- * If `0`, the stream will not time out.
22
+ * If set to `0`, the stream will not time out.
23
23
  * @returns A Source object that can be passed to a Player to play the audio.
24
+ * @returns An Emittery instance that emits messages from the WebSocket.
25
+ * @returns An abort function that can be called to cancel the stream.
24
26
  */
25
27
  send(inputs: StreamRequest["inputs"], { timeout }?: StreamRequest["options"]): {
28
+ stop: {
29
+ (reason?: any): void;
30
+ (reason?: any): void;
31
+ };
26
32
  on: <Name extends keyof emittery.OmnipresentEventData | "message">(eventName: Name | readonly Name[], listener: (eventData: ({
27
33
  message: string;
28
34
  } & emittery.OmnipresentEventData)[Name]) => void | Promise<void>) => emittery.UnsubscribeFunction;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  WebSocket
3
- } from "../chunk-IQAXBRHU.js";
3
+ } from "../chunk-FN7BK4PS.js";
4
4
  import "../chunk-PQ6CIPFW.js";
5
5
  import "../chunk-PQ5EVEEH.js";
6
6
  import "../chunk-2BFEKY3F.js";
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "name": "Cartesia",
5
5
  "url": "https://cartesia.ai"
6
6
  },
7
- "version": "1.0.0-alpha.3",
7
+ "version": "1.0.0",
8
8
  "description": "Client for the Cartesia API.",
9
9
  "type": "module",
10
10
  "module": "./dist/index.js",
@@ -86,6 +86,8 @@ export function useTTS({
86
86
 
87
87
  const buffer = useCallback(
88
88
  async (options: object) => {
89
+ websocketReturn.current?.stop(); // Abort the previous request if it exists.
90
+
89
91
  setMessages([]);
90
92
  setBufferStatus("buffering");
91
93
  websocketReturn.current = websocket?.send(options) ?? null;
@@ -174,6 +176,11 @@ export function useTTS({
174
176
  if (playbackStatus === "playing" || !websocketReturn.current) {
175
177
  return;
176
178
  }
179
+ if (player.current) {
180
+ // Stop the current player if it exists.
181
+ await player.current.stop();
182
+ }
183
+
177
184
  setPlaybackStatus("playing");
178
185
 
179
186
  const unsubscribes = [];
@@ -225,9 +232,6 @@ export function useTTS({
225
232
  });
226
233
  }, []);
227
234
 
228
- // TODO:
229
- // - [] Access the play and buffer cursors.
230
- // - [] Seek to a specific time.
231
235
  return {
232
236
  buffer,
233
237
  play,
package/src/tts/player.ts CHANGED
@@ -1,16 +1,10 @@
1
- import Emittery from "emittery";
2
1
  import type Source from "./source";
3
2
  import { playAudioBuffer } from "./utils";
4
3
 
5
- type PlayEventData = {
6
- finish: never;
7
- };
8
-
9
4
  export default class Player {
10
5
  #context: AudioContext | null = null;
11
6
  #startNextPlaybackAt = 0;
12
7
  #bufferDuration: number;
13
- #emitter = new Emittery<PlayEventData>();
14
8
 
15
9
  /**
16
10
  * Create a new Player.
@@ -26,6 +20,9 @@ export default class Player {
26
20
  if (!this.#context) {
27
21
  throw new Error("AudioContext not initialized.");
28
22
  }
23
+ if (buf.length === 0) {
24
+ return;
25
+ }
29
26
 
30
27
  const startAt = this.#startNextPlaybackAt;
31
28
  const duration = buf.length / sampleRate;
@@ -60,11 +57,9 @@ export default class Player {
60
57
 
61
58
  if (read < buffer.length) {
62
59
  // No more audio to read.
63
- await this.#emitter.emit("finish");
64
60
  break;
65
61
  }
66
62
  }
67
-
68
63
  await Promise.all(plays);
69
64
  }
70
65
 
@@ -107,4 +102,16 @@ export default class Player {
107
102
  await this.resume();
108
103
  }
109
104
  }
105
+
106
+ /**
107
+ * Stop the audio.
108
+ *
109
+ * @returns A promise that resolves when the audio has been stopped.
110
+ */
111
+ async stop() {
112
+ if (!this.#context) {
113
+ throw new Error("AudioContext not initialized.");
114
+ }
115
+ await this.#context?.close();
116
+ }
110
117
  }
@@ -37,13 +37,15 @@ export default class WebSocket extends Client {
37
37
  }
38
38
 
39
39
  /**
40
- * Send a message over the WebSocket in order to start a stream.
40
+ * Send a message over the WebSocket to start a stream.
41
41
  *
42
42
  * @param inputs - Stream options.
43
43
  * @param options - Options for the stream.
44
44
  * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
45
- * If `0`, the stream will not time out.
45
+ * If set to `0`, the stream will not time out.
46
46
  * @returns A Source object that can be passed to a Player to play the audio.
47
+ * @returns An Emittery instance that emits messages from the WebSocket.
48
+ * @returns An abort function that can be called to cancel the stream.
47
49
  */
48
50
  send(
49
51
  inputs: StreamRequest["inputs"],
@@ -125,7 +127,11 @@ export default class WebSocket extends Client {
125
127
  }
126
128
  });
127
129
 
128
- return { source, ...getEmitteryCallbacks(emitter) };
130
+ return {
131
+ source,
132
+ ...getEmitteryCallbacks(emitter),
133
+ stop: streamCompleteController.abort.bind(streamCompleteController),
134
+ };
129
135
  }
130
136
 
131
137
  /**