@cartesia/cartesia-js 0.0.3 → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +68 -38
- package/CHANGELOG.md +12 -0
- package/README.md +123 -16
- package/dist/chunk-3FL2SNIR.js +17 -0
- package/dist/chunk-3GBZUGUD.js +17 -0
- package/dist/chunk-4RMSIQLG.js +25 -0
- package/dist/chunk-BCQ63627.js +32 -0
- package/dist/chunk-JOHSCOLW.js +106 -0
- package/dist/chunk-LYPTISWL.js +75 -0
- package/dist/chunk-NDNN326Q.js +207 -0
- package/dist/chunk-WBK6LLXX.js +58 -0
- package/dist/chunk-WE63M7PJ.js +119 -0
- package/dist/{chunk-HNLIBHEN.mjs → chunk-WIFMLPT5.js} +31 -16
- package/dist/chunk-X7SJMF2R.js +22 -0
- package/dist/index.cjs +652 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +20 -0
- package/dist/lib/client.cjs +89 -0
- package/dist/lib/client.d.cts +11 -0
- package/dist/lib/client.d.ts +2 -0
- package/dist/lib/client.js +7 -42
- package/dist/lib/constants.cjs +42 -0
- package/dist/lib/constants.d.cts +4 -0
- package/dist/lib/constants.d.ts +2 -3
- package/dist/lib/constants.js +8 -37
- package/dist/lib/index.cjs +531 -0
- package/dist/lib/index.d.cts +16 -0
- package/dist/lib/index.d.ts +6 -2
- package/dist/lib/index.js +13 -409
- package/dist/react/index.cjs +846 -0
- package/dist/react/index.d.cts +33 -0
- package/dist/react/index.d.ts +20 -13
- package/dist/react/index.js +161 -501
- package/dist/react/utils.cjs +57 -0
- package/dist/react/utils.d.cts +7 -0
- package/dist/react/utils.d.ts +7 -0
- package/dist/react/utils.js +7 -0
- package/dist/tts/index.cjs +470 -0
- package/dist/tts/index.d.cts +17 -0
- package/dist/tts/index.d.ts +17 -0
- package/dist/tts/index.js +12 -0
- package/dist/tts/player.cjs +198 -0
- package/dist/tts/player.d.cts +43 -0
- package/dist/tts/player.d.ts +43 -0
- package/dist/tts/player.js +8 -0
- package/dist/tts/source.cjs +167 -0
- package/dist/tts/source.d.cts +53 -0
- package/dist/tts/source.d.ts +53 -0
- package/dist/tts/source.js +7 -0
- package/dist/{audio/utils.js → tts/utils.cjs} +13 -54
- package/dist/tts/utils.d.cts +67 -0
- package/dist/tts/utils.d.ts +67 -0
- package/dist/{audio/utils.mjs → tts/utils.js} +2 -6
- package/dist/tts/websocket.cjs +453 -0
- package/dist/tts/websocket.d.cts +53 -0
- package/dist/tts/websocket.d.ts +53 -0
- package/dist/tts/websocket.js +11 -0
- package/dist/types/index.cjs +18 -0
- package/dist/types/index.d.cts +55 -0
- package/dist/types/index.d.ts +50 -1
- package/dist/types/index.js +1 -18
- package/dist/voices/index.cjs +155 -0
- package/dist/voices/index.d.cts +12 -0
- package/dist/voices/index.d.ts +12 -0
- package/dist/voices/index.js +9 -0
- package/package.json +11 -7
- package/src/index.ts +4 -0
- package/src/lib/client.ts +14 -1
- package/src/lib/constants.ts +13 -3
- package/src/lib/index.ts +6 -3
- package/src/react/index.ts +167 -75
- package/src/react/utils.ts +11 -0
- package/src/tts/index.ts +17 -0
- package/src/tts/player.ts +109 -0
- package/src/tts/source.ts +98 -0
- package/src/{audio → tts}/utils.ts +19 -97
- package/src/tts/websocket.ts +210 -0
- package/src/types/index.ts +63 -0
- package/src/voices/index.ts +47 -0
- package/dist/audio/index.d.mts +0 -5
- package/dist/audio/index.d.ts +0 -5
- package/dist/audio/index.js +0 -396
- package/dist/audio/index.mjs +0 -9
- package/dist/audio/utils.d.mts +0 -5
- package/dist/audio/utils.d.ts +0 -5
- package/dist/chunk-3CYTAFLF.mjs +0 -262
- package/dist/chunk-FRIBQZPN.mjs +0 -113
- package/dist/chunk-XSFPHPPG.mjs +0 -18
- package/dist/index-DSBmfK9-.d.mts +0 -158
- package/dist/index-qwAyxV5I.d.ts +0 -158
- package/dist/lib/client.d.mts +0 -9
- package/dist/lib/client.mjs +0 -7
- package/dist/lib/constants.d.mts +0 -5
- package/dist/lib/constants.mjs +0 -10
- package/dist/lib/index.d.mts +0 -12
- package/dist/lib/index.mjs +0 -19
- package/dist/react/index.d.mts +0 -26
- package/dist/react/index.mjs +0 -130
- package/dist/types/index.d.mts +0 -6
- package/index.ts +0 -3
- package/src/audio/index.ts +0 -282
- /package/dist/{types/index.mjs → chunk-FXPGR372.js} +0 -0
package/src/audio/index.ts
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
import Emittery from "emittery";
|
|
2
|
-
import { humanId } from "human-id";
|
|
3
|
-
import { WebSocket } from "partysocket";
|
|
4
|
-
import { Client } from "../lib/client";
|
|
5
|
-
import { SAMPLE_RATE, constructWebsocketUrl } from "../lib/constants";
|
|
6
|
-
import {
|
|
7
|
-
type EmitteryCallbacks,
|
|
8
|
-
type Sentinel,
|
|
9
|
-
createMessageHandlerForContextId,
|
|
10
|
-
getBufferDuration,
|
|
11
|
-
getEmitteryCallbacks,
|
|
12
|
-
isComplete,
|
|
13
|
-
isSentinel,
|
|
14
|
-
playAudioBuffer,
|
|
15
|
-
} from "./utils";
|
|
16
|
-
|
|
17
|
-
export type Chunk = string | Sentinel;
|
|
18
|
-
export type StreamEventData = {
|
|
19
|
-
chunk: {
|
|
20
|
-
chunk: Chunk;
|
|
21
|
-
chunks: Chunk[];
|
|
22
|
-
};
|
|
23
|
-
streamed: {
|
|
24
|
-
chunks: Chunk[];
|
|
25
|
-
};
|
|
26
|
-
message: unknown;
|
|
27
|
-
};
|
|
28
|
-
export type ConnectionEventData = {
|
|
29
|
-
open: never;
|
|
30
|
-
close: never;
|
|
31
|
-
};
|
|
32
|
-
export type StreamRequest = {
|
|
33
|
-
inputs: object;
|
|
34
|
-
options: {
|
|
35
|
-
timeout?: number;
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export default class extends Client {
|
|
40
|
-
socket?: WebSocket;
|
|
41
|
-
isConnected = false;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Stream audio from a model.
|
|
45
|
-
*
|
|
46
|
-
* @param inputs - Stream options. Includes a `model` key and some `parameters`, which
|
|
47
|
-
* are model-specific and can be found in the model's documentation.
|
|
48
|
-
* @param options - Options for the stream.
|
|
49
|
-
* @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
|
|
50
|
-
* If `0`, the stream will not time out.
|
|
51
|
-
* @returns An object with a method `play` of type `(bufferDuration: number) => Promise<void>`
|
|
52
|
-
* that plays the audio as it arrives, with `bufferDuration` seconds of audio buffered before
|
|
53
|
-
* starting playback.
|
|
54
|
-
*/
|
|
55
|
-
stream(
|
|
56
|
-
inputs: StreamRequest["inputs"],
|
|
57
|
-
{ timeout = 0 }: StreamRequest["options"] = {},
|
|
58
|
-
) {
|
|
59
|
-
if (!this.isConnected) {
|
|
60
|
-
throw new Error("Not connected to WebSocket. Call .connect() first.");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Send audio request.
|
|
64
|
-
const contextId = this.generateId();
|
|
65
|
-
this.socket?.send(
|
|
66
|
-
JSON.stringify({
|
|
67
|
-
data: inputs,
|
|
68
|
-
context_id: contextId,
|
|
69
|
-
}),
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
// Used to signal that the stream is complete, either because the
|
|
73
|
-
// WebSocket has closed, or because the stream has finished.
|
|
74
|
-
const streamCompleteController = new AbortController();
|
|
75
|
-
// Set a timeout.
|
|
76
|
-
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
77
|
-
if (timeout > 0) {
|
|
78
|
-
timeoutId = setTimeout(streamCompleteController.abort, timeout);
|
|
79
|
-
}
|
|
80
|
-
// Array of base64-encoded audio chunks, representing directly sampled
|
|
81
|
-
// audio data, i.e. floats in the range [-1, 1].
|
|
82
|
-
const chunks: Chunk[] = [];
|
|
83
|
-
// Used to dispatch events.
|
|
84
|
-
const emitter = new Emittery<StreamEventData>();
|
|
85
|
-
const handleMessage = createMessageHandlerForContextId(
|
|
86
|
-
contextId,
|
|
87
|
-
async ({ chunk, message }) => {
|
|
88
|
-
chunks.push(chunk);
|
|
89
|
-
await emitter.emit("chunk", {
|
|
90
|
-
chunk,
|
|
91
|
-
chunks,
|
|
92
|
-
});
|
|
93
|
-
await emitter.emit("message", message);
|
|
94
|
-
if (isSentinel(chunk)) {
|
|
95
|
-
await emitter.emit("streamed", {
|
|
96
|
-
chunks,
|
|
97
|
-
});
|
|
98
|
-
streamCompleteController.abort();
|
|
99
|
-
} else if (timeoutId) {
|
|
100
|
-
clearTimeout(timeoutId);
|
|
101
|
-
timeoutId = setTimeout(streamCompleteController.abort, timeout);
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
);
|
|
105
|
-
this.socket?.addEventListener("message", handleMessage, {
|
|
106
|
-
signal: streamCompleteController.signal,
|
|
107
|
-
});
|
|
108
|
-
this.socket?.addEventListener(
|
|
109
|
-
"close",
|
|
110
|
-
() => {
|
|
111
|
-
streamCompleteController.abort();
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
once: true,
|
|
115
|
-
},
|
|
116
|
-
);
|
|
117
|
-
this.socket?.addEventListener(
|
|
118
|
-
"error",
|
|
119
|
-
() => {
|
|
120
|
-
streamCompleteController.abort();
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
once: true,
|
|
124
|
-
},
|
|
125
|
-
);
|
|
126
|
-
streamCompleteController.signal.addEventListener("abort", () => {
|
|
127
|
-
if (timeoutId) {
|
|
128
|
-
clearTimeout(timeoutId);
|
|
129
|
-
}
|
|
130
|
-
emitter.clearListeners();
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
const play = async ({ bufferDuration }: { bufferDuration: number }) => {
|
|
134
|
-
const context = new AudioContext({
|
|
135
|
-
sampleRate: SAMPLE_RATE,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
let startNextPlaybackAt = 0;
|
|
139
|
-
const playLatestChunk = (chunk: Chunk) => {
|
|
140
|
-
if (isSentinel(chunk)) {
|
|
141
|
-
return true; // Indicates that playback has finished.
|
|
142
|
-
}
|
|
143
|
-
startNextPlaybackAt =
|
|
144
|
-
playAudioBuffer([chunk], context, startNextPlaybackAt) +
|
|
145
|
-
Math.max(context.currentTime, startNextPlaybackAt);
|
|
146
|
-
return false; // Indicates that playback has not finished.
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const playChunks = (chunks: Chunk[]) => {
|
|
150
|
-
startNextPlaybackAt += playAudioBuffer(
|
|
151
|
-
chunks,
|
|
152
|
-
context,
|
|
153
|
-
startNextPlaybackAt,
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
if (isComplete(chunks)) {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// tryStart tries to start playback if the buffer duration is
|
|
162
|
-
// already satisfied or if all the chunks have arrived. If it is
|
|
163
|
-
// not, it returns false, indicating that the caller should call
|
|
164
|
-
// it again when more chunks arrive.
|
|
165
|
-
const tryStart = async (chunks: Chunk[]) => {
|
|
166
|
-
startNextPlaybackAt = context.currentTime;
|
|
167
|
-
|
|
168
|
-
if (isComplete(chunks) || streamCompleteController.signal.aborted) {
|
|
169
|
-
playChunks(chunks);
|
|
170
|
-
return true; // Done playing.
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (getBufferDuration(chunks) > bufferDuration) {
|
|
174
|
-
// Play the initial chunks that we already have.
|
|
175
|
-
playChunks(chunks);
|
|
176
|
-
// If the stream is not complete, play new chunks as they
|
|
177
|
-
// arrive.
|
|
178
|
-
for await (const { chunk } of emitter.events("chunk")) {
|
|
179
|
-
if (playLatestChunk(chunk)) {
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return true; // Done playing.
|
|
184
|
-
}
|
|
185
|
-
return false; // Need to buffer more audio.
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
if (!(await tryStart(chunks))) {
|
|
189
|
-
for await (const { chunks } of emitter.events("chunk")) {
|
|
190
|
-
if (await tryStart(chunks)) {
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
play,
|
|
199
|
-
...getEmitteryCallbacks(emitter),
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Generate a unique ID suitable for a streaming context.
|
|
205
|
-
*
|
|
206
|
-
* Not suitable for security purposes or as a primary key, since
|
|
207
|
-
* it lacks the amount of entropy required for those use cases.
|
|
208
|
-
*
|
|
209
|
-
* @returns A unique ID.
|
|
210
|
-
*/
|
|
211
|
-
generateId() {
|
|
212
|
-
return humanId({
|
|
213
|
-
separator: "-",
|
|
214
|
-
capitalize: false,
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Authenticate and connect to a Cartesia streaming WebSocket.
|
|
220
|
-
*
|
|
221
|
-
* @returns A promise that resolves when the WebSocket is connected.
|
|
222
|
-
* @throws {Error} If the WebSocket fails to connect.
|
|
223
|
-
*/
|
|
224
|
-
connect() {
|
|
225
|
-
const url = constructWebsocketUrl(this.baseUrl);
|
|
226
|
-
url.searchParams.set("api_key", this.apiKey);
|
|
227
|
-
const emitter = new Emittery<ConnectionEventData>();
|
|
228
|
-
this.socket = new WebSocket(url.toString());
|
|
229
|
-
this.socket.onopen = () => {
|
|
230
|
-
this.isConnected = true;
|
|
231
|
-
emitter.emit("open");
|
|
232
|
-
};
|
|
233
|
-
this.socket.onclose = () => {
|
|
234
|
-
this.isConnected = false;
|
|
235
|
-
emitter.emit("close");
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
return new Promise<EmitteryCallbacks<ConnectionEventData>>(
|
|
239
|
-
(resolve, reject) => {
|
|
240
|
-
this.socket?.addEventListener(
|
|
241
|
-
"open",
|
|
242
|
-
() => {
|
|
243
|
-
resolve(getEmitteryCallbacks(emitter));
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
once: true,
|
|
247
|
-
},
|
|
248
|
-
);
|
|
249
|
-
|
|
250
|
-
const aborter = new AbortController();
|
|
251
|
-
this.socket?.addEventListener(
|
|
252
|
-
"error",
|
|
253
|
-
() => {
|
|
254
|
-
aborter.abort();
|
|
255
|
-
reject(new Error("WebSocket failed to connect."));
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
signal: aborter.signal,
|
|
259
|
-
},
|
|
260
|
-
);
|
|
261
|
-
|
|
262
|
-
this.socket?.addEventListener(
|
|
263
|
-
"close",
|
|
264
|
-
() => {
|
|
265
|
-
aborter.abort();
|
|
266
|
-
reject(new Error("WebSocket closed before it could connect."));
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
signal: aborter.signal,
|
|
270
|
-
},
|
|
271
|
-
);
|
|
272
|
-
},
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Disconnect from the Cartesia streaming WebSocket.
|
|
278
|
-
*/
|
|
279
|
-
disconnect() {
|
|
280
|
-
this.socket?.close();
|
|
281
|
-
}
|
|
282
|
-
}
|
|
File without changes
|