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