@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.
- package/.turbo/turbo-build.log +68 -38
- package/CHANGELOG.md +12 -0
- package/README.md +123 -16
- package/dist/chunk-3FL2SNIR.js +17 -0
- package/dist/chunk-3GBZUGUD.js +17 -0
- package/dist/chunk-4RMSIQLG.js +25 -0
- package/dist/chunk-BCQ63627.js +32 -0
- package/dist/chunk-JOHSCOLW.js +106 -0
- package/dist/chunk-LYPTISWL.js +75 -0
- package/dist/chunk-NDNN326Q.js +207 -0
- package/dist/chunk-WBK6LLXX.js +58 -0
- package/dist/chunk-WE63M7PJ.js +119 -0
- package/dist/{chunk-HNLIBHEN.mjs → chunk-WIFMLPT5.js} +31 -16
- package/dist/chunk-X7SJMF2R.js +22 -0
- package/dist/index.cjs +652 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +20 -0
- package/dist/lib/client.cjs +89 -0
- package/dist/lib/client.d.cts +11 -0
- package/dist/lib/client.d.ts +2 -0
- package/dist/lib/client.js +7 -42
- package/dist/lib/constants.cjs +42 -0
- package/dist/lib/constants.d.cts +4 -0
- package/dist/lib/constants.d.ts +2 -3
- package/dist/lib/constants.js +8 -37
- package/dist/lib/index.cjs +531 -0
- package/dist/lib/index.d.cts +16 -0
- package/dist/lib/index.d.ts +6 -2
- package/dist/lib/index.js +13 -409
- package/dist/react/index.cjs +846 -0
- package/dist/react/index.d.cts +33 -0
- package/dist/react/index.d.ts +20 -13
- package/dist/react/index.js +161 -501
- package/dist/react/utils.cjs +57 -0
- package/dist/react/utils.d.cts +7 -0
- package/dist/react/utils.d.ts +7 -0
- package/dist/react/utils.js +7 -0
- package/dist/tts/index.cjs +470 -0
- package/dist/tts/index.d.cts +17 -0
- package/dist/tts/index.d.ts +17 -0
- package/dist/tts/index.js +12 -0
- package/dist/tts/player.cjs +198 -0
- package/dist/tts/player.d.cts +43 -0
- package/dist/tts/player.d.ts +43 -0
- package/dist/tts/player.js +8 -0
- package/dist/tts/source.cjs +167 -0
- package/dist/tts/source.d.cts +53 -0
- package/dist/tts/source.d.ts +53 -0
- package/dist/tts/source.js +7 -0
- package/dist/{audio/utils.js → tts/utils.cjs} +13 -54
- package/dist/tts/utils.d.cts +67 -0
- package/dist/tts/utils.d.ts +67 -0
- package/dist/{audio/utils.mjs → tts/utils.js} +2 -6
- package/dist/tts/websocket.cjs +453 -0
- package/dist/tts/websocket.d.cts +53 -0
- package/dist/tts/websocket.d.ts +53 -0
- package/dist/tts/websocket.js +11 -0
- package/dist/types/index.cjs +18 -0
- package/dist/types/index.d.cts +55 -0
- package/dist/types/index.d.ts +50 -1
- package/dist/types/index.js +1 -18
- package/dist/voices/index.cjs +155 -0
- package/dist/voices/index.d.cts +12 -0
- package/dist/voices/index.d.ts +12 -0
- package/dist/voices/index.js +9 -0
- package/package.json +11 -7
- package/src/index.ts +4 -0
- package/src/lib/client.ts +14 -1
- package/src/lib/constants.ts +13 -3
- package/src/lib/index.ts +6 -3
- package/src/react/index.ts +167 -75
- package/src/react/utils.ts +11 -0
- package/src/tts/index.ts +17 -0
- package/src/tts/player.ts +109 -0
- package/src/tts/source.ts +98 -0
- package/src/{audio → tts}/utils.ts +19 -97
- package/src/tts/websocket.ts +210 -0
- package/src/types/index.ts +63 -0
- package/src/voices/index.ts +47 -0
- package/dist/audio/index.d.mts +0 -5
- package/dist/audio/index.d.ts +0 -5
- package/dist/audio/index.js +0 -396
- package/dist/audio/index.mjs +0 -9
- package/dist/audio/utils.d.mts +0 -5
- package/dist/audio/utils.d.ts +0 -5
- package/dist/chunk-3CYTAFLF.mjs +0 -262
- package/dist/chunk-FRIBQZPN.mjs +0 -113
- package/dist/chunk-XSFPHPPG.mjs +0 -18
- package/dist/index-DSBmfK9-.d.mts +0 -158
- package/dist/index-qwAyxV5I.d.ts +0 -158
- package/dist/lib/client.d.mts +0 -9
- package/dist/lib/client.mjs +0 -7
- package/dist/lib/constants.d.mts +0 -5
- package/dist/lib/constants.mjs +0 -10
- package/dist/lib/index.d.mts +0 -12
- package/dist/lib/index.mjs +0 -19
- package/dist/react/index.d.mts +0 -26
- package/dist/react/index.mjs +0 -130
- package/dist/types/index.d.mts +0 -6
- package/index.ts +0 -3
- package/src/audio/index.ts +0 -282
- /package/dist/{types/index.mjs → chunk-FXPGR372.js} +0 -0
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __defProps = Object.defineProperties;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
9
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
10
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
13
|
+
var __spreadValues = (a, b) => {
|
|
14
|
+
for (var prop in b || (b = {}))
|
|
15
|
+
if (__hasOwnProp.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
if (__getOwnPropSymbols)
|
|
18
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
19
|
+
if (__propIsEnum.call(b, prop))
|
|
20
|
+
__defNormalProp(a, prop, b[prop]);
|
|
21
|
+
}
|
|
22
|
+
return a;
|
|
23
|
+
};
|
|
24
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
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 __accessCheck = (obj, member, msg) => {
|
|
47
|
+
if (!member.has(obj))
|
|
48
|
+
throw TypeError("Cannot " + msg);
|
|
49
|
+
};
|
|
50
|
+
var __privateGet = (obj, member, getter) => {
|
|
51
|
+
__accessCheck(obj, member, "read from private field");
|
|
52
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
53
|
+
};
|
|
54
|
+
var __privateAdd = (obj, member, value) => {
|
|
55
|
+
if (member.has(obj))
|
|
56
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
57
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
58
|
+
};
|
|
59
|
+
var __privateSet = (obj, member, value, setter) => {
|
|
60
|
+
__accessCheck(obj, member, "write to private field");
|
|
61
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
62
|
+
return value;
|
|
63
|
+
};
|
|
64
|
+
var __privateMethod = (obj, member, method) => {
|
|
65
|
+
__accessCheck(obj, member, "access private method");
|
|
66
|
+
return method;
|
|
67
|
+
};
|
|
68
|
+
var __async = (__this, __arguments, generator) => {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
var fulfilled = (value) => {
|
|
71
|
+
try {
|
|
72
|
+
step(generator.next(value));
|
|
73
|
+
} catch (e) {
|
|
74
|
+
reject(e);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var rejected = (value) => {
|
|
78
|
+
try {
|
|
79
|
+
step(generator.throw(value));
|
|
80
|
+
} catch (e) {
|
|
81
|
+
reject(e);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
85
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// src/react/index.ts
|
|
90
|
+
var react_exports = {};
|
|
91
|
+
__export(react_exports, {
|
|
92
|
+
useTTS: () => useTTS
|
|
93
|
+
});
|
|
94
|
+
module.exports = __toCommonJS(react_exports);
|
|
95
|
+
var import_react = require("react");
|
|
96
|
+
|
|
97
|
+
// src/lib/client.ts
|
|
98
|
+
var import_cross_fetch = __toESM(require("cross-fetch"), 1);
|
|
99
|
+
|
|
100
|
+
// src/lib/constants.ts
|
|
101
|
+
var BASE_URL = "https://api.cartesia.ai/v0";
|
|
102
|
+
var constructApiUrl = (baseUrl, path, protocol) => {
|
|
103
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
104
|
+
if (!protocol) {
|
|
105
|
+
return new URL(`${baseUrl}${normalizedPath}`);
|
|
106
|
+
}
|
|
107
|
+
if (!["http", "ws"].includes(protocol)) {
|
|
108
|
+
throw new Error(`Invalid protocol: ${protocol}`);
|
|
109
|
+
}
|
|
110
|
+
return new URL(`${baseUrl.replace(/^http/, protocol)}${normalizedPath}`);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// src/lib/client.ts
|
|
114
|
+
var Client = class {
|
|
115
|
+
constructor(options = {}) {
|
|
116
|
+
if (!(options.apiKey || process.env.CARTESIA_API_KEY)) {
|
|
117
|
+
throw new Error("Missing Cartesia API key.");
|
|
118
|
+
}
|
|
119
|
+
this.apiKey = options.apiKey || process.env.CARTESIA_API_KEY;
|
|
120
|
+
this.baseUrl = options.baseUrl || BASE_URL;
|
|
121
|
+
}
|
|
122
|
+
fetch(path, options = {}) {
|
|
123
|
+
const url = constructApiUrl(this.baseUrl, path);
|
|
124
|
+
return (0, import_cross_fetch.default)(url.toString(), __spreadProps(__spreadValues({}, options), {
|
|
125
|
+
headers: __spreadValues({
|
|
126
|
+
"X-API-KEY": this.apiKey
|
|
127
|
+
}, options.headers)
|
|
128
|
+
}));
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// src/tts/websocket.ts
|
|
133
|
+
var import_emittery2 = __toESM(require("emittery"), 1);
|
|
134
|
+
var import_human_id = require("human-id");
|
|
135
|
+
var import_partysocket = require("partysocket");
|
|
136
|
+
|
|
137
|
+
// src/tts/source.ts
|
|
138
|
+
var import_emittery = __toESM(require("emittery"), 1);
|
|
139
|
+
var _emitter, _buffer, _readIndex, _closed, _sampleRate;
|
|
140
|
+
var Source = class {
|
|
141
|
+
/**
|
|
142
|
+
* Create a new Source.
|
|
143
|
+
*
|
|
144
|
+
* @param options - Options for the Source.
|
|
145
|
+
* @param options.sampleRate - The sample rate of the audio.
|
|
146
|
+
*/
|
|
147
|
+
constructor({ sampleRate }) {
|
|
148
|
+
__privateAdd(this, _emitter, new import_emittery.default());
|
|
149
|
+
__privateAdd(this, _buffer, new Float32Array());
|
|
150
|
+
__privateAdd(this, _readIndex, 0);
|
|
151
|
+
__privateAdd(this, _closed, false);
|
|
152
|
+
__privateAdd(this, _sampleRate, void 0);
|
|
153
|
+
this.on = __privateGet(this, _emitter).on.bind(__privateGet(this, _emitter));
|
|
154
|
+
this.once = __privateGet(this, _emitter).once.bind(__privateGet(this, _emitter));
|
|
155
|
+
this.events = __privateGet(this, _emitter).events.bind(__privateGet(this, _emitter));
|
|
156
|
+
this.off = __privateGet(this, _emitter).off.bind(__privateGet(this, _emitter));
|
|
157
|
+
__privateSet(this, _sampleRate, sampleRate);
|
|
158
|
+
}
|
|
159
|
+
get sampleRate() {
|
|
160
|
+
return __privateGet(this, _sampleRate);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Append audio to the buffer.
|
|
164
|
+
*
|
|
165
|
+
* @param src The audio to append.
|
|
166
|
+
*/
|
|
167
|
+
enqueue(src) {
|
|
168
|
+
return __async(this, null, function* () {
|
|
169
|
+
__privateSet(this, _buffer, new Float32Array([...__privateGet(this, _buffer), ...src]));
|
|
170
|
+
yield __privateGet(this, _emitter).emit("enqueue");
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Read audio from the buffer.
|
|
175
|
+
*
|
|
176
|
+
* @param dst The buffer to read the audio into.
|
|
177
|
+
* @returns The number of samples read. If the source is closed, this will be
|
|
178
|
+
* less than the length of the provided buffer.
|
|
179
|
+
*/
|
|
180
|
+
read(dst) {
|
|
181
|
+
return __async(this, null, function* () {
|
|
182
|
+
const targetReadIndex = __privateGet(this, _readIndex) + dst.length;
|
|
183
|
+
while (!__privateGet(this, _closed) && targetReadIndex > __privateGet(this, _buffer).length) {
|
|
184
|
+
yield __privateGet(this, _emitter).emit("wait");
|
|
185
|
+
yield Promise.race([
|
|
186
|
+
__privateGet(this, _emitter).once("enqueue"),
|
|
187
|
+
__privateGet(this, _emitter).once("close")
|
|
188
|
+
]);
|
|
189
|
+
yield __privateGet(this, _emitter).emit("read");
|
|
190
|
+
}
|
|
191
|
+
const read = Math.min(dst.length, __privateGet(this, _buffer).length - __privateGet(this, _readIndex));
|
|
192
|
+
dst.set(__privateGet(this, _buffer).slice(__privateGet(this, _readIndex), __privateGet(this, _readIndex) + read));
|
|
193
|
+
__privateSet(this, _readIndex, __privateGet(this, _readIndex) + read);
|
|
194
|
+
return read;
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get the number of samples in a given duration.
|
|
199
|
+
*
|
|
200
|
+
* @param durationSecs The duration in seconds.
|
|
201
|
+
* @returns The number of samples.
|
|
202
|
+
*/
|
|
203
|
+
durationToSampleCount(durationSecs) {
|
|
204
|
+
return Math.trunc(durationSecs * __privateGet(this, _sampleRate));
|
|
205
|
+
}
|
|
206
|
+
get buffer() {
|
|
207
|
+
return __privateGet(this, _buffer);
|
|
208
|
+
}
|
|
209
|
+
get readIndex() {
|
|
210
|
+
return __privateGet(this, _readIndex);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Close the source. This signals that no more audio will be enqueued.
|
|
214
|
+
*
|
|
215
|
+
* This will emit a "close" event.
|
|
216
|
+
*
|
|
217
|
+
* @returns A promise that resolves when the source is closed.
|
|
218
|
+
*/
|
|
219
|
+
close() {
|
|
220
|
+
return __async(this, null, function* () {
|
|
221
|
+
__privateSet(this, _closed, true);
|
|
222
|
+
yield __privateGet(this, _emitter).emit("close");
|
|
223
|
+
__privateGet(this, _emitter).clearListeners();
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
_emitter = new WeakMap();
|
|
228
|
+
_buffer = new WeakMap();
|
|
229
|
+
_readIndex = new WeakMap();
|
|
230
|
+
_closed = new WeakMap();
|
|
231
|
+
_sampleRate = new WeakMap();
|
|
232
|
+
|
|
233
|
+
// src/tts/utils.ts
|
|
234
|
+
var import_base64_js = __toESM(require("base64-js"), 1);
|
|
235
|
+
function base64ToArray(b64) {
|
|
236
|
+
return filterSentinel(b64).reduce((acc, b) => {
|
|
237
|
+
const floats = new Float32Array(import_base64_js.default.toByteArray(b).buffer);
|
|
238
|
+
const newAcc = new Float32Array(acc.length + floats.length);
|
|
239
|
+
newAcc.set(acc, 0);
|
|
240
|
+
newAcc.set(floats, acc.length);
|
|
241
|
+
return newAcc;
|
|
242
|
+
}, new Float32Array(0));
|
|
243
|
+
}
|
|
244
|
+
function playAudioBuffer(floats, context, startAt, sampleRate) {
|
|
245
|
+
const source = context.createBufferSource();
|
|
246
|
+
const buffer = context.createBuffer(1, floats.length, sampleRate);
|
|
247
|
+
buffer.getChannelData(0).set(floats);
|
|
248
|
+
source.buffer = buffer;
|
|
249
|
+
source.connect(context.destination);
|
|
250
|
+
source.start(startAt);
|
|
251
|
+
return new Promise((resolve) => {
|
|
252
|
+
source.onended = () => {
|
|
253
|
+
resolve();
|
|
254
|
+
};
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function createMessageHandlerForContextId(contextId, handler) {
|
|
258
|
+
return (event) => {
|
|
259
|
+
if (typeof event.data !== "string") {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const message = JSON.parse(event.data);
|
|
263
|
+
if (message.context_id !== contextId) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
let chunk;
|
|
267
|
+
if (message.done) {
|
|
268
|
+
chunk = getSentinel();
|
|
269
|
+
} else {
|
|
270
|
+
chunk = message.data;
|
|
271
|
+
}
|
|
272
|
+
handler({ chunk, message: event.data });
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function getSentinel() {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
function isSentinel(x) {
|
|
279
|
+
return x === getSentinel();
|
|
280
|
+
}
|
|
281
|
+
function filterSentinel(collection) {
|
|
282
|
+
return collection.filter(
|
|
283
|
+
(x) => !isSentinel(x)
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
function getEmitteryCallbacks(emitter) {
|
|
287
|
+
return {
|
|
288
|
+
on: emitter.on.bind(emitter),
|
|
289
|
+
off: emitter.off.bind(emitter),
|
|
290
|
+
once: emitter.once.bind(emitter),
|
|
291
|
+
events: emitter.events.bind(emitter)
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/tts/websocket.ts
|
|
296
|
+
var _isConnected, _sampleRate2, _generateId, generateId_fn;
|
|
297
|
+
var WebSocket = class extends Client {
|
|
298
|
+
/**
|
|
299
|
+
* Create a new WebSocket client.
|
|
300
|
+
*
|
|
301
|
+
* @param args - Arguments to pass to the Client constructor.
|
|
302
|
+
*/
|
|
303
|
+
constructor({ sampleRate }, ...args) {
|
|
304
|
+
super(...args);
|
|
305
|
+
/**
|
|
306
|
+
* Generate a unique ID suitable for a streaming context.
|
|
307
|
+
*
|
|
308
|
+
* Not suitable for security purposes or as a primary key, since
|
|
309
|
+
* it lacks the amount of entropy required for those use cases.
|
|
310
|
+
*
|
|
311
|
+
* @returns A unique ID.
|
|
312
|
+
*/
|
|
313
|
+
__privateAdd(this, _generateId);
|
|
314
|
+
__privateAdd(this, _isConnected, false);
|
|
315
|
+
__privateAdd(this, _sampleRate2, void 0);
|
|
316
|
+
__privateSet(this, _sampleRate2, sampleRate);
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Send a message over the WebSocket in order to start a stream.
|
|
320
|
+
*
|
|
321
|
+
* @param inputs - Stream options.
|
|
322
|
+
* @param options - Options for the stream.
|
|
323
|
+
* @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
|
|
324
|
+
* If `0`, the stream will not time out.
|
|
325
|
+
* @returns A Source object that can be passed to a Player to play the audio.
|
|
326
|
+
*/
|
|
327
|
+
send(inputs, { timeout = 0 } = {}) {
|
|
328
|
+
var _a, _b, _c, _d;
|
|
329
|
+
if (!__privateGet(this, _isConnected)) {
|
|
330
|
+
throw new Error("Not connected to WebSocket. Call .connect() first.");
|
|
331
|
+
}
|
|
332
|
+
const contextId = __privateMethod(this, _generateId, generateId_fn).call(this);
|
|
333
|
+
(_a = this.socket) == null ? void 0 : _a.send(
|
|
334
|
+
JSON.stringify(__spreadProps(__spreadValues({
|
|
335
|
+
context_id: contextId
|
|
336
|
+
}, inputs), {
|
|
337
|
+
output_format: {
|
|
338
|
+
container: "raw",
|
|
339
|
+
encoding: "pcm_f32le",
|
|
340
|
+
sample_rate: __privateGet(this, _sampleRate2)
|
|
341
|
+
}
|
|
342
|
+
}))
|
|
343
|
+
);
|
|
344
|
+
const emitter = new import_emittery2.default();
|
|
345
|
+
const source = new Source({
|
|
346
|
+
sampleRate: __privateGet(this, _sampleRate2)
|
|
347
|
+
});
|
|
348
|
+
const streamCompleteController = new AbortController();
|
|
349
|
+
let timeoutId = null;
|
|
350
|
+
if (timeout > 0) {
|
|
351
|
+
timeoutId = setTimeout(streamCompleteController.abort, timeout);
|
|
352
|
+
}
|
|
353
|
+
const handleMessage = createMessageHandlerForContextId(
|
|
354
|
+
contextId,
|
|
355
|
+
(_0) => __async(this, [_0], function* ({ chunk, message }) {
|
|
356
|
+
emitter.emit("message", message);
|
|
357
|
+
if (isSentinel(chunk)) {
|
|
358
|
+
yield source.close();
|
|
359
|
+
streamCompleteController.abort();
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
yield source.enqueue(base64ToArray([chunk]));
|
|
363
|
+
if (timeoutId) {
|
|
364
|
+
clearTimeout(timeoutId);
|
|
365
|
+
timeoutId = setTimeout(streamCompleteController.abort, timeout);
|
|
366
|
+
}
|
|
367
|
+
})
|
|
368
|
+
);
|
|
369
|
+
(_b = this.socket) == null ? void 0 : _b.addEventListener("message", handleMessage, {
|
|
370
|
+
signal: streamCompleteController.signal
|
|
371
|
+
});
|
|
372
|
+
(_c = this.socket) == null ? void 0 : _c.addEventListener(
|
|
373
|
+
"close",
|
|
374
|
+
() => {
|
|
375
|
+
streamCompleteController.abort();
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
once: true
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
(_d = this.socket) == null ? void 0 : _d.addEventListener(
|
|
382
|
+
"error",
|
|
383
|
+
() => {
|
|
384
|
+
streamCompleteController.abort();
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
once: true
|
|
388
|
+
}
|
|
389
|
+
);
|
|
390
|
+
streamCompleteController.signal.addEventListener("abort", () => {
|
|
391
|
+
source.close();
|
|
392
|
+
if (timeoutId) {
|
|
393
|
+
clearTimeout(timeoutId);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
return __spreadValues({ source }, getEmitteryCallbacks(emitter));
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Authenticate and connect to a Cartesia streaming WebSocket.
|
|
400
|
+
*
|
|
401
|
+
* @returns A promise that resolves when the WebSocket is connected.
|
|
402
|
+
* @throws {Error} If the WebSocket fails to connect.
|
|
403
|
+
*/
|
|
404
|
+
connect() {
|
|
405
|
+
const url = constructApiUrl(this.baseUrl, "/tts/websocket", "ws");
|
|
406
|
+
url.searchParams.set("api_key", this.apiKey);
|
|
407
|
+
const emitter = new import_emittery2.default();
|
|
408
|
+
this.socket = new import_partysocket.WebSocket(url.toString());
|
|
409
|
+
this.socket.onopen = () => {
|
|
410
|
+
__privateSet(this, _isConnected, true);
|
|
411
|
+
emitter.emit("open");
|
|
412
|
+
};
|
|
413
|
+
this.socket.onclose = () => {
|
|
414
|
+
__privateSet(this, _isConnected, false);
|
|
415
|
+
emitter.emit("close");
|
|
416
|
+
};
|
|
417
|
+
return new Promise(
|
|
418
|
+
(resolve, reject) => {
|
|
419
|
+
var _a, _b, _c;
|
|
420
|
+
(_a = this.socket) == null ? void 0 : _a.addEventListener(
|
|
421
|
+
"open",
|
|
422
|
+
() => {
|
|
423
|
+
resolve(getEmitteryCallbacks(emitter));
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
once: true
|
|
427
|
+
}
|
|
428
|
+
);
|
|
429
|
+
const aborter = new AbortController();
|
|
430
|
+
(_b = this.socket) == null ? void 0 : _b.addEventListener(
|
|
431
|
+
"error",
|
|
432
|
+
() => {
|
|
433
|
+
aborter.abort();
|
|
434
|
+
reject(new Error("WebSocket failed to connect."));
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
signal: aborter.signal
|
|
438
|
+
}
|
|
439
|
+
);
|
|
440
|
+
(_c = this.socket) == null ? void 0 : _c.addEventListener(
|
|
441
|
+
"close",
|
|
442
|
+
() => {
|
|
443
|
+
aborter.abort();
|
|
444
|
+
reject(new Error("WebSocket closed before it could connect."));
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
signal: aborter.signal
|
|
448
|
+
}
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Disconnect from the Cartesia streaming WebSocket.
|
|
455
|
+
*/
|
|
456
|
+
disconnect() {
|
|
457
|
+
var _a;
|
|
458
|
+
(_a = this.socket) == null ? void 0 : _a.close();
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
_isConnected = new WeakMap();
|
|
462
|
+
_sampleRate2 = new WeakMap();
|
|
463
|
+
_generateId = new WeakSet();
|
|
464
|
+
generateId_fn = function() {
|
|
465
|
+
return (0, import_human_id.humanId)({
|
|
466
|
+
separator: "-",
|
|
467
|
+
capitalize: false
|
|
468
|
+
});
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// src/tts/index.ts
|
|
472
|
+
var TTS = class extends Client {
|
|
473
|
+
/**
|
|
474
|
+
* Get a WebSocket client for streaming audio from the TTS API.
|
|
475
|
+
*
|
|
476
|
+
* @returns {WebSocket} A Cartesia WebSocket client.
|
|
477
|
+
*/
|
|
478
|
+
websocket(options) {
|
|
479
|
+
return new WebSocket(options, {
|
|
480
|
+
apiKey: this.apiKey,
|
|
481
|
+
baseUrl: this.baseUrl
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
// src/voices/index.ts
|
|
487
|
+
var Voices = class extends Client {
|
|
488
|
+
list() {
|
|
489
|
+
return __async(this, null, function* () {
|
|
490
|
+
const response = yield this.fetch("/voices");
|
|
491
|
+
return response.json();
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
get(voiceId) {
|
|
495
|
+
return __async(this, null, function* () {
|
|
496
|
+
const response = yield this.fetch(`/voices/${voiceId}`);
|
|
497
|
+
return response.json();
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
create(voice) {
|
|
501
|
+
return __async(this, null, function* () {
|
|
502
|
+
const response = yield this.fetch("/voices", {
|
|
503
|
+
method: "POST",
|
|
504
|
+
body: JSON.stringify(voice)
|
|
505
|
+
});
|
|
506
|
+
return response.json();
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
clone(options) {
|
|
510
|
+
return __async(this, null, function* () {
|
|
511
|
+
if (options.mode === "url") {
|
|
512
|
+
const response = yield this.fetch(
|
|
513
|
+
`/voices/clone/url?link=${options.link}`,
|
|
514
|
+
{
|
|
515
|
+
method: "POST"
|
|
516
|
+
}
|
|
517
|
+
);
|
|
518
|
+
return response.json();
|
|
519
|
+
}
|
|
520
|
+
if (options.mode === "clip") {
|
|
521
|
+
const formData = new FormData();
|
|
522
|
+
formData.append("clip", options.clip);
|
|
523
|
+
const response = yield this.fetch("/voices/clone/clip", {
|
|
524
|
+
method: "POST",
|
|
525
|
+
body: formData
|
|
526
|
+
});
|
|
527
|
+
return response.json();
|
|
528
|
+
}
|
|
529
|
+
throw new Error("Invalid mode for clone()");
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
// src/lib/index.ts
|
|
535
|
+
var Cartesia = class extends Client {
|
|
536
|
+
constructor(options = {}) {
|
|
537
|
+
super(options);
|
|
538
|
+
this.tts = new TTS(options);
|
|
539
|
+
this.voices = new Voices(options);
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
// src/tts/player.ts
|
|
544
|
+
var import_emittery3 = __toESM(require("emittery"), 1);
|
|
545
|
+
var _context, _startNextPlaybackAt, _bufferDuration, _emitter2, _playBuffer, playBuffer_fn;
|
|
546
|
+
var Player = class {
|
|
547
|
+
/**
|
|
548
|
+
* Create a new Player.
|
|
549
|
+
*
|
|
550
|
+
* @param options - Options for the Player.
|
|
551
|
+
* @param options.bufferDuration - The duration of the audio buffer to play.
|
|
552
|
+
*/
|
|
553
|
+
constructor({ bufferDuration }) {
|
|
554
|
+
__privateAdd(this, _playBuffer);
|
|
555
|
+
__privateAdd(this, _context, null);
|
|
556
|
+
__privateAdd(this, _startNextPlaybackAt, 0);
|
|
557
|
+
__privateAdd(this, _bufferDuration, void 0);
|
|
558
|
+
__privateAdd(this, _emitter2, new import_emittery3.default());
|
|
559
|
+
__privateSet(this, _bufferDuration, bufferDuration);
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Play audio from a source.
|
|
563
|
+
*
|
|
564
|
+
* @param source The source to play audio from.
|
|
565
|
+
* @returns A promise that resolves when the audio has finished playing.
|
|
566
|
+
*/
|
|
567
|
+
play(source) {
|
|
568
|
+
return __async(this, null, function* () {
|
|
569
|
+
__privateSet(this, _startNextPlaybackAt, 0);
|
|
570
|
+
__privateSet(this, _context, new AudioContext({ sampleRate: source.sampleRate }));
|
|
571
|
+
const buffer = new Float32Array(
|
|
572
|
+
source.durationToSampleCount(__privateGet(this, _bufferDuration))
|
|
573
|
+
);
|
|
574
|
+
const plays = [];
|
|
575
|
+
while (true) {
|
|
576
|
+
const read = yield source.read(buffer);
|
|
577
|
+
const playableAudio = buffer.slice(0, read);
|
|
578
|
+
plays.push(__privateMethod(this, _playBuffer, playBuffer_fn).call(this, playableAudio, source.sampleRate));
|
|
579
|
+
if (read < buffer.length) {
|
|
580
|
+
yield __privateGet(this, _emitter2).emit("finish");
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
yield Promise.all(plays);
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Pause the audio.
|
|
589
|
+
*
|
|
590
|
+
* @returns A promise that resolves when the audio has been paused.
|
|
591
|
+
*/
|
|
592
|
+
pause() {
|
|
593
|
+
return __async(this, null, function* () {
|
|
594
|
+
if (!__privateGet(this, _context)) {
|
|
595
|
+
throw new Error("AudioContext not initialized.");
|
|
596
|
+
}
|
|
597
|
+
yield __privateGet(this, _context).suspend();
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Resume the audio.
|
|
602
|
+
*
|
|
603
|
+
* @returns A promise that resolves when the audio has been resumed.
|
|
604
|
+
*/
|
|
605
|
+
resume() {
|
|
606
|
+
return __async(this, null, function* () {
|
|
607
|
+
if (!__privateGet(this, _context)) {
|
|
608
|
+
throw new Error("AudioContext not initialized.");
|
|
609
|
+
}
|
|
610
|
+
yield __privateGet(this, _context).resume();
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Toggle the audio.
|
|
615
|
+
*
|
|
616
|
+
* @returns A promise that resolves when the audio has been toggled.
|
|
617
|
+
*/
|
|
618
|
+
toggle() {
|
|
619
|
+
return __async(this, null, function* () {
|
|
620
|
+
if (!__privateGet(this, _context)) {
|
|
621
|
+
throw new Error("AudioContext not initialized.");
|
|
622
|
+
}
|
|
623
|
+
if (__privateGet(this, _context).state === "running") {
|
|
624
|
+
yield this.pause();
|
|
625
|
+
} else {
|
|
626
|
+
yield this.resume();
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
_context = new WeakMap();
|
|
632
|
+
_startNextPlaybackAt = new WeakMap();
|
|
633
|
+
_bufferDuration = new WeakMap();
|
|
634
|
+
_emitter2 = new WeakMap();
|
|
635
|
+
_playBuffer = new WeakSet();
|
|
636
|
+
playBuffer_fn = function(buf, sampleRate) {
|
|
637
|
+
return __async(this, null, function* () {
|
|
638
|
+
if (!__privateGet(this, _context)) {
|
|
639
|
+
throw new Error("AudioContext not initialized.");
|
|
640
|
+
}
|
|
641
|
+
const startAt = __privateGet(this, _startNextPlaybackAt);
|
|
642
|
+
const duration = buf.length / sampleRate;
|
|
643
|
+
__privateSet(this, _startNextPlaybackAt, duration + Math.max(__privateGet(this, _context).currentTime, __privateGet(this, _startNextPlaybackAt)));
|
|
644
|
+
yield playAudioBuffer(buf, __privateGet(this, _context), startAt, sampleRate);
|
|
645
|
+
});
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
// src/react/utils.ts
|
|
649
|
+
function pingServer(url) {
|
|
650
|
+
return __async(this, null, function* () {
|
|
651
|
+
const start = (/* @__PURE__ */ new Date()).getTime();
|
|
652
|
+
yield fetch(url);
|
|
653
|
+
const end = (/* @__PURE__ */ new Date()).getTime();
|
|
654
|
+
return end - start;
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// src/react/index.ts
|
|
659
|
+
var PING_INTERVAL = 5e3;
|
|
660
|
+
var DEFAULT_BUFFER_DURATION = 0.01;
|
|
661
|
+
function useTTS({
|
|
662
|
+
apiKey,
|
|
663
|
+
baseUrl,
|
|
664
|
+
sampleRate
|
|
665
|
+
}) {
|
|
666
|
+
var _a, _b;
|
|
667
|
+
if (typeof window === "undefined") {
|
|
668
|
+
return {
|
|
669
|
+
buffer: () => __async(this, null, function* () {
|
|
670
|
+
}),
|
|
671
|
+
play: () => __async(this, null, function* () {
|
|
672
|
+
}),
|
|
673
|
+
pause: () => __async(this, null, function* () {
|
|
674
|
+
}),
|
|
675
|
+
resume: () => __async(this, null, function* () {
|
|
676
|
+
}),
|
|
677
|
+
toggle: () => __async(this, null, function* () {
|
|
678
|
+
}),
|
|
679
|
+
playbackStatus: "inactive",
|
|
680
|
+
bufferStatus: "inactive",
|
|
681
|
+
isWaiting: false,
|
|
682
|
+
source: null,
|
|
683
|
+
isConnected: false,
|
|
684
|
+
metrics: {
|
|
685
|
+
modelLatency: null
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
const websocket = (0, import_react.useMemo)(() => {
|
|
690
|
+
if (!apiKey) {
|
|
691
|
+
return null;
|
|
692
|
+
}
|
|
693
|
+
const cartesia = new Cartesia({ apiKey, baseUrl });
|
|
694
|
+
baseUrl = baseUrl != null ? baseUrl : cartesia.baseUrl;
|
|
695
|
+
return cartesia.tts.websocket({ sampleRate });
|
|
696
|
+
}, [apiKey, baseUrl, sampleRate]);
|
|
697
|
+
const websocketReturn = (0, import_react.useRef)(null);
|
|
698
|
+
const player = (0, import_react.useRef)(null);
|
|
699
|
+
const [playbackStatus, setPlaybackStatus] = (0, import_react.useState)("inactive");
|
|
700
|
+
const [bufferStatus, setBufferStatus] = (0, import_react.useState)("inactive");
|
|
701
|
+
const [isWaiting, setIsWaiting] = (0, import_react.useState)(false);
|
|
702
|
+
const [isConnected, setIsConnected] = (0, import_react.useState)(false);
|
|
703
|
+
const [bufferDuration, setBufferDuration] = (0, import_react.useState)(null);
|
|
704
|
+
const [messages, setMessages] = (0, import_react.useState)([]);
|
|
705
|
+
const buffer = (0, import_react.useCallback)(
|
|
706
|
+
(options) => __async(this, null, function* () {
|
|
707
|
+
var _a2;
|
|
708
|
+
setMessages([]);
|
|
709
|
+
setBufferStatus("buffering");
|
|
710
|
+
websocketReturn.current = (_a2 = websocket == null ? void 0 : websocket.send(options)) != null ? _a2 : null;
|
|
711
|
+
if (!websocketReturn.current) {
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
websocketReturn.current.on("message", (message) => {
|
|
715
|
+
setMessages((messages2) => [...messages2, JSON.parse(message)]);
|
|
716
|
+
});
|
|
717
|
+
yield websocketReturn.current.source.once("close");
|
|
718
|
+
setBufferStatus("buffered");
|
|
719
|
+
}),
|
|
720
|
+
[websocket]
|
|
721
|
+
);
|
|
722
|
+
const metrics = (0, import_react.useMemo)(() => {
|
|
723
|
+
var _a2;
|
|
724
|
+
if (messages.length === 0) {
|
|
725
|
+
return {
|
|
726
|
+
modelLatency: null
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
const modelLatency = (_a2 = messages[0].step_time) != null ? _a2 : null;
|
|
730
|
+
return {
|
|
731
|
+
modelLatency: Math.trunc(modelLatency)
|
|
732
|
+
};
|
|
733
|
+
}, [messages]);
|
|
734
|
+
(0, import_react.useEffect)(() => {
|
|
735
|
+
let cleanup = () => {
|
|
736
|
+
};
|
|
737
|
+
function setupConnection() {
|
|
738
|
+
return __async(this, null, function* () {
|
|
739
|
+
try {
|
|
740
|
+
const connection = yield websocket == null ? void 0 : websocket.connect();
|
|
741
|
+
if (!connection) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
setIsConnected(true);
|
|
745
|
+
connection.on("open", () => {
|
|
746
|
+
setIsConnected(true);
|
|
747
|
+
});
|
|
748
|
+
const unsubscribe = connection.on("close", () => {
|
|
749
|
+
setIsConnected(false);
|
|
750
|
+
});
|
|
751
|
+
const intervalId = setInterval(() => {
|
|
752
|
+
if (baseUrl) {
|
|
753
|
+
pingServer(new URL(baseUrl).origin).then((ping) => {
|
|
754
|
+
let bufferDuration2;
|
|
755
|
+
if (ping < 300) {
|
|
756
|
+
bufferDuration2 = 0.01;
|
|
757
|
+
} else if (ping > 1500) {
|
|
758
|
+
bufferDuration2 = 6;
|
|
759
|
+
} else {
|
|
760
|
+
bufferDuration2 = ping / 1e3 * 4;
|
|
761
|
+
}
|
|
762
|
+
setBufferDuration(bufferDuration2);
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
}, PING_INTERVAL);
|
|
766
|
+
return () => {
|
|
767
|
+
unsubscribe();
|
|
768
|
+
clearInterval(intervalId);
|
|
769
|
+
websocket == null ? void 0 : websocket.disconnect();
|
|
770
|
+
};
|
|
771
|
+
} catch (e) {
|
|
772
|
+
console.error(e);
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
setupConnection().then((cleanupConnection) => {
|
|
777
|
+
cleanup = cleanupConnection;
|
|
778
|
+
});
|
|
779
|
+
return () => cleanup == null ? void 0 : cleanup();
|
|
780
|
+
}, [websocket, baseUrl]);
|
|
781
|
+
const play = (0, import_react.useCallback)(() => __async(this, null, function* () {
|
|
782
|
+
if (playbackStatus === "playing" || !websocketReturn.current) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
setPlaybackStatus("playing");
|
|
786
|
+
const unsubscribes = [];
|
|
787
|
+
unsubscribes.push(
|
|
788
|
+
websocketReturn.current.source.on("wait", () => {
|
|
789
|
+
setIsWaiting(true);
|
|
790
|
+
})
|
|
791
|
+
);
|
|
792
|
+
unsubscribes.push(
|
|
793
|
+
websocketReturn.current.source.on("read", () => {
|
|
794
|
+
setIsWaiting(false);
|
|
795
|
+
})
|
|
796
|
+
);
|
|
797
|
+
player.current = new Player({
|
|
798
|
+
bufferDuration: bufferDuration != null ? bufferDuration : DEFAULT_BUFFER_DURATION
|
|
799
|
+
});
|
|
800
|
+
yield player.current.play(websocketReturn.current.source);
|
|
801
|
+
for (const unsubscribe of unsubscribes) {
|
|
802
|
+
unsubscribe();
|
|
803
|
+
}
|
|
804
|
+
setPlaybackStatus("finished");
|
|
805
|
+
}), [playbackStatus, bufferDuration]);
|
|
806
|
+
const pause = (0, import_react.useCallback)(() => __async(this, null, function* () {
|
|
807
|
+
var _a2;
|
|
808
|
+
yield (_a2 = player.current) == null ? void 0 : _a2.pause();
|
|
809
|
+
setPlaybackStatus("paused");
|
|
810
|
+
}), []);
|
|
811
|
+
const resume = (0, import_react.useCallback)(() => __async(this, null, function* () {
|
|
812
|
+
var _a2;
|
|
813
|
+
yield (_a2 = player.current) == null ? void 0 : _a2.resume();
|
|
814
|
+
setPlaybackStatus("playing");
|
|
815
|
+
}), []);
|
|
816
|
+
const toggle = (0, import_react.useCallback)(() => __async(this, null, function* () {
|
|
817
|
+
var _a2;
|
|
818
|
+
yield (_a2 = player.current) == null ? void 0 : _a2.toggle();
|
|
819
|
+
setPlaybackStatus((status) => {
|
|
820
|
+
if (status === "playing") {
|
|
821
|
+
return "paused";
|
|
822
|
+
}
|
|
823
|
+
if (status === "paused") {
|
|
824
|
+
return "playing";
|
|
825
|
+
}
|
|
826
|
+
return status;
|
|
827
|
+
});
|
|
828
|
+
}), []);
|
|
829
|
+
return {
|
|
830
|
+
buffer,
|
|
831
|
+
play,
|
|
832
|
+
pause,
|
|
833
|
+
source: (_b = (_a = websocketReturn.current) == null ? void 0 : _a.source) != null ? _b : null,
|
|
834
|
+
resume,
|
|
835
|
+
toggle,
|
|
836
|
+
playbackStatus,
|
|
837
|
+
bufferStatus,
|
|
838
|
+
isWaiting,
|
|
839
|
+
isConnected,
|
|
840
|
+
metrics
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
844
|
+
0 && (module.exports = {
|
|
845
|
+
useTTS
|
|
846
|
+
});
|