@cartesia/cartesia-js 0.0.3 → 1.0.0-alpha.1

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.
Files changed (103) hide show
  1. package/.turbo/turbo-build.log +68 -38
  2. package/CHANGELOG.md +12 -0
  3. package/README.md +123 -16
  4. package/dist/chunk-3FL2SNIR.js +17 -0
  5. package/dist/chunk-3GBZUGUD.js +17 -0
  6. package/dist/chunk-4RMSIQLG.js +25 -0
  7. package/dist/chunk-BCQ63627.js +32 -0
  8. package/dist/chunk-JOHSCOLW.js +106 -0
  9. package/dist/chunk-LYPTISWL.js +75 -0
  10. package/dist/chunk-NDNN326Q.js +207 -0
  11. package/dist/chunk-WBK6LLXX.js +58 -0
  12. package/dist/chunk-WE63M7PJ.js +119 -0
  13. package/dist/{chunk-HNLIBHEN.mjs → chunk-WIFMLPT5.js} +31 -16
  14. package/dist/chunk-X7SJMF2R.js +22 -0
  15. package/dist/index.cjs +652 -0
  16. package/dist/index.d.cts +10 -0
  17. package/dist/index.d.ts +10 -0
  18. package/dist/index.js +20 -0
  19. package/dist/lib/client.cjs +89 -0
  20. package/dist/lib/client.d.cts +11 -0
  21. package/dist/lib/client.d.ts +2 -0
  22. package/dist/lib/client.js +7 -42
  23. package/dist/lib/constants.cjs +42 -0
  24. package/dist/lib/constants.d.cts +4 -0
  25. package/dist/lib/constants.d.ts +2 -3
  26. package/dist/lib/constants.js +8 -37
  27. package/dist/lib/index.cjs +531 -0
  28. package/dist/lib/index.d.cts +16 -0
  29. package/dist/lib/index.d.ts +6 -2
  30. package/dist/lib/index.js +13 -409
  31. package/dist/react/index.cjs +846 -0
  32. package/dist/react/index.d.cts +33 -0
  33. package/dist/react/index.d.ts +20 -13
  34. package/dist/react/index.js +161 -501
  35. package/dist/react/utils.cjs +57 -0
  36. package/dist/react/utils.d.cts +7 -0
  37. package/dist/react/utils.d.ts +7 -0
  38. package/dist/react/utils.js +7 -0
  39. package/dist/tts/index.cjs +470 -0
  40. package/dist/tts/index.d.cts +17 -0
  41. package/dist/tts/index.d.ts +17 -0
  42. package/dist/tts/index.js +12 -0
  43. package/dist/tts/player.cjs +198 -0
  44. package/dist/tts/player.d.cts +43 -0
  45. package/dist/tts/player.d.ts +43 -0
  46. package/dist/tts/player.js +8 -0
  47. package/dist/tts/source.cjs +167 -0
  48. package/dist/tts/source.d.cts +53 -0
  49. package/dist/tts/source.d.ts +53 -0
  50. package/dist/tts/source.js +7 -0
  51. package/dist/{audio/utils.js → tts/utils.cjs} +13 -54
  52. package/dist/tts/utils.d.cts +67 -0
  53. package/dist/tts/utils.d.ts +67 -0
  54. package/dist/{audio/utils.mjs → tts/utils.js} +2 -6
  55. package/dist/tts/websocket.cjs +453 -0
  56. package/dist/tts/websocket.d.cts +53 -0
  57. package/dist/tts/websocket.d.ts +53 -0
  58. package/dist/tts/websocket.js +11 -0
  59. package/dist/types/index.cjs +18 -0
  60. package/dist/types/index.d.cts +55 -0
  61. package/dist/types/index.d.ts +50 -1
  62. package/dist/types/index.js +1 -18
  63. package/dist/voices/index.cjs +155 -0
  64. package/dist/voices/index.d.cts +12 -0
  65. package/dist/voices/index.d.ts +12 -0
  66. package/dist/voices/index.js +9 -0
  67. package/package.json +11 -7
  68. package/src/index.ts +4 -0
  69. package/src/lib/client.ts +14 -1
  70. package/src/lib/constants.ts +13 -3
  71. package/src/lib/index.ts +6 -3
  72. package/src/react/index.ts +167 -75
  73. package/src/react/utils.ts +11 -0
  74. package/src/tts/index.ts +17 -0
  75. package/src/tts/player.ts +109 -0
  76. package/src/tts/source.ts +98 -0
  77. package/src/{audio → tts}/utils.ts +19 -97
  78. package/src/tts/websocket.ts +210 -0
  79. package/src/types/index.ts +63 -0
  80. package/src/voices/index.ts +47 -0
  81. package/dist/audio/index.d.mts +0 -5
  82. package/dist/audio/index.d.ts +0 -5
  83. package/dist/audio/index.js +0 -396
  84. package/dist/audio/index.mjs +0 -9
  85. package/dist/audio/utils.d.mts +0 -5
  86. package/dist/audio/utils.d.ts +0 -5
  87. package/dist/chunk-3CYTAFLF.mjs +0 -262
  88. package/dist/chunk-FRIBQZPN.mjs +0 -113
  89. package/dist/chunk-XSFPHPPG.mjs +0 -18
  90. package/dist/index-DSBmfK9-.d.mts +0 -158
  91. package/dist/index-qwAyxV5I.d.ts +0 -158
  92. package/dist/lib/client.d.mts +0 -9
  93. package/dist/lib/client.mjs +0 -7
  94. package/dist/lib/constants.d.mts +0 -5
  95. package/dist/lib/constants.mjs +0 -10
  96. package/dist/lib/index.d.mts +0 -12
  97. package/dist/lib/index.mjs +0 -19
  98. package/dist/react/index.d.mts +0 -26
  99. package/dist/react/index.mjs +0 -130
  100. package/dist/types/index.d.mts +0 -6
  101. package/index.ts +0 -3
  102. package/src/audio/index.ts +0 -282
  103. /package/dist/{types/index.mjs → chunk-FXPGR372.js} +0 -0
@@ -1,514 +1,136 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
- var __knownSymbol = (name, symbol) => {
11
- return (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
12
- };
13
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
14
- var __spreadValues = (a, b) => {
15
- for (var prop in b || (b = {}))
16
- if (__hasOwnProp.call(b, prop))
17
- __defNormalProp(a, prop, b[prop]);
18
- if (__getOwnPropSymbols)
19
- for (var prop of __getOwnPropSymbols(b)) {
20
- if (__propIsEnum.call(b, prop))
21
- __defNormalProp(a, prop, b[prop]);
22
- }
23
- return a;
24
- };
25
- var __export = (target, all) => {
26
- for (var name in all)
27
- __defProp(target, name, { get: all[name], enumerable: true });
28
- };
29
- var __copyProps = (to, from, except, desc) => {
30
- if (from && typeof from === "object" || typeof from === "function") {
31
- for (let key of __getOwnPropNames(from))
32
- if (!__hasOwnProp.call(to, key) && key !== except)
33
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
34
- }
35
- return to;
36
- };
37
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
38
- // If the importer is in node compatibility mode or this is not an ESM
39
- // file that has been converted to a CommonJS file using a Babel-
40
- // compatible transform (i.e. "__esModule" has not been set), then set
41
- // "default" to the CommonJS "module.exports" for node compatibility.
42
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
43
- mod
44
- ));
45
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
46
- var __async = (__this, __arguments, generator) => {
47
- return new Promise((resolve, reject) => {
48
- var fulfilled = (value) => {
49
- try {
50
- step(generator.next(value));
51
- } catch (e) {
52
- reject(e);
53
- }
54
- };
55
- var rejected = (value) => {
56
- try {
57
- step(generator.throw(value));
58
- } catch (e) {
59
- reject(e);
60
- }
61
- };
62
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
63
- step((generator = generator.apply(__this, __arguments)).next());
64
- });
65
- };
66
- var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
67
-
68
- // src/react/index.ts
69
- var react_exports = {};
70
- __export(react_exports, {
71
- useAudio: () => useAudio
72
- });
73
- module.exports = __toCommonJS(react_exports);
74
- var import_react = require("react");
75
-
76
- // src/audio/index.ts
77
- var import_emittery = __toESM(require("emittery"));
78
- var import_human_id = require("human-id");
79
- var import_partysocket = require("partysocket");
80
-
81
- // src/lib/constants.ts
82
- var BASE_URL = "https://api.cartesia.ai/v0";
83
- var SAMPLE_RATE = 44100;
84
- var constructWebsocketUrl = (baseUrl) => {
85
- return new URL(`${baseUrl.replace(/^http/, "ws")}/audio/websocket`);
86
- };
87
-
88
- // src/lib/client.ts
89
- var Client = class {
90
- constructor(options = {}) {
91
- if (!(options.apiKey || process.env.CARTESIA_API_KEY)) {
92
- throw new Error("Missing Cartesia API key.");
93
- }
94
- this.apiKey = options.apiKey || process.env.CARTESIA_API_KEY;
95
- this.baseUrl = options.baseUrl || BASE_URL;
96
- }
97
- };
98
-
99
- // src/audio/utils.ts
100
- var import_base64_js = __toESM(require("base64-js"));
101
- function getBufferDuration(b64) {
102
- const floats = base64ToArray(b64);
103
- return floats.length / SAMPLE_RATE;
104
- }
105
- function base64ToArray(b64) {
106
- return filterSentinel(b64).reduce((acc, b) => {
107
- const floats = new Float32Array(import_base64_js.default.toByteArray(b).buffer);
108
- const newAcc = new Float32Array(acc.length + floats.length);
109
- newAcc.set(acc, 0);
110
- newAcc.set(floats, acc.length);
111
- return newAcc;
112
- }, new Float32Array(0));
113
- }
114
- function playAudioBuffer(b64, context, maybeStartAt = null, onEnded = null) {
115
- const startAt = maybeStartAt != null ? maybeStartAt : context.currentTime;
116
- const floats = base64ToArray(b64);
117
- const source = context.createBufferSource();
118
- const buffer = context.createBuffer(1, floats.length, SAMPLE_RATE);
119
- buffer.getChannelData(0).set(floats);
120
- source.buffer = buffer;
121
- source.connect(context.destination);
122
- source.start(startAt);
123
- source.onended = onEnded;
124
- return buffer.duration;
125
- }
126
- function createMessageHandlerForContextId(contextId, handler) {
127
- return (event) => {
128
- const message = JSON.parse(event.data);
129
- if (message.context_id !== contextId) {
130
- return;
131
- }
132
- let chunk;
133
- if (message.done) {
134
- chunk = getSentinel();
135
- } else {
136
- chunk = message.data;
137
- }
138
- handler({ chunk, message });
139
- };
140
- }
141
- function getSentinel() {
142
- return null;
143
- }
144
- function isSentinel(x) {
145
- return x === getSentinel();
146
- }
147
- function filterSentinel(collection) {
148
- return collection.filter(
149
- (x) => !isSentinel(x)
150
- );
151
- }
152
- function isComplete(chunks) {
153
- return isSentinel(chunks[chunks.length - 1]);
154
- }
155
- function getEmitteryCallbacks(emitter) {
156
- return {
157
- on: emitter.on.bind(emitter),
158
- off: emitter.off.bind(emitter),
159
- once: emitter.once.bind(emitter),
160
- events: emitter.events.bind(emitter)
161
- };
162
- }
163
- function bufferToWav(sampleRate, channelBuffers) {
164
- const totalSamples = channelBuffers[0].length * channelBuffers.length;
165
- const buffer = new ArrayBuffer(44 + totalSamples * 2);
166
- const view = new DataView(buffer);
167
- const writeString = (view2, offset2, string) => {
168
- for (let i = 0; i < string.length; i++) {
169
- view2.setUint8(offset2 + i, string.charCodeAt(i));
170
- }
171
- };
172
- writeString(view, 0, "RIFF");
173
- view.setUint32(4, 36 + totalSamples * 2, true);
174
- writeString(view, 8, "WAVE");
175
- writeString(view, 12, "fmt ");
176
- view.setUint32(16, 16, true);
177
- view.setUint16(20, 1, true);
178
- view.setUint16(22, channelBuffers.length, true);
179
- view.setUint32(24, sampleRate, true);
180
- view.setUint32(28, sampleRate * 4, true);
181
- view.setUint16(32, channelBuffers.length * 2, true);
182
- view.setUint16(34, 16, true);
183
- writeString(view, 36, "data");
184
- view.setUint32(40, totalSamples * 2, true);
185
- let offset = 44;
186
- for (let i = 0; i < channelBuffers[0].length; i++) {
187
- for (let channel = 0; channel < channelBuffers.length; channel++) {
188
- const s = Math.max(-1, Math.min(1, channelBuffers[channel][i]));
189
- view.setInt16(offset, s < 0 ? s * 32768 : s * 32767, true);
190
- offset += 2;
191
- }
192
- }
193
- return buffer;
194
- }
195
-
196
- // src/audio/index.ts
197
- var audio_default = class extends Client {
198
- constructor() {
199
- super(...arguments);
200
- this.isConnected = false;
201
- }
202
- /**
203
- * Stream audio from a model.
204
- *
205
- * @param inputs - Stream options. Includes a `model` key and some `parameters`, which
206
- * are model-specific and can be found in the model's documentation.
207
- * @param options - Options for the stream.
208
- * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
209
- * If `0`, the stream will not time out.
210
- * @returns An object with a method `play` of type `(bufferDuration: number) => Promise<void>`
211
- * that plays the audio as it arrives, with `bufferDuration` seconds of audio buffered before
212
- * starting playback.
213
- */
214
- stream(inputs, { timeout = 0 } = {}) {
215
- var _a, _b, _c, _d;
216
- if (!this.isConnected) {
217
- throw new Error("Not connected to WebSocket. Call .connect() first.");
218
- }
219
- const contextId = this.generateId();
220
- (_a = this.socket) == null ? void 0 : _a.send(
221
- JSON.stringify({
222
- data: inputs,
223
- context_id: contextId
224
- })
225
- );
226
- const streamCompleteController = new AbortController();
227
- let timeoutId = null;
228
- if (timeout > 0) {
229
- timeoutId = setTimeout(streamCompleteController.abort, timeout);
230
- }
231
- const chunks = [];
232
- const emitter = new import_emittery.default();
233
- const handleMessage = createMessageHandlerForContextId(
234
- contextId,
235
- (_0) => __async(this, [_0], function* ({ chunk, message }) {
236
- chunks.push(chunk);
237
- yield emitter.emit("chunk", {
238
- chunk,
239
- chunks
240
- });
241
- yield emitter.emit("message", message);
242
- if (isSentinel(chunk)) {
243
- yield emitter.emit("streamed", {
244
- chunks
245
- });
246
- streamCompleteController.abort();
247
- } else if (timeoutId) {
248
- clearTimeout(timeoutId);
249
- timeoutId = setTimeout(streamCompleteController.abort, timeout);
250
- }
251
- })
252
- );
253
- (_b = this.socket) == null ? void 0 : _b.addEventListener("message", handleMessage, {
254
- signal: streamCompleteController.signal
255
- });
256
- (_c = this.socket) == null ? void 0 : _c.addEventListener(
257
- "close",
258
- () => {
259
- streamCompleteController.abort();
260
- },
261
- {
262
- once: true
263
- }
264
- );
265
- (_d = this.socket) == null ? void 0 : _d.addEventListener(
266
- "error",
267
- () => {
268
- streamCompleteController.abort();
269
- },
270
- {
271
- once: true
272
- }
273
- );
274
- streamCompleteController.signal.addEventListener("abort", () => {
275
- if (timeoutId) {
276
- clearTimeout(timeoutId);
277
- }
278
- emitter.clearListeners();
279
- });
280
- const play = (_0) => __async(this, [_0], function* ({ bufferDuration }) {
281
- const context = new AudioContext({
282
- sampleRate: SAMPLE_RATE
283
- });
284
- let startNextPlaybackAt = 0;
285
- const playLatestChunk = (chunk) => {
286
- if (isSentinel(chunk)) {
287
- return true;
288
- }
289
- startNextPlaybackAt = playAudioBuffer([chunk], context, startNextPlaybackAt) + Math.max(context.currentTime, startNextPlaybackAt);
290
- return false;
291
- };
292
- const playChunks = (chunks2) => {
293
- startNextPlaybackAt += playAudioBuffer(
294
- chunks2,
295
- context,
296
- startNextPlaybackAt
297
- );
298
- if (isComplete(chunks2)) {
299
- return;
300
- }
301
- };
302
- const tryStart = (chunks2) => __async(this, null, function* () {
303
- startNextPlaybackAt = context.currentTime;
304
- if (isComplete(chunks2) || streamCompleteController.signal.aborted) {
305
- playChunks(chunks2);
306
- return true;
307
- }
308
- if (getBufferDuration(chunks2) > bufferDuration) {
309
- playChunks(chunks2);
310
- try {
311
- for (var iter2 = __forAwait(emitter.events("chunk")), more2, temp2, error2; more2 = !(temp2 = yield iter2.next()).done; more2 = false) {
312
- const { chunk } = temp2.value;
313
- if (playLatestChunk(chunk)) {
314
- break;
315
- }
316
- }
317
- } catch (temp2) {
318
- error2 = [temp2];
319
- } finally {
320
- try {
321
- more2 && (temp2 = iter2.return) && (yield temp2.call(iter2));
322
- } finally {
323
- if (error2)
324
- throw error2[0];
325
- }
326
- }
327
- return true;
328
- }
329
- return false;
330
- });
331
- if (!(yield tryStart(chunks))) {
332
- try {
333
- for (var iter = __forAwait(emitter.events("chunk")), more, temp, error; more = !(temp = yield iter.next()).done; more = false) {
334
- const { chunks: chunks2 } = temp.value;
335
- if (yield tryStart(chunks2)) {
336
- break;
337
- }
338
- }
339
- } catch (temp) {
340
- error = [temp];
341
- } finally {
342
- try {
343
- more && (temp = iter.return) && (yield temp.call(iter));
344
- } finally {
345
- if (error)
346
- throw error[0];
347
- }
348
- }
349
- }
350
- });
351
- return __spreadValues({
352
- play
353
- }, getEmitteryCallbacks(emitter));
354
- }
355
- /**
356
- * Generate a unique ID suitable for a streaming context.
357
- *
358
- * Not suitable for security purposes or as a primary key, since
359
- * it lacks the amount of entropy required for those use cases.
360
- *
361
- * @returns A unique ID.
362
- */
363
- generateId() {
364
- return (0, import_human_id.humanId)({
365
- separator: "-",
366
- capitalize: false
367
- });
368
- }
369
- /**
370
- * Authenticate and connect to a Cartesia streaming WebSocket.
371
- *
372
- * @returns A promise that resolves when the WebSocket is connected.
373
- * @throws {Error} If the WebSocket fails to connect.
374
- */
375
- connect() {
376
- const url = constructWebsocketUrl(this.baseUrl);
377
- url.searchParams.set("api_key", this.apiKey);
378
- const emitter = new import_emittery.default();
379
- this.socket = new import_partysocket.WebSocket(url.toString());
380
- this.socket.onopen = () => {
381
- this.isConnected = true;
382
- emitter.emit("open");
383
- };
384
- this.socket.onclose = () => {
385
- this.isConnected = false;
386
- emitter.emit("close");
387
- };
388
- return new Promise(
389
- (resolve, reject) => {
390
- var _a, _b, _c;
391
- (_a = this.socket) == null ? void 0 : _a.addEventListener(
392
- "open",
393
- () => {
394
- resolve(getEmitteryCallbacks(emitter));
395
- },
396
- {
397
- once: true
398
- }
399
- );
400
- const aborter = new AbortController();
401
- (_b = this.socket) == null ? void 0 : _b.addEventListener(
402
- "error",
403
- () => {
404
- aborter.abort();
405
- reject(new Error("WebSocket failed to connect."));
406
- },
407
- {
408
- signal: aborter.signal
409
- }
410
- );
411
- (_c = this.socket) == null ? void 0 : _c.addEventListener(
412
- "close",
413
- () => {
414
- aborter.abort();
415
- reject(new Error("WebSocket closed before it could connect."));
416
- },
417
- {
418
- signal: aborter.signal
419
- }
420
- );
421
- }
422
- );
423
- }
424
- /**
425
- * Disconnect from the Cartesia streaming WebSocket.
426
- */
427
- disconnect() {
428
- var _a;
429
- (_a = this.socket) == null ? void 0 : _a.close();
430
- }
431
- };
1
+ import {
2
+ Cartesia
3
+ } from "../chunk-X7SJMF2R.js";
4
+ import "../chunk-WBK6LLXX.js";
5
+ import {
6
+ pingServer
7
+ } from "../chunk-3FL2SNIR.js";
8
+ import "../chunk-4RMSIQLG.js";
9
+ import "../chunk-NDNN326Q.js";
10
+ import "../chunk-JOHSCOLW.js";
11
+ import "../chunk-BCQ63627.js";
12
+ import "../chunk-3GBZUGUD.js";
13
+ import {
14
+ Player
15
+ } from "../chunk-WE63M7PJ.js";
16
+ import "../chunk-LYPTISWL.js";
17
+ import {
18
+ __async
19
+ } from "../chunk-WIFMLPT5.js";
432
20
 
433
21
  // src/react/index.ts
434
- function useAudio({ apiKey, baseUrl }) {
22
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
23
+ var PING_INTERVAL = 5e3;
24
+ var DEFAULT_BUFFER_DURATION = 0.01;
25
+ function useTTS({
26
+ apiKey,
27
+ baseUrl,
28
+ sampleRate
29
+ }) {
30
+ var _a, _b;
435
31
  if (typeof window === "undefined") {
436
32
  return {
437
- stream: () => {
438
- },
33
+ buffer: () => __async(this, null, function* () {
34
+ }),
439
35
  play: () => __async(this, null, function* () {
440
36
  }),
441
- download: () => null,
37
+ pause: () => __async(this, null, function* () {
38
+ }),
39
+ resume: () => __async(this, null, function* () {
40
+ }),
41
+ toggle: () => __async(this, null, function* () {
42
+ }),
43
+ playbackStatus: "inactive",
44
+ bufferStatus: "inactive",
45
+ isWaiting: false,
46
+ source: null,
442
47
  isConnected: false,
443
- isPlaying: false,
444
- isStreamed: false,
445
- chunks: [],
446
- messages: []
48
+ metrics: {
49
+ modelLatency: null
50
+ }
447
51
  };
448
52
  }
449
- const audio = (0, import_react.useMemo)(() => {
53
+ const websocket = useMemo(() => {
450
54
  if (!apiKey) {
451
55
  return null;
452
56
  }
453
- const audio2 = new audio_default({ apiKey, baseUrl });
454
- return audio2;
455
- }, [apiKey, baseUrl]);
456
- const streamReturn = (0, import_react.useRef)(null);
457
- const [isStreamed, setIsStreamed] = (0, import_react.useState)(false);
458
- const [isPlaying, setIsPlaying] = (0, import_react.useState)(false);
459
- const [isConnected, setIsConnected] = (0, import_react.useState)(false);
460
- const [chunks, setChunks] = (0, import_react.useState)([]);
461
- const [messages, setMessages] = (0, import_react.useState)([]);
462
- const stream = (0, import_react.useCallback)(
57
+ const cartesia = new Cartesia({ apiKey, baseUrl });
58
+ baseUrl = baseUrl != null ? baseUrl : cartesia.baseUrl;
59
+ return cartesia.tts.websocket({ sampleRate });
60
+ }, [apiKey, baseUrl, sampleRate]);
61
+ const websocketReturn = useRef(null);
62
+ const player = useRef(null);
63
+ const [playbackStatus, setPlaybackStatus] = useState("inactive");
64
+ const [bufferStatus, setBufferStatus] = useState("inactive");
65
+ const [isWaiting, setIsWaiting] = useState(false);
66
+ const [isConnected, setIsConnected] = useState(false);
67
+ const [bufferDuration, setBufferDuration] = useState(null);
68
+ const [messages, setMessages] = useState([]);
69
+ const buffer = useCallback(
463
70
  (options) => __async(this, null, function* () {
464
- var _a;
465
- streamReturn.current = (_a = audio == null ? void 0 : audio.stream(options)) != null ? _a : null;
466
- if (!streamReturn.current) {
71
+ var _a2;
72
+ setMessages([]);
73
+ setBufferStatus("buffering");
74
+ websocketReturn.current = (_a2 = websocket == null ? void 0 : websocket.send(options)) != null ? _a2 : null;
75
+ if (!websocketReturn.current) {
467
76
  return;
468
77
  }
469
- setMessages([]);
470
- streamReturn.current.on(
471
- "chunk",
472
- ({ chunks: chunks3 }) => {
473
- setChunks(chunks3);
474
- }
475
- );
476
- streamReturn.current.on(
477
- "message",
478
- (message) => {
479
- setMessages((messages2) => [...messages2, message]);
480
- }
481
- );
482
- const { chunks: chunks2 } = yield streamReturn.current.once("streamed");
483
- setChunks(chunks2);
484
- setIsStreamed(true);
78
+ websocketReturn.current.on("message", (message) => {
79
+ setMessages((messages2) => [...messages2, JSON.parse(message)]);
80
+ });
81
+ yield websocketReturn.current.source.once("close");
82
+ setBufferStatus("buffered");
485
83
  }),
486
- [audio]
84
+ [websocket]
487
85
  );
488
- const download = (0, import_react.useCallback)(() => {
489
- if (!isStreamed) {
490
- return null;
86
+ const metrics = useMemo(() => {
87
+ var _a2;
88
+ if (messages.length === 0) {
89
+ return {
90
+ modelLatency: null
91
+ };
491
92
  }
492
- const audio2 = bufferToWav(SAMPLE_RATE, [base64ToArray(chunks)]);
493
- return new Blob([audio2], { type: "audio/wav" });
494
- }, [isStreamed, chunks]);
495
- (0, import_react.useEffect)(() => {
93
+ const modelLatency = (_a2 = messages[0].step_time) != null ? _a2 : null;
94
+ return {
95
+ modelLatency: Math.trunc(modelLatency)
96
+ };
97
+ }, [messages]);
98
+ useEffect(() => {
496
99
  let cleanup = () => {
497
100
  };
498
101
  function setupConnection() {
499
102
  return __async(this, null, function* () {
500
103
  try {
501
- const connection = yield audio == null ? void 0 : audio.connect();
104
+ const connection = yield websocket == null ? void 0 : websocket.connect();
502
105
  if (!connection) {
503
106
  return;
504
107
  }
505
108
  setIsConnected(true);
109
+ connection.on("open", () => {
110
+ setIsConnected(true);
111
+ });
506
112
  const unsubscribe = connection.on("close", () => {
507
113
  setIsConnected(false);
508
114
  });
115
+ const intervalId = setInterval(() => {
116
+ if (baseUrl) {
117
+ pingServer(new URL(baseUrl).origin).then((ping) => {
118
+ let bufferDuration2;
119
+ if (ping < 300) {
120
+ bufferDuration2 = 0.01;
121
+ } else if (ping > 1500) {
122
+ bufferDuration2 = 6;
123
+ } else {
124
+ bufferDuration2 = ping / 1e3 * 4;
125
+ }
126
+ setBufferDuration(bufferDuration2);
127
+ });
128
+ }
129
+ }, PING_INTERVAL);
509
130
  return () => {
510
131
  unsubscribe();
511
- audio == null ? void 0 : audio.disconnect();
132
+ clearInterval(intervalId);
133
+ websocket == null ? void 0 : websocket.disconnect();
512
134
  };
513
135
  } catch (e) {
514
136
  console.error(e);
@@ -519,31 +141,69 @@ function useAudio({ apiKey, baseUrl }) {
519
141
  cleanup = cleanupConnection;
520
142
  });
521
143
  return () => cleanup == null ? void 0 : cleanup();
522
- }, [audio]);
523
- const play = (0, import_react.useCallback)(
524
- (bufferDuration = 0) => __async(this, null, function* () {
525
- var _a;
526
- if (isPlaying || !streamReturn.current) {
527
- return;
144
+ }, [websocket, baseUrl]);
145
+ const play = useCallback(() => __async(this, null, function* () {
146
+ if (playbackStatus === "playing" || !websocketReturn.current) {
147
+ return;
148
+ }
149
+ setPlaybackStatus("playing");
150
+ const unsubscribes = [];
151
+ unsubscribes.push(
152
+ websocketReturn.current.source.on("wait", () => {
153
+ setIsWaiting(true);
154
+ })
155
+ );
156
+ unsubscribes.push(
157
+ websocketReturn.current.source.on("read", () => {
158
+ setIsWaiting(false);
159
+ })
160
+ );
161
+ player.current = new Player({
162
+ bufferDuration: bufferDuration != null ? bufferDuration : DEFAULT_BUFFER_DURATION
163
+ });
164
+ yield player.current.play(websocketReturn.current.source);
165
+ for (const unsubscribe of unsubscribes) {
166
+ unsubscribe();
167
+ }
168
+ setPlaybackStatus("finished");
169
+ }), [playbackStatus, bufferDuration]);
170
+ const pause = useCallback(() => __async(this, null, function* () {
171
+ var _a2;
172
+ yield (_a2 = player.current) == null ? void 0 : _a2.pause();
173
+ setPlaybackStatus("paused");
174
+ }), []);
175
+ const resume = useCallback(() => __async(this, null, function* () {
176
+ var _a2;
177
+ yield (_a2 = player.current) == null ? void 0 : _a2.resume();
178
+ setPlaybackStatus("playing");
179
+ }), []);
180
+ const toggle = useCallback(() => __async(this, null, function* () {
181
+ var _a2;
182
+ yield (_a2 = player.current) == null ? void 0 : _a2.toggle();
183
+ setPlaybackStatus((status) => {
184
+ if (status === "playing") {
185
+ return "paused";
528
186
  }
529
- setIsPlaying(true);
530
- yield (_a = streamReturn.current) == null ? void 0 : _a.play({ bufferDuration });
531
- setIsPlaying(false);
532
- }),
533
- [isPlaying]
534
- );
187
+ if (status === "paused") {
188
+ return "playing";
189
+ }
190
+ return status;
191
+ });
192
+ }), []);
535
193
  return {
536
- stream,
194
+ buffer,
537
195
  play,
538
- download,
539
- isPlaying,
196
+ pause,
197
+ source: (_b = (_a = websocketReturn.current) == null ? void 0 : _a.source) != null ? _b : null,
198
+ resume,
199
+ toggle,
200
+ playbackStatus,
201
+ bufferStatus,
202
+ isWaiting,
540
203
  isConnected,
541
- isStreamed,
542
- chunks,
543
- messages
204
+ metrics
544
205
  };
545
206
  }
546
- // Annotate the CommonJS export names for ESM import in node:
547
- 0 && (module.exports = {
548
- useAudio
549
- });
207
+ export {
208
+ useTTS
209
+ };