@cartesia/cartesia-js 0.0.4-alpha.0 → 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 +64 -46
- package/CHANGELOG.md +6 -0
- package/README.md +123 -16
- package/dist/{chunk-XPIMIAAE.js → chunk-3FL2SNIR.js} +1 -1
- 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-R4P7LWVZ.js → chunk-WIFMLPT5.js} +31 -6
- package/dist/chunk-X7SJMF2R.js +22 -0
- package/dist/index.cjs +391 -158
- 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 +46 -0
- 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 +11 -7
- package/dist/lib/constants.d.cts +2 -3
- package/dist/lib/constants.d.ts +2 -3
- package/dist/lib/constants.js +4 -6
- package/dist/lib/index.cjs +276 -163
- 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 +524 -275
- package/dist/react/index.d.cts +20 -14
- package/dist/react/index.d.ts +20 -14
- package/dist/react/index.js +142 -98
- package/dist/react/utils.js +2 -2
- 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 → tts}/utils.cjs +12 -53
- 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/{audio/index.cjs → tts/websocket.cjs} +213 -164
- 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 +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 +2 -1
- package/src/index.ts +1 -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 +157 -103
- 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.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/dist/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/index.ts
|
|
69
90
|
var src_exports = {};
|
|
70
91
|
__export(src_exports, {
|
|
71
92
|
Cartesia: () => Cartesia,
|
|
93
|
+
WebPlayer: () => Player,
|
|
72
94
|
default: () => Cartesia
|
|
73
95
|
});
|
|
74
96
|
module.exports = __toCommonJS(src_exports);
|
|
75
97
|
|
|
76
|
-
// src/
|
|
77
|
-
var
|
|
78
|
-
var import_human_id = require("human-id");
|
|
79
|
-
var import_partysocket = require("partysocket");
|
|
98
|
+
// src/lib/client.ts
|
|
99
|
+
var import_cross_fetch = __toESM(require("cross-fetch"), 1);
|
|
80
100
|
|
|
81
101
|
// src/lib/constants.ts
|
|
82
102
|
var BASE_URL = "https://api.cartesia.ai/v0";
|
|
83
|
-
var
|
|
84
|
-
|
|
85
|
-
|
|
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,14 +120,119 @@ 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
|
+
}, options.headers)
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
97
131
|
};
|
|
98
132
|
|
|
99
|
-
// src/
|
|
133
|
+
// src/tts/websocket.ts
|
|
134
|
+
var import_emittery2 = __toESM(require("emittery"), 1);
|
|
135
|
+
var import_human_id = require("human-id");
|
|
136
|
+
var import_partysocket = require("partysocket");
|
|
137
|
+
|
|
138
|
+
// src/tts/source.ts
|
|
139
|
+
var import_emittery = __toESM(require("emittery"), 1);
|
|
140
|
+
var _emitter, _buffer, _readIndex, _closed, _sampleRate;
|
|
141
|
+
var Source = class {
|
|
142
|
+
/**
|
|
143
|
+
* Create a new Source.
|
|
144
|
+
*
|
|
145
|
+
* @param options - Options for the Source.
|
|
146
|
+
* @param options.sampleRate - The sample rate of the audio.
|
|
147
|
+
*/
|
|
148
|
+
constructor({ sampleRate }) {
|
|
149
|
+
__privateAdd(this, _emitter, new import_emittery.default());
|
|
150
|
+
__privateAdd(this, _buffer, new Float32Array());
|
|
151
|
+
__privateAdd(this, _readIndex, 0);
|
|
152
|
+
__privateAdd(this, _closed, false);
|
|
153
|
+
__privateAdd(this, _sampleRate, void 0);
|
|
154
|
+
this.on = __privateGet(this, _emitter).on.bind(__privateGet(this, _emitter));
|
|
155
|
+
this.once = __privateGet(this, _emitter).once.bind(__privateGet(this, _emitter));
|
|
156
|
+
this.events = __privateGet(this, _emitter).events.bind(__privateGet(this, _emitter));
|
|
157
|
+
this.off = __privateGet(this, _emitter).off.bind(__privateGet(this, _emitter));
|
|
158
|
+
__privateSet(this, _sampleRate, sampleRate);
|
|
159
|
+
}
|
|
160
|
+
get sampleRate() {
|
|
161
|
+
return __privateGet(this, _sampleRate);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Append audio to the buffer.
|
|
165
|
+
*
|
|
166
|
+
* @param src The audio to append.
|
|
167
|
+
*/
|
|
168
|
+
enqueue(src) {
|
|
169
|
+
return __async(this, null, function* () {
|
|
170
|
+
__privateSet(this, _buffer, new Float32Array([...__privateGet(this, _buffer), ...src]));
|
|
171
|
+
yield __privateGet(this, _emitter).emit("enqueue");
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Read audio from the buffer.
|
|
176
|
+
*
|
|
177
|
+
* @param dst The buffer to read the audio into.
|
|
178
|
+
* @returns The number of samples read. If the source is closed, this will be
|
|
179
|
+
* less than the length of the provided buffer.
|
|
180
|
+
*/
|
|
181
|
+
read(dst) {
|
|
182
|
+
return __async(this, null, function* () {
|
|
183
|
+
const targetReadIndex = __privateGet(this, _readIndex) + dst.length;
|
|
184
|
+
while (!__privateGet(this, _closed) && targetReadIndex > __privateGet(this, _buffer).length) {
|
|
185
|
+
yield __privateGet(this, _emitter).emit("wait");
|
|
186
|
+
yield Promise.race([
|
|
187
|
+
__privateGet(this, _emitter).once("enqueue"),
|
|
188
|
+
__privateGet(this, _emitter).once("close")
|
|
189
|
+
]);
|
|
190
|
+
yield __privateGet(this, _emitter).emit("read");
|
|
191
|
+
}
|
|
192
|
+
const read = Math.min(dst.length, __privateGet(this, _buffer).length - __privateGet(this, _readIndex));
|
|
193
|
+
dst.set(__privateGet(this, _buffer).slice(__privateGet(this, _readIndex), __privateGet(this, _readIndex) + read));
|
|
194
|
+
__privateSet(this, _readIndex, __privateGet(this, _readIndex) + read);
|
|
195
|
+
return read;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get the number of samples in a given duration.
|
|
200
|
+
*
|
|
201
|
+
* @param durationSecs The duration in seconds.
|
|
202
|
+
* @returns The number of samples.
|
|
203
|
+
*/
|
|
204
|
+
durationToSampleCount(durationSecs) {
|
|
205
|
+
return Math.trunc(durationSecs * __privateGet(this, _sampleRate));
|
|
206
|
+
}
|
|
207
|
+
get buffer() {
|
|
208
|
+
return __privateGet(this, _buffer);
|
|
209
|
+
}
|
|
210
|
+
get readIndex() {
|
|
211
|
+
return __privateGet(this, _readIndex);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Close the source. This signals that no more audio will be enqueued.
|
|
215
|
+
*
|
|
216
|
+
* This will emit a "close" event.
|
|
217
|
+
*
|
|
218
|
+
* @returns A promise that resolves when the source is closed.
|
|
219
|
+
*/
|
|
220
|
+
close() {
|
|
221
|
+
return __async(this, null, function* () {
|
|
222
|
+
__privateSet(this, _closed, true);
|
|
223
|
+
yield __privateGet(this, _emitter).emit("close");
|
|
224
|
+
__privateGet(this, _emitter).clearListeners();
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
_emitter = new WeakMap();
|
|
229
|
+
_buffer = new WeakMap();
|
|
230
|
+
_readIndex = new WeakMap();
|
|
231
|
+
_closed = new WeakMap();
|
|
232
|
+
_sampleRate = new WeakMap();
|
|
233
|
+
|
|
234
|
+
// src/tts/utils.ts
|
|
100
235
|
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
236
|
function base64ToArray(b64) {
|
|
106
237
|
return filterSentinel(b64).reduce((acc, b) => {
|
|
107
238
|
const floats = new Float32Array(import_base64_js.default.toByteArray(b).buffer);
|
|
@@ -111,20 +242,24 @@ function base64ToArray(b64) {
|
|
|
111
242
|
return newAcc;
|
|
112
243
|
}, new Float32Array(0));
|
|
113
244
|
}
|
|
114
|
-
function playAudioBuffer(
|
|
115
|
-
const startAt = maybeStartAt != null ? maybeStartAt : context.currentTime;
|
|
116
|
-
const floats = base64ToArray(b64);
|
|
245
|
+
function playAudioBuffer(floats, context, startAt, sampleRate) {
|
|
117
246
|
const source = context.createBufferSource();
|
|
118
|
-
const buffer = context.createBuffer(1, floats.length,
|
|
247
|
+
const buffer = context.createBuffer(1, floats.length, sampleRate);
|
|
119
248
|
buffer.getChannelData(0).set(floats);
|
|
120
249
|
source.buffer = buffer;
|
|
121
250
|
source.connect(context.destination);
|
|
122
251
|
source.start(startAt);
|
|
123
|
-
|
|
124
|
-
|
|
252
|
+
return new Promise((resolve) => {
|
|
253
|
+
source.onended = () => {
|
|
254
|
+
resolve();
|
|
255
|
+
};
|
|
256
|
+
});
|
|
125
257
|
}
|
|
126
258
|
function createMessageHandlerForContextId(contextId, handler) {
|
|
127
259
|
return (event) => {
|
|
260
|
+
if (typeof event.data !== "string") {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
128
263
|
const message = JSON.parse(event.data);
|
|
129
264
|
if (message.context_id !== contextId) {
|
|
130
265
|
return;
|
|
@@ -135,7 +270,7 @@ function createMessageHandlerForContextId(contextId, handler) {
|
|
|
135
270
|
} else {
|
|
136
271
|
chunk = message.data;
|
|
137
272
|
}
|
|
138
|
-
handler({ chunk, message });
|
|
273
|
+
handler({ chunk, message: event.data });
|
|
139
274
|
};
|
|
140
275
|
}
|
|
141
276
|
function getSentinel() {
|
|
@@ -149,9 +284,6 @@ function filterSentinel(collection) {
|
|
|
149
284
|
(x) => !isSentinel(x)
|
|
150
285
|
);
|
|
151
286
|
}
|
|
152
|
-
function isComplete(chunks) {
|
|
153
|
-
return isSentinel(chunks[chunks.length - 1]);
|
|
154
|
-
}
|
|
155
287
|
function getEmitteryCallbacks(emitter) {
|
|
156
288
|
return {
|
|
157
289
|
on: emitter.on.bind(emitter),
|
|
@@ -161,58 +293,75 @@ function getEmitteryCallbacks(emitter) {
|
|
|
161
293
|
};
|
|
162
294
|
}
|
|
163
295
|
|
|
164
|
-
// src/
|
|
165
|
-
var
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
296
|
+
// src/tts/websocket.ts
|
|
297
|
+
var _isConnected, _sampleRate2, _generateId, generateId_fn;
|
|
298
|
+
var WebSocket = class extends Client {
|
|
299
|
+
/**
|
|
300
|
+
* Create a new WebSocket client.
|
|
301
|
+
*
|
|
302
|
+
* @param args - Arguments to pass to the Client constructor.
|
|
303
|
+
*/
|
|
304
|
+
constructor({ sampleRate }, ...args) {
|
|
305
|
+
super(...args);
|
|
306
|
+
/**
|
|
307
|
+
* Generate a unique ID suitable for a streaming context.
|
|
308
|
+
*
|
|
309
|
+
* Not suitable for security purposes or as a primary key, since
|
|
310
|
+
* it lacks the amount of entropy required for those use cases.
|
|
311
|
+
*
|
|
312
|
+
* @returns A unique ID.
|
|
313
|
+
*/
|
|
314
|
+
__privateAdd(this, _generateId);
|
|
315
|
+
__privateAdd(this, _isConnected, false);
|
|
316
|
+
__privateAdd(this, _sampleRate2, void 0);
|
|
317
|
+
__privateSet(this, _sampleRate2, sampleRate);
|
|
169
318
|
}
|
|
170
319
|
/**
|
|
171
|
-
*
|
|
320
|
+
* Send a message over the WebSocket in order to start a stream.
|
|
172
321
|
*
|
|
173
|
-
* @param inputs - Stream options.
|
|
174
|
-
* are model-specific and can be found in the model's documentation.
|
|
322
|
+
* @param inputs - Stream options.
|
|
175
323
|
* @param options - Options for the stream.
|
|
176
324
|
* @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
|
|
177
325
|
* If `0`, the stream will not time out.
|
|
178
|
-
* @returns
|
|
179
|
-
* that plays the audio as it arrives, with `bufferDuration` seconds of audio buffered before
|
|
180
|
-
* starting playback.
|
|
326
|
+
* @returns A Source object that can be passed to a Player to play the audio.
|
|
181
327
|
*/
|
|
182
|
-
|
|
328
|
+
send(inputs, { timeout = 0 } = {}) {
|
|
183
329
|
var _a, _b, _c, _d;
|
|
184
|
-
if (!this
|
|
330
|
+
if (!__privateGet(this, _isConnected)) {
|
|
185
331
|
throw new Error("Not connected to WebSocket. Call .connect() first.");
|
|
186
332
|
}
|
|
187
|
-
const contextId = this.
|
|
333
|
+
const contextId = __privateMethod(this, _generateId, generateId_fn).call(this);
|
|
188
334
|
(_a = this.socket) == null ? void 0 : _a.send(
|
|
189
|
-
JSON.stringify({
|
|
190
|
-
data: inputs,
|
|
335
|
+
JSON.stringify(__spreadProps(__spreadValues({
|
|
191
336
|
context_id: contextId
|
|
192
|
-
})
|
|
337
|
+
}, inputs), {
|
|
338
|
+
output_format: {
|
|
339
|
+
container: "raw",
|
|
340
|
+
encoding: "pcm_f32le",
|
|
341
|
+
sample_rate: __privateGet(this, _sampleRate2)
|
|
342
|
+
}
|
|
343
|
+
}))
|
|
193
344
|
);
|
|
345
|
+
const emitter = new import_emittery2.default();
|
|
346
|
+
const source = new Source({
|
|
347
|
+
sampleRate: __privateGet(this, _sampleRate2)
|
|
348
|
+
});
|
|
194
349
|
const streamCompleteController = new AbortController();
|
|
195
350
|
let timeoutId = null;
|
|
196
351
|
if (timeout > 0) {
|
|
197
352
|
timeoutId = setTimeout(streamCompleteController.abort, timeout);
|
|
198
353
|
}
|
|
199
|
-
const chunks = [];
|
|
200
|
-
const emitter = new import_emittery.default();
|
|
201
354
|
const handleMessage = createMessageHandlerForContextId(
|
|
202
355
|
contextId,
|
|
203
356
|
(_0) => __async(this, [_0], function* ({ chunk, message }) {
|
|
204
|
-
|
|
205
|
-
yield emitter.emit("chunk", {
|
|
206
|
-
chunk,
|
|
207
|
-
chunks
|
|
208
|
-
});
|
|
209
|
-
yield emitter.emit("message", message);
|
|
357
|
+
emitter.emit("message", message);
|
|
210
358
|
if (isSentinel(chunk)) {
|
|
211
|
-
yield
|
|
212
|
-
chunks
|
|
213
|
-
});
|
|
359
|
+
yield source.close();
|
|
214
360
|
streamCompleteController.abort();
|
|
215
|
-
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
yield source.enqueue(base64ToArray([chunk]));
|
|
364
|
+
if (timeoutId) {
|
|
216
365
|
clearTimeout(timeoutId);
|
|
217
366
|
timeoutId = setTimeout(streamCompleteController.abort, timeout);
|
|
218
367
|
}
|
|
@@ -240,107 +389,12 @@ var audio_default = class extends Client {
|
|
|
240
389
|
}
|
|
241
390
|
);
|
|
242
391
|
streamCompleteController.signal.addEventListener("abort", () => {
|
|
392
|
+
source.close();
|
|
243
393
|
if (timeoutId) {
|
|
244
394
|
clearTimeout(timeoutId);
|
|
245
395
|
}
|
|
246
|
-
emitter.clearListeners();
|
|
247
|
-
});
|
|
248
|
-
const play = (_0) => __async(this, [_0], function* ({ bufferDuration }) {
|
|
249
|
-
const context = new AudioContext({
|
|
250
|
-
sampleRate: SAMPLE_RATE
|
|
251
|
-
});
|
|
252
|
-
let startNextPlaybackAt = 0;
|
|
253
|
-
const playLatestChunk = (chunk) => {
|
|
254
|
-
if (isSentinel(chunk)) {
|
|
255
|
-
return true;
|
|
256
|
-
}
|
|
257
|
-
startNextPlaybackAt = playAudioBuffer([chunk], context, startNextPlaybackAt) + Math.max(context.currentTime, startNextPlaybackAt);
|
|
258
|
-
return false;
|
|
259
|
-
};
|
|
260
|
-
const playChunks = (chunks2) => {
|
|
261
|
-
startNextPlaybackAt += playAudioBuffer(
|
|
262
|
-
chunks2,
|
|
263
|
-
context,
|
|
264
|
-
startNextPlaybackAt
|
|
265
|
-
);
|
|
266
|
-
if (isComplete(chunks2)) {
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
const tryStart = (chunks2) => __async(this, null, function* () {
|
|
271
|
-
startNextPlaybackAt = context.currentTime;
|
|
272
|
-
if (isComplete(chunks2) || streamCompleteController.signal.aborted) {
|
|
273
|
-
emitter.emit("buffered");
|
|
274
|
-
playChunks(chunks2);
|
|
275
|
-
return true;
|
|
276
|
-
}
|
|
277
|
-
if (getBufferDuration(chunks2) > bufferDuration) {
|
|
278
|
-
emitter.emit("buffered");
|
|
279
|
-
playChunks(chunks2);
|
|
280
|
-
try {
|
|
281
|
-
for (var iter2 = __forAwait(emitter.events("chunk")), more2, temp2, error2; more2 = !(temp2 = yield iter2.next()).done; more2 = false) {
|
|
282
|
-
const { chunk } = temp2.value;
|
|
283
|
-
if (playLatestChunk(chunk)) {
|
|
284
|
-
break;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
} catch (temp2) {
|
|
288
|
-
error2 = [temp2];
|
|
289
|
-
} finally {
|
|
290
|
-
try {
|
|
291
|
-
more2 && (temp2 = iter2.return) && (yield temp2.call(iter2));
|
|
292
|
-
} finally {
|
|
293
|
-
if (error2)
|
|
294
|
-
throw error2[0];
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return true;
|
|
298
|
-
}
|
|
299
|
-
emitter.emit("buffering");
|
|
300
|
-
return false;
|
|
301
|
-
});
|
|
302
|
-
if (!(yield tryStart(chunks))) {
|
|
303
|
-
try {
|
|
304
|
-
for (var iter = __forAwait(emitter.events("chunk")), more, temp, error; more = !(temp = yield iter.next()).done; more = false) {
|
|
305
|
-
const { chunks: chunks2 } = temp.value;
|
|
306
|
-
if (yield tryStart(chunks2)) {
|
|
307
|
-
const playbackEndsIn = Math.max(0, startNextPlaybackAt - context.currentTime) * 1e3;
|
|
308
|
-
emitter.emit("scheduled", { playbackEndsIn });
|
|
309
|
-
break;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
} catch (temp) {
|
|
313
|
-
error = [temp];
|
|
314
|
-
} finally {
|
|
315
|
-
try {
|
|
316
|
-
more && (temp = iter.return) && (yield temp.call(iter));
|
|
317
|
-
} finally {
|
|
318
|
-
if (error)
|
|
319
|
-
throw error[0];
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
} else {
|
|
323
|
-
const playbackEndsIn = Math.max(0, startNextPlaybackAt - context.currentTime) * 1e3;
|
|
324
|
-
emitter.emit("scheduled", { playbackEndsIn });
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
return __spreadValues({
|
|
328
|
-
play
|
|
329
|
-
}, getEmitteryCallbacks(emitter));
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Generate a unique ID suitable for a streaming context.
|
|
333
|
-
*
|
|
334
|
-
* Not suitable for security purposes or as a primary key, since
|
|
335
|
-
* it lacks the amount of entropy required for those use cases.
|
|
336
|
-
*
|
|
337
|
-
* @returns A unique ID.
|
|
338
|
-
*/
|
|
339
|
-
generateId() {
|
|
340
|
-
return (0, import_human_id.humanId)({
|
|
341
|
-
separator: "-",
|
|
342
|
-
capitalize: false
|
|
343
396
|
});
|
|
397
|
+
return __spreadValues({ source }, getEmitteryCallbacks(emitter));
|
|
344
398
|
}
|
|
345
399
|
/**
|
|
346
400
|
* Authenticate and connect to a Cartesia streaming WebSocket.
|
|
@@ -349,16 +403,16 @@ var audio_default = class extends Client {
|
|
|
349
403
|
* @throws {Error} If the WebSocket fails to connect.
|
|
350
404
|
*/
|
|
351
405
|
connect() {
|
|
352
|
-
const url =
|
|
406
|
+
const url = constructApiUrl(this.baseUrl, "/tts/websocket", "ws");
|
|
353
407
|
url.searchParams.set("api_key", this.apiKey);
|
|
354
|
-
const emitter = new
|
|
408
|
+
const emitter = new import_emittery2.default();
|
|
355
409
|
this.socket = new import_partysocket.WebSocket(url.toString());
|
|
356
410
|
this.socket.onopen = () => {
|
|
357
|
-
this
|
|
411
|
+
__privateSet(this, _isConnected, true);
|
|
358
412
|
emitter.emit("open");
|
|
359
413
|
};
|
|
360
414
|
this.socket.onclose = () => {
|
|
361
|
-
this
|
|
415
|
+
__privateSet(this, _isConnected, false);
|
|
362
416
|
emitter.emit("close");
|
|
363
417
|
};
|
|
364
418
|
return new Promise(
|
|
@@ -405,15 +459,194 @@ var audio_default = class extends Client {
|
|
|
405
459
|
(_a = this.socket) == null ? void 0 : _a.close();
|
|
406
460
|
}
|
|
407
461
|
};
|
|
462
|
+
_isConnected = new WeakMap();
|
|
463
|
+
_sampleRate2 = new WeakMap();
|
|
464
|
+
_generateId = new WeakSet();
|
|
465
|
+
generateId_fn = function() {
|
|
466
|
+
return (0, import_human_id.humanId)({
|
|
467
|
+
separator: "-",
|
|
468
|
+
capitalize: false
|
|
469
|
+
});
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
// src/tts/index.ts
|
|
473
|
+
var TTS = class extends Client {
|
|
474
|
+
/**
|
|
475
|
+
* Get a WebSocket client for streaming audio from the TTS API.
|
|
476
|
+
*
|
|
477
|
+
* @returns {WebSocket} A Cartesia WebSocket client.
|
|
478
|
+
*/
|
|
479
|
+
websocket(options) {
|
|
480
|
+
return new WebSocket(options, {
|
|
481
|
+
apiKey: this.apiKey,
|
|
482
|
+
baseUrl: this.baseUrl
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// src/voices/index.ts
|
|
488
|
+
var Voices = class extends Client {
|
|
489
|
+
list() {
|
|
490
|
+
return __async(this, null, function* () {
|
|
491
|
+
const response = yield this.fetch("/voices");
|
|
492
|
+
return response.json();
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
get(voiceId) {
|
|
496
|
+
return __async(this, null, function* () {
|
|
497
|
+
const response = yield this.fetch(`/voices/${voiceId}`);
|
|
498
|
+
return response.json();
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
create(voice) {
|
|
502
|
+
return __async(this, null, function* () {
|
|
503
|
+
const response = yield this.fetch("/voices", {
|
|
504
|
+
method: "POST",
|
|
505
|
+
body: JSON.stringify(voice)
|
|
506
|
+
});
|
|
507
|
+
return response.json();
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
clone(options) {
|
|
511
|
+
return __async(this, null, function* () {
|
|
512
|
+
if (options.mode === "url") {
|
|
513
|
+
const response = yield this.fetch(
|
|
514
|
+
`/voices/clone/url?link=${options.link}`,
|
|
515
|
+
{
|
|
516
|
+
method: "POST"
|
|
517
|
+
}
|
|
518
|
+
);
|
|
519
|
+
return response.json();
|
|
520
|
+
}
|
|
521
|
+
if (options.mode === "clip") {
|
|
522
|
+
const formData = new FormData();
|
|
523
|
+
formData.append("clip", options.clip);
|
|
524
|
+
const response = yield this.fetch("/voices/clone/clip", {
|
|
525
|
+
method: "POST",
|
|
526
|
+
body: formData
|
|
527
|
+
});
|
|
528
|
+
return response.json();
|
|
529
|
+
}
|
|
530
|
+
throw new Error("Invalid mode for clone()");
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
};
|
|
408
534
|
|
|
409
535
|
// src/lib/index.ts
|
|
410
536
|
var Cartesia = class extends Client {
|
|
411
537
|
constructor(options = {}) {
|
|
412
538
|
super(options);
|
|
413
|
-
this.
|
|
539
|
+
this.tts = new TTS(options);
|
|
540
|
+
this.voices = new Voices(options);
|
|
414
541
|
}
|
|
415
542
|
};
|
|
543
|
+
|
|
544
|
+
// src/tts/player.ts
|
|
545
|
+
var import_emittery3 = __toESM(require("emittery"), 1);
|
|
546
|
+
var _context, _startNextPlaybackAt, _bufferDuration, _emitter2, _playBuffer, playBuffer_fn;
|
|
547
|
+
var Player = class {
|
|
548
|
+
/**
|
|
549
|
+
* Create a new Player.
|
|
550
|
+
*
|
|
551
|
+
* @param options - Options for the Player.
|
|
552
|
+
* @param options.bufferDuration - The duration of the audio buffer to play.
|
|
553
|
+
*/
|
|
554
|
+
constructor({ bufferDuration }) {
|
|
555
|
+
__privateAdd(this, _playBuffer);
|
|
556
|
+
__privateAdd(this, _context, null);
|
|
557
|
+
__privateAdd(this, _startNextPlaybackAt, 0);
|
|
558
|
+
__privateAdd(this, _bufferDuration, void 0);
|
|
559
|
+
__privateAdd(this, _emitter2, new import_emittery3.default());
|
|
560
|
+
__privateSet(this, _bufferDuration, bufferDuration);
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Play audio from a source.
|
|
564
|
+
*
|
|
565
|
+
* @param source The source to play audio from.
|
|
566
|
+
* @returns A promise that resolves when the audio has finished playing.
|
|
567
|
+
*/
|
|
568
|
+
play(source) {
|
|
569
|
+
return __async(this, null, function* () {
|
|
570
|
+
__privateSet(this, _startNextPlaybackAt, 0);
|
|
571
|
+
__privateSet(this, _context, new AudioContext({ sampleRate: source.sampleRate }));
|
|
572
|
+
const buffer = new Float32Array(
|
|
573
|
+
source.durationToSampleCount(__privateGet(this, _bufferDuration))
|
|
574
|
+
);
|
|
575
|
+
const plays = [];
|
|
576
|
+
while (true) {
|
|
577
|
+
const read = yield source.read(buffer);
|
|
578
|
+
const playableAudio = buffer.slice(0, read);
|
|
579
|
+
plays.push(__privateMethod(this, _playBuffer, playBuffer_fn).call(this, playableAudio, source.sampleRate));
|
|
580
|
+
if (read < buffer.length) {
|
|
581
|
+
yield __privateGet(this, _emitter2).emit("finish");
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
yield Promise.all(plays);
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Pause the audio.
|
|
590
|
+
*
|
|
591
|
+
* @returns A promise that resolves when the audio has been paused.
|
|
592
|
+
*/
|
|
593
|
+
pause() {
|
|
594
|
+
return __async(this, null, function* () {
|
|
595
|
+
if (!__privateGet(this, _context)) {
|
|
596
|
+
throw new Error("AudioContext not initialized.");
|
|
597
|
+
}
|
|
598
|
+
yield __privateGet(this, _context).suspend();
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Resume the audio.
|
|
603
|
+
*
|
|
604
|
+
* @returns A promise that resolves when the audio has been resumed.
|
|
605
|
+
*/
|
|
606
|
+
resume() {
|
|
607
|
+
return __async(this, null, function* () {
|
|
608
|
+
if (!__privateGet(this, _context)) {
|
|
609
|
+
throw new Error("AudioContext not initialized.");
|
|
610
|
+
}
|
|
611
|
+
yield __privateGet(this, _context).resume();
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Toggle the audio.
|
|
616
|
+
*
|
|
617
|
+
* @returns A promise that resolves when the audio has been toggled.
|
|
618
|
+
*/
|
|
619
|
+
toggle() {
|
|
620
|
+
return __async(this, null, function* () {
|
|
621
|
+
if (!__privateGet(this, _context)) {
|
|
622
|
+
throw new Error("AudioContext not initialized.");
|
|
623
|
+
}
|
|
624
|
+
if (__privateGet(this, _context).state === "running") {
|
|
625
|
+
yield this.pause();
|
|
626
|
+
} else {
|
|
627
|
+
yield this.resume();
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
_context = new WeakMap();
|
|
633
|
+
_startNextPlaybackAt = new WeakMap();
|
|
634
|
+
_bufferDuration = new WeakMap();
|
|
635
|
+
_emitter2 = new WeakMap();
|
|
636
|
+
_playBuffer = new WeakSet();
|
|
637
|
+
playBuffer_fn = function(buf, sampleRate) {
|
|
638
|
+
return __async(this, null, function* () {
|
|
639
|
+
if (!__privateGet(this, _context)) {
|
|
640
|
+
throw new Error("AudioContext not initialized.");
|
|
641
|
+
}
|
|
642
|
+
const startAt = __privateGet(this, _startNextPlaybackAt);
|
|
643
|
+
const duration = buf.length / sampleRate;
|
|
644
|
+
__privateSet(this, _startNextPlaybackAt, duration + Math.max(__privateGet(this, _context).currentTime, __privateGet(this, _startNextPlaybackAt)));
|
|
645
|
+
yield playAudioBuffer(buf, __privateGet(this, _context), startAt, sampleRate);
|
|
646
|
+
});
|
|
647
|
+
};
|
|
416
648
|
// Annotate the CommonJS export names for ESM import in node:
|
|
417
649
|
0 && (module.exports = {
|
|
418
|
-
Cartesia
|
|
650
|
+
Cartesia,
|
|
651
|
+
WebPlayer
|
|
419
652
|
});
|