@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
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import emittery__default from 'emittery';
|
|
2
|
+
import { Chunk, Sentinel, EmitteryCallbacks } from '../types/index.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Convert base64-encoded audio buffer(s) to a Float32Array.
|
|
6
|
+
*
|
|
7
|
+
* @param b64 The base64-encoded audio buffer, or an array of base64-encoded
|
|
8
|
+
* audio buffers.
|
|
9
|
+
* @returns The audio buffer(s) as a Float32Array.
|
|
10
|
+
*/
|
|
11
|
+
declare function base64ToArray(b64: Chunk[]): Float32Array;
|
|
12
|
+
/**
|
|
13
|
+
* Schedule an audio buffer to play at a given time in the passed context.
|
|
14
|
+
*
|
|
15
|
+
* @param floats The audio buffer to play.
|
|
16
|
+
* @param context The audio context to play the buffer in.
|
|
17
|
+
* @param startAt The time to start playing the buffer at.
|
|
18
|
+
* @param sampleRate The sample rate of the audio.
|
|
19
|
+
* @returns A promise that resolves when the audio has finished playing.
|
|
20
|
+
*/
|
|
21
|
+
declare function playAudioBuffer(floats: Float32Array, context: AudioContext, startAt: number, sampleRate: number): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Unwraps a chunk of audio data from a message event and calls the
|
|
24
|
+
* handler with it if the context ID matches.
|
|
25
|
+
*
|
|
26
|
+
* @param contextId The context ID to listen for.
|
|
27
|
+
* @param handler The handler to call with the chunk of audio data.
|
|
28
|
+
* @returns A message event handler.
|
|
29
|
+
*/
|
|
30
|
+
declare function createMessageHandlerForContextId(contextId: string, handler: ({ chunk, message, }: {
|
|
31
|
+
chunk: Chunk;
|
|
32
|
+
message: string;
|
|
33
|
+
}) => void): (event: MessageEvent) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Get a sentinel value that indicates the end of a stream.
|
|
36
|
+
* @returns A sentinel value to indicate the end of a stream.
|
|
37
|
+
*/
|
|
38
|
+
declare function getSentinel(): Sentinel;
|
|
39
|
+
/**
|
|
40
|
+
* Check if a chunk is a sentinel value (i.e. null).
|
|
41
|
+
*
|
|
42
|
+
* @param chunk
|
|
43
|
+
* @returns Whether the chunk is a sentinel value.
|
|
44
|
+
*/
|
|
45
|
+
declare function isSentinel(x: unknown): x is Sentinel;
|
|
46
|
+
/**
|
|
47
|
+
* Filter out null values from a collection.
|
|
48
|
+
*
|
|
49
|
+
* @param collection The collection to filter.
|
|
50
|
+
* @returns The collection with null values removed.
|
|
51
|
+
*/
|
|
52
|
+
declare function filterSentinel<T>(collection: T[]): Exclude<T, Sentinel>[];
|
|
53
|
+
/**
|
|
54
|
+
* Check if an array of chunks is complete by testing if the last chunk is a sentinel
|
|
55
|
+
* value (i.e. null).
|
|
56
|
+
* @param chunk
|
|
57
|
+
* @returns Whether the array of chunks is complete.
|
|
58
|
+
*/
|
|
59
|
+
declare function isComplete(chunks: Chunk[]): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Get user-facing emitter callbacks for an Emittery instance.
|
|
62
|
+
* @param emitter The Emittery instance to get callbacks for.
|
|
63
|
+
* @returns User-facing emitter callbacks.
|
|
64
|
+
*/
|
|
65
|
+
declare function getEmitteryCallbacks<T>(emitter: emittery__default<T>): EmitteryCallbacks<T>;
|
|
66
|
+
|
|
67
|
+
export { base64ToArray, createMessageHandlerForContextId, filterSentinel, getEmitteryCallbacks, getSentinel, isComplete, isSentinel, playAudioBuffer };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import emittery__default from 'emittery';
|
|
2
|
+
import { Chunk, Sentinel, EmitteryCallbacks } from '../types/index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Convert base64-encoded audio buffer(s) to a Float32Array.
|
|
6
|
+
*
|
|
7
|
+
* @param b64 The base64-encoded audio buffer, or an array of base64-encoded
|
|
8
|
+
* audio buffers.
|
|
9
|
+
* @returns The audio buffer(s) as a Float32Array.
|
|
10
|
+
*/
|
|
11
|
+
declare function base64ToArray(b64: Chunk[]): Float32Array;
|
|
12
|
+
/**
|
|
13
|
+
* Schedule an audio buffer to play at a given time in the passed context.
|
|
14
|
+
*
|
|
15
|
+
* @param floats The audio buffer to play.
|
|
16
|
+
* @param context The audio context to play the buffer in.
|
|
17
|
+
* @param startAt The time to start playing the buffer at.
|
|
18
|
+
* @param sampleRate The sample rate of the audio.
|
|
19
|
+
* @returns A promise that resolves when the audio has finished playing.
|
|
20
|
+
*/
|
|
21
|
+
declare function playAudioBuffer(floats: Float32Array, context: AudioContext, startAt: number, sampleRate: number): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Unwraps a chunk of audio data from a message event and calls the
|
|
24
|
+
* handler with it if the context ID matches.
|
|
25
|
+
*
|
|
26
|
+
* @param contextId The context ID to listen for.
|
|
27
|
+
* @param handler The handler to call with the chunk of audio data.
|
|
28
|
+
* @returns A message event handler.
|
|
29
|
+
*/
|
|
30
|
+
declare function createMessageHandlerForContextId(contextId: string, handler: ({ chunk, message, }: {
|
|
31
|
+
chunk: Chunk;
|
|
32
|
+
message: string;
|
|
33
|
+
}) => void): (event: MessageEvent) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Get a sentinel value that indicates the end of a stream.
|
|
36
|
+
* @returns A sentinel value to indicate the end of a stream.
|
|
37
|
+
*/
|
|
38
|
+
declare function getSentinel(): Sentinel;
|
|
39
|
+
/**
|
|
40
|
+
* Check if a chunk is a sentinel value (i.e. null).
|
|
41
|
+
*
|
|
42
|
+
* @param chunk
|
|
43
|
+
* @returns Whether the chunk is a sentinel value.
|
|
44
|
+
*/
|
|
45
|
+
declare function isSentinel(x: unknown): x is Sentinel;
|
|
46
|
+
/**
|
|
47
|
+
* Filter out null values from a collection.
|
|
48
|
+
*
|
|
49
|
+
* @param collection The collection to filter.
|
|
50
|
+
* @returns The collection with null values removed.
|
|
51
|
+
*/
|
|
52
|
+
declare function filterSentinel<T>(collection: T[]): Exclude<T, Sentinel>[];
|
|
53
|
+
/**
|
|
54
|
+
* Check if an array of chunks is complete by testing if the last chunk is a sentinel
|
|
55
|
+
* value (i.e. null).
|
|
56
|
+
* @param chunk
|
|
57
|
+
* @returns Whether the array of chunks is complete.
|
|
58
|
+
*/
|
|
59
|
+
declare function isComplete(chunks: Chunk[]): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Get user-facing emitter callbacks for an Emittery instance.
|
|
62
|
+
* @param emitter The Emittery instance to get callbacks for.
|
|
63
|
+
* @returns User-facing emitter callbacks.
|
|
64
|
+
*/
|
|
65
|
+
declare function getEmitteryCallbacks<T>(emitter: emittery__default<T>): EmitteryCallbacks<T>;
|
|
66
|
+
|
|
67
|
+
export { base64ToArray, createMessageHandlerForContextId, filterSentinel, getEmitteryCallbacks, getSentinel, isComplete, isSentinel, playAudioBuffer };
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
base64ToArray,
|
|
3
|
-
bufferToWav,
|
|
4
3
|
createMessageHandlerForContextId,
|
|
5
4
|
filterSentinel,
|
|
6
|
-
getBufferDuration,
|
|
7
5
|
getEmitteryCallbacks,
|
|
8
6
|
getSentinel,
|
|
9
7
|
isComplete,
|
|
10
8
|
isSentinel,
|
|
11
9
|
playAudioBuffer
|
|
12
|
-
} from "../chunk-
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-R4P7LWVZ.js";
|
|
10
|
+
} from "../chunk-LYPTISWL.js";
|
|
11
|
+
import "../chunk-WIFMLPT5.js";
|
|
15
12
|
export {
|
|
16
13
|
base64ToArray,
|
|
17
|
-
bufferToWav,
|
|
18
14
|
createMessageHandlerForContextId,
|
|
19
15
|
filterSentinel,
|
|
20
|
-
getBufferDuration,
|
|
21
16
|
getEmitteryCallbacks,
|
|
22
17
|
getSentinel,
|
|
23
18
|
isComplete,
|
|
@@ -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,23 +85,31 @@ 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
|
-
// src/
|
|
69
|
-
var
|
|
70
|
-
__export(
|
|
71
|
-
default: () =>
|
|
89
|
+
// src/tts/websocket.ts
|
|
90
|
+
var websocket_exports = {};
|
|
91
|
+
__export(websocket_exports, {
|
|
92
|
+
default: () => WebSocket
|
|
72
93
|
});
|
|
73
|
-
module.exports = __toCommonJS(
|
|
74
|
-
var
|
|
94
|
+
module.exports = __toCommonJS(websocket_exports);
|
|
95
|
+
var import_emittery2 = __toESM(require("emittery"), 1);
|
|
75
96
|
var import_human_id = require("human-id");
|
|
76
97
|
var import_partysocket = require("partysocket");
|
|
77
98
|
|
|
99
|
+
// src/lib/client.ts
|
|
100
|
+
var import_cross_fetch = __toESM(require("cross-fetch"), 1);
|
|
101
|
+
|
|
78
102
|
// src/lib/constants.ts
|
|
79
103
|
var BASE_URL = "https://api.cartesia.ai/v0";
|
|
80
|
-
var
|
|
81
|
-
|
|
82
|
-
|
|
104
|
+
var constructApiUrl = (baseUrl, path, protocol) => {
|
|
105
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
106
|
+
if (!protocol) {
|
|
107
|
+
return new URL(`${baseUrl}${normalizedPath}`);
|
|
108
|
+
}
|
|
109
|
+
if (!["http", "ws"].includes(protocol)) {
|
|
110
|
+
throw new Error(`Invalid protocol: ${protocol}`);
|
|
111
|
+
}
|
|
112
|
+
return new URL(`${baseUrl.replace(/^http/, protocol)}${normalizedPath}`);
|
|
83
113
|
};
|
|
84
114
|
|
|
85
115
|
// src/lib/client.ts
|
|
@@ -91,14 +121,114 @@ var Client = class {
|
|
|
91
121
|
this.apiKey = options.apiKey || process.env.CARTESIA_API_KEY;
|
|
92
122
|
this.baseUrl = options.baseUrl || BASE_URL;
|
|
93
123
|
}
|
|
124
|
+
fetch(path, options = {}) {
|
|
125
|
+
const url = constructApiUrl(this.baseUrl, path);
|
|
126
|
+
return (0, import_cross_fetch.default)(url.toString(), __spreadProps(__spreadValues({}, options), {
|
|
127
|
+
headers: __spreadValues({
|
|
128
|
+
"X-API-KEY": this.apiKey
|
|
129
|
+
}, options.headers)
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
94
132
|
};
|
|
95
133
|
|
|
96
|
-
// src/
|
|
134
|
+
// src/tts/source.ts
|
|
135
|
+
var import_emittery = __toESM(require("emittery"), 1);
|
|
136
|
+
var _emitter, _buffer, _readIndex, _closed, _sampleRate;
|
|
137
|
+
var Source = class {
|
|
138
|
+
/**
|
|
139
|
+
* Create a new Source.
|
|
140
|
+
*
|
|
141
|
+
* @param options - Options for the Source.
|
|
142
|
+
* @param options.sampleRate - The sample rate of the audio.
|
|
143
|
+
*/
|
|
144
|
+
constructor({ sampleRate }) {
|
|
145
|
+
__privateAdd(this, _emitter, new import_emittery.default());
|
|
146
|
+
__privateAdd(this, _buffer, new Float32Array());
|
|
147
|
+
__privateAdd(this, _readIndex, 0);
|
|
148
|
+
__privateAdd(this, _closed, false);
|
|
149
|
+
__privateAdd(this, _sampleRate, void 0);
|
|
150
|
+
this.on = __privateGet(this, _emitter).on.bind(__privateGet(this, _emitter));
|
|
151
|
+
this.once = __privateGet(this, _emitter).once.bind(__privateGet(this, _emitter));
|
|
152
|
+
this.events = __privateGet(this, _emitter).events.bind(__privateGet(this, _emitter));
|
|
153
|
+
this.off = __privateGet(this, _emitter).off.bind(__privateGet(this, _emitter));
|
|
154
|
+
__privateSet(this, _sampleRate, sampleRate);
|
|
155
|
+
}
|
|
156
|
+
get sampleRate() {
|
|
157
|
+
return __privateGet(this, _sampleRate);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Append audio to the buffer.
|
|
161
|
+
*
|
|
162
|
+
* @param src The audio to append.
|
|
163
|
+
*/
|
|
164
|
+
enqueue(src) {
|
|
165
|
+
return __async(this, null, function* () {
|
|
166
|
+
__privateSet(this, _buffer, new Float32Array([...__privateGet(this, _buffer), ...src]));
|
|
167
|
+
yield __privateGet(this, _emitter).emit("enqueue");
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Read audio from the buffer.
|
|
172
|
+
*
|
|
173
|
+
* @param dst The buffer to read the audio into.
|
|
174
|
+
* @returns The number of samples read. If the source is closed, this will be
|
|
175
|
+
* less than the length of the provided buffer.
|
|
176
|
+
*/
|
|
177
|
+
read(dst) {
|
|
178
|
+
return __async(this, null, function* () {
|
|
179
|
+
const targetReadIndex = __privateGet(this, _readIndex) + dst.length;
|
|
180
|
+
while (!__privateGet(this, _closed) && targetReadIndex > __privateGet(this, _buffer).length) {
|
|
181
|
+
yield __privateGet(this, _emitter).emit("wait");
|
|
182
|
+
yield Promise.race([
|
|
183
|
+
__privateGet(this, _emitter).once("enqueue"),
|
|
184
|
+
__privateGet(this, _emitter).once("close")
|
|
185
|
+
]);
|
|
186
|
+
yield __privateGet(this, _emitter).emit("read");
|
|
187
|
+
}
|
|
188
|
+
const read = Math.min(dst.length, __privateGet(this, _buffer).length - __privateGet(this, _readIndex));
|
|
189
|
+
dst.set(__privateGet(this, _buffer).slice(__privateGet(this, _readIndex), __privateGet(this, _readIndex) + read));
|
|
190
|
+
__privateSet(this, _readIndex, __privateGet(this, _readIndex) + read);
|
|
191
|
+
return read;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get the number of samples in a given duration.
|
|
196
|
+
*
|
|
197
|
+
* @param durationSecs The duration in seconds.
|
|
198
|
+
* @returns The number of samples.
|
|
199
|
+
*/
|
|
200
|
+
durationToSampleCount(durationSecs) {
|
|
201
|
+
return Math.trunc(durationSecs * __privateGet(this, _sampleRate));
|
|
202
|
+
}
|
|
203
|
+
get buffer() {
|
|
204
|
+
return __privateGet(this, _buffer);
|
|
205
|
+
}
|
|
206
|
+
get readIndex() {
|
|
207
|
+
return __privateGet(this, _readIndex);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Close the source. This signals that no more audio will be enqueued.
|
|
211
|
+
*
|
|
212
|
+
* This will emit a "close" event.
|
|
213
|
+
*
|
|
214
|
+
* @returns A promise that resolves when the source is closed.
|
|
215
|
+
*/
|
|
216
|
+
close() {
|
|
217
|
+
return __async(this, null, function* () {
|
|
218
|
+
__privateSet(this, _closed, true);
|
|
219
|
+
yield __privateGet(this, _emitter).emit("close");
|
|
220
|
+
__privateGet(this, _emitter).clearListeners();
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
_emitter = new WeakMap();
|
|
225
|
+
_buffer = new WeakMap();
|
|
226
|
+
_readIndex = new WeakMap();
|
|
227
|
+
_closed = new WeakMap();
|
|
228
|
+
_sampleRate = new WeakMap();
|
|
229
|
+
|
|
230
|
+
// src/tts/utils.ts
|
|
97
231
|
var import_base64_js = __toESM(require("base64-js"), 1);
|
|
98
|
-
function getBufferDuration(b64) {
|
|
99
|
-
const floats = base64ToArray(b64);
|
|
100
|
-
return floats.length / SAMPLE_RATE;
|
|
101
|
-
}
|
|
102
232
|
function base64ToArray(b64) {
|
|
103
233
|
return filterSentinel(b64).reduce((acc, b) => {
|
|
104
234
|
const floats = new Float32Array(import_base64_js.default.toByteArray(b).buffer);
|
|
@@ -108,20 +238,11 @@ function base64ToArray(b64) {
|
|
|
108
238
|
return newAcc;
|
|
109
239
|
}, new Float32Array(0));
|
|
110
240
|
}
|
|
111
|
-
function playAudioBuffer(b64, context, maybeStartAt = null, onEnded = null) {
|
|
112
|
-
const startAt = maybeStartAt != null ? maybeStartAt : context.currentTime;
|
|
113
|
-
const floats = base64ToArray(b64);
|
|
114
|
-
const source = context.createBufferSource();
|
|
115
|
-
const buffer = context.createBuffer(1, floats.length, SAMPLE_RATE);
|
|
116
|
-
buffer.getChannelData(0).set(floats);
|
|
117
|
-
source.buffer = buffer;
|
|
118
|
-
source.connect(context.destination);
|
|
119
|
-
source.start(startAt);
|
|
120
|
-
source.onended = onEnded;
|
|
121
|
-
return buffer.duration;
|
|
122
|
-
}
|
|
123
241
|
function createMessageHandlerForContextId(contextId, handler) {
|
|
124
242
|
return (event) => {
|
|
243
|
+
if (typeof event.data !== "string") {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
125
246
|
const message = JSON.parse(event.data);
|
|
126
247
|
if (message.context_id !== contextId) {
|
|
127
248
|
return;
|
|
@@ -132,7 +253,7 @@ function createMessageHandlerForContextId(contextId, handler) {
|
|
|
132
253
|
} else {
|
|
133
254
|
chunk = message.data;
|
|
134
255
|
}
|
|
135
|
-
handler({ chunk, message });
|
|
256
|
+
handler({ chunk, message: event.data });
|
|
136
257
|
};
|
|
137
258
|
}
|
|
138
259
|
function getSentinel() {
|
|
@@ -146,9 +267,6 @@ function filterSentinel(collection) {
|
|
|
146
267
|
(x) => !isSentinel(x)
|
|
147
268
|
);
|
|
148
269
|
}
|
|
149
|
-
function isComplete(chunks) {
|
|
150
|
-
return isSentinel(chunks[chunks.length - 1]);
|
|
151
|
-
}
|
|
152
270
|
function getEmitteryCallbacks(emitter) {
|
|
153
271
|
return {
|
|
154
272
|
on: emitter.on.bind(emitter),
|
|
@@ -158,58 +276,75 @@ function getEmitteryCallbacks(emitter) {
|
|
|
158
276
|
};
|
|
159
277
|
}
|
|
160
278
|
|
|
161
|
-
// src/
|
|
162
|
-
var
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
279
|
+
// src/tts/websocket.ts
|
|
280
|
+
var _isConnected, _sampleRate2, _generateId, generateId_fn;
|
|
281
|
+
var WebSocket = class extends Client {
|
|
282
|
+
/**
|
|
283
|
+
* Create a new WebSocket client.
|
|
284
|
+
*
|
|
285
|
+
* @param args - Arguments to pass to the Client constructor.
|
|
286
|
+
*/
|
|
287
|
+
constructor({ sampleRate }, ...args) {
|
|
288
|
+
super(...args);
|
|
289
|
+
/**
|
|
290
|
+
* Generate a unique ID suitable for a streaming context.
|
|
291
|
+
*
|
|
292
|
+
* Not suitable for security purposes or as a primary key, since
|
|
293
|
+
* it lacks the amount of entropy required for those use cases.
|
|
294
|
+
*
|
|
295
|
+
* @returns A unique ID.
|
|
296
|
+
*/
|
|
297
|
+
__privateAdd(this, _generateId);
|
|
298
|
+
__privateAdd(this, _isConnected, false);
|
|
299
|
+
__privateAdd(this, _sampleRate2, void 0);
|
|
300
|
+
__privateSet(this, _sampleRate2, sampleRate);
|
|
166
301
|
}
|
|
167
302
|
/**
|
|
168
|
-
*
|
|
303
|
+
* Send a message over the WebSocket in order to start a stream.
|
|
169
304
|
*
|
|
170
|
-
* @param inputs - Stream options.
|
|
171
|
-
* are model-specific and can be found in the model's documentation.
|
|
305
|
+
* @param inputs - Stream options.
|
|
172
306
|
* @param options - Options for the stream.
|
|
173
307
|
* @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
|
|
174
308
|
* If `0`, the stream will not time out.
|
|
175
|
-
* @returns
|
|
176
|
-
* that plays the audio as it arrives, with `bufferDuration` seconds of audio buffered before
|
|
177
|
-
* starting playback.
|
|
309
|
+
* @returns A Source object that can be passed to a Player to play the audio.
|
|
178
310
|
*/
|
|
179
|
-
|
|
311
|
+
send(inputs, { timeout = 0 } = {}) {
|
|
180
312
|
var _a, _b, _c, _d;
|
|
181
|
-
if (!this
|
|
313
|
+
if (!__privateGet(this, _isConnected)) {
|
|
182
314
|
throw new Error("Not connected to WebSocket. Call .connect() first.");
|
|
183
315
|
}
|
|
184
|
-
const contextId = this.
|
|
316
|
+
const contextId = __privateMethod(this, _generateId, generateId_fn).call(this);
|
|
185
317
|
(_a = this.socket) == null ? void 0 : _a.send(
|
|
186
|
-
JSON.stringify({
|
|
187
|
-
data: inputs,
|
|
318
|
+
JSON.stringify(__spreadProps(__spreadValues({
|
|
188
319
|
context_id: contextId
|
|
189
|
-
})
|
|
320
|
+
}, inputs), {
|
|
321
|
+
output_format: {
|
|
322
|
+
container: "raw",
|
|
323
|
+
encoding: "pcm_f32le",
|
|
324
|
+
sample_rate: __privateGet(this, _sampleRate2)
|
|
325
|
+
}
|
|
326
|
+
}))
|
|
190
327
|
);
|
|
328
|
+
const emitter = new import_emittery2.default();
|
|
329
|
+
const source = new Source({
|
|
330
|
+
sampleRate: __privateGet(this, _sampleRate2)
|
|
331
|
+
});
|
|
191
332
|
const streamCompleteController = new AbortController();
|
|
192
333
|
let timeoutId = null;
|
|
193
334
|
if (timeout > 0) {
|
|
194
335
|
timeoutId = setTimeout(streamCompleteController.abort, timeout);
|
|
195
336
|
}
|
|
196
|
-
const chunks = [];
|
|
197
|
-
const emitter = new import_emittery.default();
|
|
198
337
|
const handleMessage = createMessageHandlerForContextId(
|
|
199
338
|
contextId,
|
|
200
339
|
(_0) => __async(this, [_0], function* ({ chunk, message }) {
|
|
201
|
-
|
|
202
|
-
yield emitter.emit("chunk", {
|
|
203
|
-
chunk,
|
|
204
|
-
chunks
|
|
205
|
-
});
|
|
206
|
-
yield emitter.emit("message", message);
|
|
340
|
+
emitter.emit("message", message);
|
|
207
341
|
if (isSentinel(chunk)) {
|
|
208
|
-
yield
|
|
209
|
-
chunks
|
|
210
|
-
});
|
|
342
|
+
yield source.close();
|
|
211
343
|
streamCompleteController.abort();
|
|
212
|
-
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
yield source.enqueue(base64ToArray([chunk]));
|
|
347
|
+
if (timeoutId) {
|
|
213
348
|
clearTimeout(timeoutId);
|
|
214
349
|
timeoutId = setTimeout(streamCompleteController.abort, timeout);
|
|
215
350
|
}
|
|
@@ -237,107 +372,12 @@ var audio_default = class extends Client {
|
|
|
237
372
|
}
|
|
238
373
|
);
|
|
239
374
|
streamCompleteController.signal.addEventListener("abort", () => {
|
|
375
|
+
source.close();
|
|
240
376
|
if (timeoutId) {
|
|
241
377
|
clearTimeout(timeoutId);
|
|
242
378
|
}
|
|
243
|
-
emitter.clearListeners();
|
|
244
|
-
});
|
|
245
|
-
const play = (_0) => __async(this, [_0], function* ({ bufferDuration }) {
|
|
246
|
-
const context = new AudioContext({
|
|
247
|
-
sampleRate: SAMPLE_RATE
|
|
248
|
-
});
|
|
249
|
-
let startNextPlaybackAt = 0;
|
|
250
|
-
const playLatestChunk = (chunk) => {
|
|
251
|
-
if (isSentinel(chunk)) {
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
|
-
startNextPlaybackAt = playAudioBuffer([chunk], context, startNextPlaybackAt) + Math.max(context.currentTime, startNextPlaybackAt);
|
|
255
|
-
return false;
|
|
256
|
-
};
|
|
257
|
-
const playChunks = (chunks2) => {
|
|
258
|
-
startNextPlaybackAt += playAudioBuffer(
|
|
259
|
-
chunks2,
|
|
260
|
-
context,
|
|
261
|
-
startNextPlaybackAt
|
|
262
|
-
);
|
|
263
|
-
if (isComplete(chunks2)) {
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
const tryStart = (chunks2) => __async(this, null, function* () {
|
|
268
|
-
startNextPlaybackAt = context.currentTime;
|
|
269
|
-
if (isComplete(chunks2) || streamCompleteController.signal.aborted) {
|
|
270
|
-
emitter.emit("buffered");
|
|
271
|
-
playChunks(chunks2);
|
|
272
|
-
return true;
|
|
273
|
-
}
|
|
274
|
-
if (getBufferDuration(chunks2) > bufferDuration) {
|
|
275
|
-
emitter.emit("buffered");
|
|
276
|
-
playChunks(chunks2);
|
|
277
|
-
try {
|
|
278
|
-
for (var iter2 = __forAwait(emitter.events("chunk")), more2, temp2, error2; more2 = !(temp2 = yield iter2.next()).done; more2 = false) {
|
|
279
|
-
const { chunk } = temp2.value;
|
|
280
|
-
if (playLatestChunk(chunk)) {
|
|
281
|
-
break;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
} catch (temp2) {
|
|
285
|
-
error2 = [temp2];
|
|
286
|
-
} finally {
|
|
287
|
-
try {
|
|
288
|
-
more2 && (temp2 = iter2.return) && (yield temp2.call(iter2));
|
|
289
|
-
} finally {
|
|
290
|
-
if (error2)
|
|
291
|
-
throw error2[0];
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
return true;
|
|
295
|
-
}
|
|
296
|
-
emitter.emit("buffering");
|
|
297
|
-
return false;
|
|
298
|
-
});
|
|
299
|
-
if (!(yield tryStart(chunks))) {
|
|
300
|
-
try {
|
|
301
|
-
for (var iter = __forAwait(emitter.events("chunk")), more, temp, error; more = !(temp = yield iter.next()).done; more = false) {
|
|
302
|
-
const { chunks: chunks2 } = temp.value;
|
|
303
|
-
if (yield tryStart(chunks2)) {
|
|
304
|
-
const playbackEndsIn = Math.max(0, startNextPlaybackAt - context.currentTime) * 1e3;
|
|
305
|
-
emitter.emit("scheduled", { playbackEndsIn });
|
|
306
|
-
break;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
} catch (temp) {
|
|
310
|
-
error = [temp];
|
|
311
|
-
} finally {
|
|
312
|
-
try {
|
|
313
|
-
more && (temp = iter.return) && (yield temp.call(iter));
|
|
314
|
-
} finally {
|
|
315
|
-
if (error)
|
|
316
|
-
throw error[0];
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
} else {
|
|
320
|
-
const playbackEndsIn = Math.max(0, startNextPlaybackAt - context.currentTime) * 1e3;
|
|
321
|
-
emitter.emit("scheduled", { playbackEndsIn });
|
|
322
|
-
}
|
|
323
|
-
});
|
|
324
|
-
return __spreadValues({
|
|
325
|
-
play
|
|
326
|
-
}, getEmitteryCallbacks(emitter));
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* Generate a unique ID suitable for a streaming context.
|
|
330
|
-
*
|
|
331
|
-
* Not suitable for security purposes or as a primary key, since
|
|
332
|
-
* it lacks the amount of entropy required for those use cases.
|
|
333
|
-
*
|
|
334
|
-
* @returns A unique ID.
|
|
335
|
-
*/
|
|
336
|
-
generateId() {
|
|
337
|
-
return (0, import_human_id.humanId)({
|
|
338
|
-
separator: "-",
|
|
339
|
-
capitalize: false
|
|
340
379
|
});
|
|
380
|
+
return __spreadValues({ source }, getEmitteryCallbacks(emitter));
|
|
341
381
|
}
|
|
342
382
|
/**
|
|
343
383
|
* Authenticate and connect to a Cartesia streaming WebSocket.
|
|
@@ -346,16 +386,16 @@ var audio_default = class extends Client {
|
|
|
346
386
|
* @throws {Error} If the WebSocket fails to connect.
|
|
347
387
|
*/
|
|
348
388
|
connect() {
|
|
349
|
-
const url =
|
|
389
|
+
const url = constructApiUrl(this.baseUrl, "/tts/websocket", "ws");
|
|
350
390
|
url.searchParams.set("api_key", this.apiKey);
|
|
351
|
-
const emitter = new
|
|
391
|
+
const emitter = new import_emittery2.default();
|
|
352
392
|
this.socket = new import_partysocket.WebSocket(url.toString());
|
|
353
393
|
this.socket.onopen = () => {
|
|
354
|
-
this
|
|
394
|
+
__privateSet(this, _isConnected, true);
|
|
355
395
|
emitter.emit("open");
|
|
356
396
|
};
|
|
357
397
|
this.socket.onclose = () => {
|
|
358
|
-
this
|
|
398
|
+
__privateSet(this, _isConnected, false);
|
|
359
399
|
emitter.emit("close");
|
|
360
400
|
};
|
|
361
401
|
return new Promise(
|
|
@@ -402,3 +442,12 @@ var audio_default = class extends Client {
|
|
|
402
442
|
(_a = this.socket) == null ? void 0 : _a.close();
|
|
403
443
|
}
|
|
404
444
|
};
|
|
445
|
+
_isConnected = new WeakMap();
|
|
446
|
+
_sampleRate2 = new WeakMap();
|
|
447
|
+
_generateId = new WeakSet();
|
|
448
|
+
generateId_fn = function() {
|
|
449
|
+
return (0, import_human_id.humanId)({
|
|
450
|
+
separator: "-",
|
|
451
|
+
capitalize: false
|
|
452
|
+
});
|
|
453
|
+
};
|