@ai-sdk/cartesia 3.0.45 → 3.0.47
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/CHANGELOG.md +17 -0
- package/dist/index.d.ts +179 -169
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +876 -1025
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/cartesia-provider.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -1,1052 +1,903 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
NoSuchModelError
|
|
4
|
-
} from "@ai-sdk/provider";
|
|
5
|
-
import {
|
|
6
|
-
loadApiKey,
|
|
7
|
-
withUserAgentSuffix
|
|
8
|
-
} from "@ai-sdk/provider-utils";
|
|
9
|
-
|
|
10
|
-
// src/cartesia-transcription-model.ts
|
|
11
|
-
import {
|
|
12
|
-
InvalidArgumentError,
|
|
13
|
-
UnsupportedFunctionalityError
|
|
14
|
-
} from "@ai-sdk/provider";
|
|
15
|
-
import {
|
|
16
|
-
combineHeaders,
|
|
17
|
-
connectToWebSocket,
|
|
18
|
-
convertBase64ToUint8Array,
|
|
19
|
-
createJsonResponseHandler,
|
|
20
|
-
mediaTypeToExtension,
|
|
21
|
-
parseProviderOptions,
|
|
22
|
-
postFormDataToApi,
|
|
23
|
-
postJsonToApi,
|
|
24
|
-
safeParseJSON,
|
|
25
|
-
serializeModelOptions,
|
|
26
|
-
toWebSocketUrl,
|
|
27
|
-
waitForWebSocketBufferDrain,
|
|
28
|
-
WORKFLOW_SERIALIZE,
|
|
29
|
-
WORKFLOW_DESERIALIZE
|
|
30
|
-
} from "@ai-sdk/provider-utils";
|
|
31
|
-
import { z as z3 } from "zod/v4";
|
|
32
|
-
|
|
33
|
-
// src/cartesia-error.ts
|
|
1
|
+
import { InvalidArgumentError, NoSuchModelError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
|
|
2
|
+
import { WORKFLOW_DESERIALIZE, WORKFLOW_SERIALIZE, combineHeaders, connectToWebSocket, convertBase64ToUint8Array, createBinaryResponseHandler, createJsonErrorResponseHandler, createJsonResponseHandler, loadApiKey, mediaTypeToExtension, parseProviderOptions, postFormDataToApi, postJsonToApi, safeParseJSON, serializeModelOptions, toWebSocketUrl, waitForWebSocketBufferDrain, withUserAgentSuffix } from "@ai-sdk/provider-utils";
|
|
34
3
|
import { z } from "zod/v4";
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
4
|
+
//#region src/cartesia-error.ts
|
|
5
|
+
const cartesiaErrorDataSchema = z.object({
|
|
6
|
+
error_code: z.string().nullish(),
|
|
7
|
+
title: z.string(),
|
|
8
|
+
message: z.string(),
|
|
9
|
+
request_id: z.string(),
|
|
10
|
+
doc_url: z.string().optional()
|
|
42
11
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
12
|
+
const cartesiaFailedResponseHandler = createJsonErrorResponseHandler({
|
|
13
|
+
errorSchema: cartesiaErrorDataSchema,
|
|
14
|
+
errorToMessage: (data) => `${data.title}: ${data.message}`
|
|
46
15
|
});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/cartesia-transcription-model-options.ts
|
|
18
|
+
/** Raw audio encodings accepted by Ink 2 streaming transcription. */
|
|
19
|
+
const cartesiaStreamingEncodingSchema = z.enum([
|
|
20
|
+
"pcm_alaw",
|
|
21
|
+
"pcm_f16le",
|
|
22
|
+
"pcm_f32le",
|
|
23
|
+
"pcm_mulaw",
|
|
24
|
+
"pcm_s16le",
|
|
25
|
+
"pcm_s32le"
|
|
57
26
|
]);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
27
|
+
const cartesiaTranscriptionModelOptionsSchema = z.object({
|
|
28
|
+
/** The language of the audio (ISO 639-1 code). Defaults to English. */
|
|
29
|
+
language: z.string().nullish(),
|
|
30
|
+
/** The timestamp granularities to populate. Currently only `word` is supported. */
|
|
31
|
+
timestampGranularities: z.array(z.enum(["word"])).nullish(),
|
|
32
|
+
/** Options for realtime Ink 2 transcription over WebSocket. */
|
|
33
|
+
streaming: z.object({
|
|
34
|
+
/**
|
|
35
|
+
* Raw audio encoding sent to Ink 2. Defaults to the encoding inferred
|
|
36
|
+
* from `inputAudioFormat.type`.
|
|
37
|
+
*/
|
|
38
|
+
encoding: cartesiaStreamingEncodingSchema.optional(),
|
|
39
|
+
/**
|
|
40
|
+
* Use Cartesia's native turn detection endpoint. Defaults to true.
|
|
41
|
+
* Disable this to finalize the transcript only when the audio stream ends.
|
|
42
|
+
*/
|
|
43
|
+
turnDetection: z.boolean().optional()
|
|
44
|
+
}).optional()
|
|
76
45
|
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
var CartesiaTranscriptionModel = class
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const requestUrl = new URL(url);
|
|
232
|
-
requestUrl.searchParams.delete("access_token");
|
|
233
|
-
return {
|
|
234
|
-
request: { body: requestUrl.toString() },
|
|
235
|
-
response: {
|
|
236
|
-
timestamp: currentDate,
|
|
237
|
-
modelId: this.modelId
|
|
238
|
-
},
|
|
239
|
-
stream: createCartesiaStreamingTranscriptionStream({
|
|
240
|
-
webSocket: this.config.webSocket,
|
|
241
|
-
url,
|
|
242
|
-
warnings,
|
|
243
|
-
language: cartesiaOptions?.language ?? "en",
|
|
244
|
-
useTurnDetection,
|
|
245
|
-
audio: options.audio,
|
|
246
|
-
abortSignal: options.abortSignal,
|
|
247
|
-
includeRawChunks: options.includeRawChunks
|
|
248
|
-
})
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
async createStreamingAccessToken(options) {
|
|
252
|
-
const { value } = await postJsonToApi({
|
|
253
|
-
url: this.config.url({ path: "/access-token", modelId: this.modelId }),
|
|
254
|
-
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
255
|
-
body: { grants: { stt: true } },
|
|
256
|
-
failedResponseHandler: cartesiaFailedResponseHandler,
|
|
257
|
-
successfulResponseHandler: createJsonResponseHandler(
|
|
258
|
-
cartesiaAccessTokenResponseSchema
|
|
259
|
-
),
|
|
260
|
-
abortSignal: options.abortSignal,
|
|
261
|
-
fetch: this.config.fetch
|
|
262
|
-
});
|
|
263
|
-
return value.token;
|
|
264
|
-
}
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/cartesia-transcription-model.ts
|
|
48
|
+
var CartesiaTranscriptionModel = class CartesiaTranscriptionModel {
|
|
49
|
+
get provider() {
|
|
50
|
+
return this.config.provider;
|
|
51
|
+
}
|
|
52
|
+
static [WORKFLOW_SERIALIZE](model) {
|
|
53
|
+
return serializeModelOptions({
|
|
54
|
+
modelId: model.modelId,
|
|
55
|
+
config: model.config
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
static [WORKFLOW_DESERIALIZE](options) {
|
|
59
|
+
return new CartesiaTranscriptionModel(options.modelId, options.config);
|
|
60
|
+
}
|
|
61
|
+
constructor(modelId, config) {
|
|
62
|
+
this.modelId = modelId;
|
|
63
|
+
this.config = config;
|
|
64
|
+
this.specificationVersion = "v4";
|
|
65
|
+
}
|
|
66
|
+
async getArgs({ audio, mediaType, providerOptions }) {
|
|
67
|
+
const warnings = [];
|
|
68
|
+
const cartesiaOptions = await parseProviderOptions({
|
|
69
|
+
provider: "cartesia",
|
|
70
|
+
providerOptions,
|
|
71
|
+
schema: cartesiaTranscriptionModelOptionsSchema
|
|
72
|
+
});
|
|
73
|
+
if (cartesiaOptions?.streaming != null) warnings.push({
|
|
74
|
+
type: "unsupported",
|
|
75
|
+
feature: "providerOptions.cartesia.streaming",
|
|
76
|
+
details: "Cartesia batch transcription does not support streaming options."
|
|
77
|
+
});
|
|
78
|
+
const formData = new FormData();
|
|
79
|
+
const blob = audio instanceof Uint8Array ? new Blob([audio]) : new Blob([convertBase64ToUint8Array(audio)]);
|
|
80
|
+
const fileExtension = mediaTypeToExtension(mediaType);
|
|
81
|
+
formData.append("model", this.modelId);
|
|
82
|
+
formData.append("file", new File([blob], "audio", { type: mediaType }), `audio.${fileExtension}`);
|
|
83
|
+
if (cartesiaOptions) {
|
|
84
|
+
if (cartesiaOptions.language != null) formData.set("language", cartesiaOptions.language);
|
|
85
|
+
if (cartesiaOptions.timestampGranularities != null) for (const granularity of cartesiaOptions.timestampGranularities) formData.append("timestamp_granularities[]", granularity);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
formData,
|
|
89
|
+
warnings
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async doGenerate(options) {
|
|
93
|
+
if (isStreamingTranscriptionModelId(this.modelId)) throw new UnsupportedFunctionalityError({ functionality: `non-streaming transcription with ${this.modelId}` });
|
|
94
|
+
const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
|
|
95
|
+
const { formData, warnings } = await this.getArgs(options);
|
|
96
|
+
const { value: response, responseHeaders, rawValue: rawResponse } = await postFormDataToApi({
|
|
97
|
+
url: this.config.url({
|
|
98
|
+
path: "/stt",
|
|
99
|
+
modelId: this.modelId
|
|
100
|
+
}),
|
|
101
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
102
|
+
formData,
|
|
103
|
+
failedResponseHandler: cartesiaFailedResponseHandler,
|
|
104
|
+
successfulResponseHandler: createJsonResponseHandler(cartesiaTranscriptionResponseSchema),
|
|
105
|
+
abortSignal: options.abortSignal,
|
|
106
|
+
fetch: this.config.fetch
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
text: response.text,
|
|
110
|
+
segments: response.words?.map((word) => ({
|
|
111
|
+
text: word.word,
|
|
112
|
+
startSecond: word.start,
|
|
113
|
+
endSecond: word.end
|
|
114
|
+
})) ?? [],
|
|
115
|
+
language: response.language ?? void 0,
|
|
116
|
+
durationInSeconds: response.duration ?? void 0,
|
|
117
|
+
warnings,
|
|
118
|
+
response: {
|
|
119
|
+
timestamp: currentDate,
|
|
120
|
+
modelId: this.modelId,
|
|
121
|
+
headers: responseHeaders,
|
|
122
|
+
body: rawResponse
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
async doStream(options) {
|
|
127
|
+
if (!isStreamingTranscriptionModelId(this.modelId)) throw new UnsupportedFunctionalityError({ functionality: `streaming transcription with ${this.modelId}` });
|
|
128
|
+
const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
|
|
129
|
+
const warnings = [];
|
|
130
|
+
const cartesiaOptions = await parseProviderOptions({
|
|
131
|
+
provider: "cartesia",
|
|
132
|
+
providerOptions: options.providerOptions,
|
|
133
|
+
schema: cartesiaTranscriptionModelOptionsSchema
|
|
134
|
+
});
|
|
135
|
+
if (cartesiaOptions?.language != null && cartesiaOptions.language !== "en") throw new InvalidArgumentError({
|
|
136
|
+
argument: "providerOptions",
|
|
137
|
+
message: "Cartesia Ink 2 currently supports English only."
|
|
138
|
+
});
|
|
139
|
+
if (cartesiaOptions?.timestampGranularities != null) warnings.push({
|
|
140
|
+
type: "unsupported",
|
|
141
|
+
feature: "providerOptions.cartesia.timestampGranularities",
|
|
142
|
+
details: "Cartesia streaming transcription does not support timestamp granularities."
|
|
143
|
+
});
|
|
144
|
+
const inferredEncoding = cartesiaEncodingFromInputAudioFormat(options.inputAudioFormat.type);
|
|
145
|
+
const encoding = cartesiaOptions?.streaming?.encoding ?? inferredEncoding;
|
|
146
|
+
if (encoding !== inferredEncoding && !(inferredEncoding === "pcm_s16le" && LINEAR_PCM_STREAMING_ENCODINGS.has(encoding))) warnings.push({
|
|
147
|
+
type: "other",
|
|
148
|
+
message: `providerOptions.cartesia.streaming.encoding '${encoding}' contradicts inputAudioFormat.type '${options.inputAudioFormat.type}' (inferred '${inferredEncoding}'); sending '${encoding}'.`
|
|
149
|
+
});
|
|
150
|
+
const token = await this.createStreamingAccessToken(options);
|
|
151
|
+
const useTurnDetection = cartesiaOptions?.streaming?.turnDetection !== false;
|
|
152
|
+
const url = buildCartesiaStreamingTranscriptionUrl({
|
|
153
|
+
baseURL: this.config.url({
|
|
154
|
+
path: "/",
|
|
155
|
+
modelId: this.modelId
|
|
156
|
+
}),
|
|
157
|
+
version: this.config.version ?? "2026-03-01",
|
|
158
|
+
modelId: this.modelId,
|
|
159
|
+
encoding,
|
|
160
|
+
inputAudioFormat: options.inputAudioFormat,
|
|
161
|
+
providerOptions: cartesiaOptions,
|
|
162
|
+
token,
|
|
163
|
+
useTurnDetection
|
|
164
|
+
});
|
|
165
|
+
const requestUrl = new URL(url);
|
|
166
|
+
requestUrl.searchParams.delete("access_token");
|
|
167
|
+
return {
|
|
168
|
+
request: { body: requestUrl.toString() },
|
|
169
|
+
response: {
|
|
170
|
+
timestamp: currentDate,
|
|
171
|
+
modelId: this.modelId
|
|
172
|
+
},
|
|
173
|
+
stream: createCartesiaStreamingTranscriptionStream({
|
|
174
|
+
webSocket: this.config.webSocket,
|
|
175
|
+
url,
|
|
176
|
+
warnings,
|
|
177
|
+
language: cartesiaOptions?.language ?? "en",
|
|
178
|
+
useTurnDetection,
|
|
179
|
+
audio: options.audio,
|
|
180
|
+
abortSignal: options.abortSignal,
|
|
181
|
+
includeRawChunks: options.includeRawChunks
|
|
182
|
+
})
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
async createStreamingAccessToken(options) {
|
|
186
|
+
const { value } = await postJsonToApi({
|
|
187
|
+
url: this.config.url({
|
|
188
|
+
path: "/access-token",
|
|
189
|
+
modelId: this.modelId
|
|
190
|
+
}),
|
|
191
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
192
|
+
body: { grants: { stt: true } },
|
|
193
|
+
failedResponseHandler: cartesiaFailedResponseHandler,
|
|
194
|
+
successfulResponseHandler: createJsonResponseHandler(cartesiaAccessTokenResponseSchema),
|
|
195
|
+
abortSignal: options.abortSignal,
|
|
196
|
+
fetch: this.config.fetch
|
|
197
|
+
});
|
|
198
|
+
return value.token;
|
|
199
|
+
}
|
|
265
200
|
};
|
|
266
|
-
function createCartesiaStreamingTranscriptionStream({
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
case "done": {
|
|
397
|
-
finish();
|
|
398
|
-
break;
|
|
399
|
-
}
|
|
400
|
-
case "error": {
|
|
401
|
-
finishWithError(
|
|
402
|
-
new Error(
|
|
403
|
-
raw.message ?? raw.error_code ?? "Cartesia streaming transcription error"
|
|
404
|
-
)
|
|
405
|
-
);
|
|
406
|
-
break;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
},
|
|
410
|
-
onSocketError: () => {
|
|
411
|
-
finishWithError(new Error("Cartesia streaming transcription error"));
|
|
412
|
-
},
|
|
413
|
-
onClose: () => {
|
|
414
|
-
if (!finished) finish();
|
|
415
|
-
}
|
|
416
|
-
});
|
|
417
|
-
},
|
|
418
|
-
cancel: () => {
|
|
419
|
-
if (finished) return;
|
|
420
|
-
finished = true;
|
|
421
|
-
cleanup();
|
|
422
|
-
}
|
|
423
|
-
});
|
|
201
|
+
function createCartesiaStreamingTranscriptionStream({ webSocket, url, warnings, language, useTurnDetection, audio, abortSignal, includeRawChunks }) {
|
|
202
|
+
let finished = false;
|
|
203
|
+
let cleanup = () => {};
|
|
204
|
+
return new ReadableStream({
|
|
205
|
+
start: (controller) => {
|
|
206
|
+
const finalTexts = [];
|
|
207
|
+
let durationInSeconds = 0;
|
|
208
|
+
let audioReader;
|
|
209
|
+
let connection;
|
|
210
|
+
cleanup = (closeCode) => {
|
|
211
|
+
if (audioReader != null) audioReader.cancel().catch(() => {});
|
|
212
|
+
else audio.cancel().catch(() => {});
|
|
213
|
+
connection?.close(closeCode);
|
|
214
|
+
};
|
|
215
|
+
const finishWithError = (error) => {
|
|
216
|
+
if (finished) return;
|
|
217
|
+
finished = true;
|
|
218
|
+
cleanup();
|
|
219
|
+
controller.error(error);
|
|
220
|
+
};
|
|
221
|
+
const finish = () => {
|
|
222
|
+
if (finished) return;
|
|
223
|
+
finished = true;
|
|
224
|
+
controller.enqueue({
|
|
225
|
+
type: "finish",
|
|
226
|
+
text: finalTexts.join(useTurnDetection ? " " : ""),
|
|
227
|
+
segments: [],
|
|
228
|
+
language,
|
|
229
|
+
...durationInSeconds > 0 ? { durationInSeconds } : {}
|
|
230
|
+
});
|
|
231
|
+
controller.close();
|
|
232
|
+
cleanup(1e3);
|
|
233
|
+
};
|
|
234
|
+
const sendAudio = async (socket) => {
|
|
235
|
+
audioReader = audio.getReader();
|
|
236
|
+
try {
|
|
237
|
+
while (true) {
|
|
238
|
+
const { done, value } = await audioReader.read();
|
|
239
|
+
if (done || finished) break;
|
|
240
|
+
socket.send(value instanceof Uint8Array ? value : convertBase64ToUint8Array(value));
|
|
241
|
+
await waitForWebSocketBufferDrain(socket);
|
|
242
|
+
}
|
|
243
|
+
} finally {
|
|
244
|
+
audioReader.releaseLock();
|
|
245
|
+
audioReader = void 0;
|
|
246
|
+
}
|
|
247
|
+
if (!finished) socket.send(useTurnDetection ? JSON.stringify({ type: "close" }) : "finalize");
|
|
248
|
+
};
|
|
249
|
+
connection = connectToWebSocket({
|
|
250
|
+
url,
|
|
251
|
+
webSocket,
|
|
252
|
+
abortSignal,
|
|
253
|
+
onAbort: finishWithError,
|
|
254
|
+
onProcessingError: finishWithError,
|
|
255
|
+
onOpen: (socket) => {
|
|
256
|
+
controller.enqueue({
|
|
257
|
+
type: "stream-start",
|
|
258
|
+
warnings
|
|
259
|
+
});
|
|
260
|
+
sendAudio(socket).catch(finishWithError);
|
|
261
|
+
},
|
|
262
|
+
onMessageText: async (text) => {
|
|
263
|
+
const parsed = await safeParseJSON({ text });
|
|
264
|
+
if (!parsed.success) return;
|
|
265
|
+
const raw = parsed.value;
|
|
266
|
+
if (includeRawChunks) controller.enqueue({
|
|
267
|
+
type: "raw",
|
|
268
|
+
rawValue: raw
|
|
269
|
+
});
|
|
270
|
+
switch (raw.type) {
|
|
271
|
+
case "turn.update":
|
|
272
|
+
case "turn.eager_end":
|
|
273
|
+
controller.enqueue({
|
|
274
|
+
type: "transcript-partial",
|
|
275
|
+
id: raw.request_id,
|
|
276
|
+
text: raw.transcript ?? ""
|
|
277
|
+
});
|
|
278
|
+
break;
|
|
279
|
+
case "turn.end": {
|
|
280
|
+
const text = raw.transcript ?? "";
|
|
281
|
+
finalTexts.push(text);
|
|
282
|
+
controller.enqueue({
|
|
283
|
+
type: "transcript-final",
|
|
284
|
+
id: raw.request_id,
|
|
285
|
+
text
|
|
286
|
+
});
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
case "transcript": {
|
|
290
|
+
const transcript = raw.text ?? "";
|
|
291
|
+
if (raw.is_final === true) {
|
|
292
|
+
finalTexts.push(transcript);
|
|
293
|
+
durationInSeconds += raw.duration ?? 0;
|
|
294
|
+
controller.enqueue({
|
|
295
|
+
type: "transcript-final",
|
|
296
|
+
id: raw.request_id,
|
|
297
|
+
text: transcript
|
|
298
|
+
});
|
|
299
|
+
} else controller.enqueue({
|
|
300
|
+
type: "transcript-partial",
|
|
301
|
+
id: raw.request_id,
|
|
302
|
+
text: transcript,
|
|
303
|
+
...raw.duration != null ? { durationInSeconds: raw.duration } : {}
|
|
304
|
+
});
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
case "flush_done":
|
|
308
|
+
connection?.socket?.send("close");
|
|
309
|
+
break;
|
|
310
|
+
case "done":
|
|
311
|
+
finish();
|
|
312
|
+
break;
|
|
313
|
+
case "error": finishWithError(new Error(raw.message ?? raw.error_code ?? "Cartesia streaming transcription error"));
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
onSocketError: () => {
|
|
317
|
+
finishWithError(/* @__PURE__ */ new Error("Cartesia streaming transcription error"));
|
|
318
|
+
},
|
|
319
|
+
onClose: () => {
|
|
320
|
+
if (!finished) finish();
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
},
|
|
324
|
+
cancel: () => {
|
|
325
|
+
if (finished) return;
|
|
326
|
+
finished = true;
|
|
327
|
+
cleanup();
|
|
328
|
+
}
|
|
329
|
+
});
|
|
424
330
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
);
|
|
434
|
-
function buildCartesiaStreamingTranscriptionUrl({
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}) {
|
|
444
|
-
const url = toWebSocketUrl(
|
|
445
|
-
new URL(
|
|
446
|
-
useTurnDetection ? "/stt/turns/websocket" : "/stt/websocket",
|
|
447
|
-
baseURL
|
|
448
|
-
)
|
|
449
|
-
);
|
|
450
|
-
url.searchParams.set("model", modelId);
|
|
451
|
-
url.searchParams.set("encoding", encoding);
|
|
452
|
-
url.searchParams.set("sample_rate", String(inputAudioFormat.rate ?? 24e3));
|
|
453
|
-
url.searchParams.set("cartesia_version", version);
|
|
454
|
-
url.searchParams.set("access_token", token);
|
|
455
|
-
if (!useTurnDetection && providerOptions?.language != null) {
|
|
456
|
-
url.searchParams.set("language", providerOptions.language);
|
|
457
|
-
}
|
|
458
|
-
return url;
|
|
331
|
+
/** G.711 companding laws — the only non-linear members of the encoding enum. */
|
|
332
|
+
const G711_STREAMING_ENCODINGS = /* @__PURE__ */ new Set(["pcm_mulaw", "pcm_alaw"]);
|
|
333
|
+
/**
|
|
334
|
+
* Linear PCM encodings that legitimately widen generic `audio/pcm` input.
|
|
335
|
+
* Derived from the option enum so a future linear encoding added there is
|
|
336
|
+
* treated as widening-compatible by default; G.711 is a closed set (the
|
|
337
|
+
* standard defines exactly two companding laws), so it is the hardcoded half.
|
|
338
|
+
*/
|
|
339
|
+
const LINEAR_PCM_STREAMING_ENCODINGS = new Set(cartesiaStreamingEncodingSchema.options.filter((encoding) => !G711_STREAMING_ENCODINGS.has(encoding)));
|
|
340
|
+
function buildCartesiaStreamingTranscriptionUrl({ baseURL, version, modelId, encoding, inputAudioFormat, providerOptions, token, useTurnDetection }) {
|
|
341
|
+
const url = toWebSocketUrl(new URL(useTurnDetection ? "/stt/turns/websocket" : "/stt/websocket", baseURL));
|
|
342
|
+
url.searchParams.set("model", modelId);
|
|
343
|
+
url.searchParams.set("encoding", encoding);
|
|
344
|
+
url.searchParams.set("sample_rate", String(inputAudioFormat.rate ?? 24e3));
|
|
345
|
+
url.searchParams.set("cartesia_version", version);
|
|
346
|
+
url.searchParams.set("access_token", token);
|
|
347
|
+
if (!useTurnDetection && providerOptions?.language != null) url.searchParams.set("language", providerOptions.language);
|
|
348
|
+
return url;
|
|
459
349
|
}
|
|
460
350
|
function cartesiaEncodingFromInputAudioFormat(type) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
argument: "inputAudioFormat",
|
|
471
|
-
message: `Unsupported Cartesia streaming audio format: ${type}`
|
|
472
|
-
});
|
|
473
|
-
}
|
|
351
|
+
switch (type) {
|
|
352
|
+
case "audio/pcm": return "pcm_s16le";
|
|
353
|
+
case "audio/pcmu": return "pcm_mulaw";
|
|
354
|
+
case "audio/pcma": return "pcm_alaw";
|
|
355
|
+
default: throw new InvalidArgumentError({
|
|
356
|
+
argument: "inputAudioFormat",
|
|
357
|
+
message: `Unsupported Cartesia streaming audio format: ${type}`
|
|
358
|
+
});
|
|
359
|
+
}
|
|
474
360
|
}
|
|
475
361
|
function isStreamingTranscriptionModelId(modelId) {
|
|
476
|
-
|
|
362
|
+
return modelId === "ink-2" || modelId.startsWith("ink-2-");
|
|
477
363
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
})
|
|
488
|
-
).nullish()
|
|
489
|
-
});
|
|
490
|
-
var cartesiaAccessTokenResponseSchema = z3.object({
|
|
491
|
-
token: z3.string().min(1)
|
|
364
|
+
const cartesiaTranscriptionResponseSchema = z.object({
|
|
365
|
+
text: z.string(),
|
|
366
|
+
language: z.string().nullish(),
|
|
367
|
+
duration: z.number().nullish(),
|
|
368
|
+
words: z.array(z.object({
|
|
369
|
+
word: z.string(),
|
|
370
|
+
start: z.number(),
|
|
371
|
+
end: z.number()
|
|
372
|
+
})).nullish()
|
|
492
373
|
});
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
/** The language to generate speech in (ISO 639-1 code). */
|
|
532
|
-
language: z4.string().nullish()
|
|
374
|
+
const cartesiaAccessTokenResponseSchema = z.object({ token: z.string().min(1) });
|
|
375
|
+
//#endregion
|
|
376
|
+
//#region src/cartesia-speech-model-options.ts
|
|
377
|
+
const cartesiaSpeechModelOptionsSchema = z.object({
|
|
378
|
+
/** Container format for the output audio (raw, wav, mp3). */
|
|
379
|
+
container: z.enum([
|
|
380
|
+
"raw",
|
|
381
|
+
"wav",
|
|
382
|
+
"mp3"
|
|
383
|
+
]).nullish(),
|
|
384
|
+
/** Encoding type for the audio output (pcm_f32le, pcm_s16le, pcm_mulaw, pcm_alaw). */
|
|
385
|
+
encoding: z.enum([
|
|
386
|
+
"pcm_f32le",
|
|
387
|
+
"pcm_s16le",
|
|
388
|
+
"pcm_mulaw",
|
|
389
|
+
"pcm_alaw"
|
|
390
|
+
]).nullish(),
|
|
391
|
+
/** Sample rate for the output audio in Hz (e.g. 8000, 16000, 22050, 24000, 44100, 48000). */
|
|
392
|
+
sampleRate: z.union([
|
|
393
|
+
z.literal(8e3),
|
|
394
|
+
z.literal(16e3),
|
|
395
|
+
z.literal(22050),
|
|
396
|
+
z.literal(24e3),
|
|
397
|
+
z.literal(44100),
|
|
398
|
+
z.literal(48e3)
|
|
399
|
+
]).nullish(),
|
|
400
|
+
/** Bitrate for mp3 output in bits per second (e.g. 32000, 64000, 128000, 192000). */
|
|
401
|
+
bitRate: z.union([
|
|
402
|
+
z.literal(32e3),
|
|
403
|
+
z.literal(64e3),
|
|
404
|
+
z.literal(96e3),
|
|
405
|
+
z.literal(128e3),
|
|
406
|
+
z.literal(192e3)
|
|
407
|
+
]).nullish(),
|
|
408
|
+
/** Controls the speed of the generated speech. */
|
|
409
|
+
speed: z.number().min(.6).max(1.5).nullish(),
|
|
410
|
+
/** The language to generate speech in (ISO 639-1 code). */
|
|
411
|
+
language: z.string().nullish()
|
|
533
412
|
});
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
413
|
+
//#endregion
|
|
414
|
+
//#region src/cartesia-speech-model.ts
|
|
415
|
+
const DEFAULT_OUTPUT_FORMAT = {
|
|
416
|
+
container: "mp3",
|
|
417
|
+
sample_rate: 44100,
|
|
418
|
+
bit_rate: 128e3
|
|
540
419
|
};
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
420
|
+
const OUTPUT_FORMATS = {
|
|
421
|
+
alaw: {
|
|
422
|
+
container: "raw",
|
|
423
|
+
encoding: "pcm_alaw",
|
|
424
|
+
sample_rate: 8e3
|
|
425
|
+
},
|
|
426
|
+
mp3: DEFAULT_OUTPUT_FORMAT,
|
|
427
|
+
mulaw: {
|
|
428
|
+
container: "raw",
|
|
429
|
+
encoding: "pcm_mulaw",
|
|
430
|
+
sample_rate: 8e3
|
|
431
|
+
},
|
|
432
|
+
pcm: {
|
|
433
|
+
container: "raw",
|
|
434
|
+
encoding: "pcm_f32le",
|
|
435
|
+
sample_rate: 44100
|
|
436
|
+
},
|
|
437
|
+
raw: {
|
|
438
|
+
container: "raw",
|
|
439
|
+
encoding: "pcm_f32le",
|
|
440
|
+
sample_rate: 44100
|
|
441
|
+
},
|
|
442
|
+
wav: {
|
|
443
|
+
container: "wav",
|
|
444
|
+
encoding: "pcm_s16le",
|
|
445
|
+
sample_rate: 44100
|
|
446
|
+
}
|
|
548
447
|
};
|
|
549
|
-
|
|
448
|
+
const SAMPLE_RATES = [
|
|
449
|
+
8e3,
|
|
450
|
+
16e3,
|
|
451
|
+
22050,
|
|
452
|
+
24e3,
|
|
453
|
+
44100,
|
|
454
|
+
48e3
|
|
455
|
+
];
|
|
550
456
|
function isSampleRate(value) {
|
|
551
|
-
|
|
457
|
+
return SAMPLE_RATES.includes(value);
|
|
552
458
|
}
|
|
553
|
-
function resolveOutputFormat({
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
if (providerOptions?.bitRate != null) {
|
|
596
|
-
warnings.push({
|
|
597
|
-
type: "unsupported",
|
|
598
|
-
feature: "providerOptions.cartesia.bitRate",
|
|
599
|
-
details: "Cartesia raw and WAV output do not accept a bit rate. The bitRate option was ignored."
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
|
-
return {
|
|
603
|
-
container,
|
|
604
|
-
encoding: providerOptions?.encoding ?? (resolved.container === "mp3" ? container === "wav" ? "pcm_s16le" : "pcm_f32le" : resolved.encoding),
|
|
605
|
-
sample_rate: sampleRate
|
|
606
|
-
};
|
|
459
|
+
function resolveOutputFormat({ outputFormat, providerOptions, warnings }) {
|
|
460
|
+
const [formatName, sampleRateText, ...extraParts] = outputFormat.toLowerCase().split("_");
|
|
461
|
+
const mapped = OUTPUT_FORMATS[formatName];
|
|
462
|
+
let resolved = mapped ? { ...mapped } : { ...DEFAULT_OUTPUT_FORMAT };
|
|
463
|
+
if (!mapped) warnings.push({
|
|
464
|
+
type: "unsupported",
|
|
465
|
+
feature: "outputFormat",
|
|
466
|
+
details: `Unknown output format "${outputFormat}". Falling back to mp3. Use providerOptions.cartesia to configure container, encoding, and sampleRate directly.`
|
|
467
|
+
});
|
|
468
|
+
else if (sampleRateText != null) {
|
|
469
|
+
const parsedRate = Number(sampleRateText);
|
|
470
|
+
if (extraParts.length === 0 && Number.isInteger(parsedRate) && isSampleRate(parsedRate)) resolved.sample_rate = parsedRate;
|
|
471
|
+
else warnings.push({
|
|
472
|
+
type: "unsupported",
|
|
473
|
+
feature: "outputFormat",
|
|
474
|
+
details: `Unsupported Cartesia sample rate in output format "${outputFormat}". Using ${resolved.sample_rate} Hz instead.`
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
const container = providerOptions?.container ?? resolved.container;
|
|
478
|
+
const sampleRate = providerOptions?.sampleRate ?? resolved.sample_rate;
|
|
479
|
+
if (container === "mp3") {
|
|
480
|
+
if (providerOptions?.encoding != null) warnings.push({
|
|
481
|
+
type: "unsupported",
|
|
482
|
+
feature: "providerOptions.cartesia.encoding",
|
|
483
|
+
details: "Cartesia MP3 output does not accept an encoding. The encoding option was ignored."
|
|
484
|
+
});
|
|
485
|
+
return {
|
|
486
|
+
container,
|
|
487
|
+
sample_rate: sampleRate,
|
|
488
|
+
bit_rate: providerOptions?.bitRate ?? (resolved.container === "mp3" ? resolved.bit_rate : 128e3)
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
if (providerOptions?.bitRate != null) warnings.push({
|
|
492
|
+
type: "unsupported",
|
|
493
|
+
feature: "providerOptions.cartesia.bitRate",
|
|
494
|
+
details: "Cartesia raw and WAV output do not accept a bit rate. The bitRate option was ignored."
|
|
495
|
+
});
|
|
496
|
+
return {
|
|
497
|
+
container,
|
|
498
|
+
encoding: providerOptions?.encoding ?? (resolved.container === "mp3" ? container === "wav" ? "pcm_s16le" : "pcm_f32le" : resolved.encoding),
|
|
499
|
+
sample_rate: sampleRate
|
|
500
|
+
};
|
|
607
501
|
}
|
|
608
|
-
var CartesiaSpeechModel = class
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
url: this.config.url({
|
|
699
|
-
path: "/tts/bytes",
|
|
700
|
-
modelId: this.modelId
|
|
701
|
-
}),
|
|
702
|
-
headers: combineHeaders2(this.config.headers?.(), options.headers),
|
|
703
|
-
body: requestBody,
|
|
704
|
-
failedResponseHandler: cartesiaFailedResponseHandler,
|
|
705
|
-
successfulResponseHandler: createBinaryResponseHandler(),
|
|
706
|
-
abortSignal: options.abortSignal,
|
|
707
|
-
fetch: this.config.fetch
|
|
708
|
-
});
|
|
709
|
-
return {
|
|
710
|
-
audio,
|
|
711
|
-
warnings,
|
|
712
|
-
request: {
|
|
713
|
-
body: JSON.stringify(requestBody)
|
|
714
|
-
},
|
|
715
|
-
response: {
|
|
716
|
-
timestamp: currentDate,
|
|
717
|
-
modelId: this.modelId,
|
|
718
|
-
headers: responseHeaders,
|
|
719
|
-
body: rawResponse
|
|
720
|
-
}
|
|
721
|
-
};
|
|
722
|
-
}
|
|
502
|
+
var CartesiaSpeechModel = class CartesiaSpeechModel {
|
|
503
|
+
get provider() {
|
|
504
|
+
return this.config.provider;
|
|
505
|
+
}
|
|
506
|
+
static [WORKFLOW_SERIALIZE](model) {
|
|
507
|
+
return serializeModelOptions({
|
|
508
|
+
modelId: model.modelId,
|
|
509
|
+
config: model.config
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
static [WORKFLOW_DESERIALIZE](options) {
|
|
513
|
+
return new CartesiaSpeechModel(options.modelId, options.config);
|
|
514
|
+
}
|
|
515
|
+
constructor(modelId, config) {
|
|
516
|
+
this.modelId = modelId;
|
|
517
|
+
this.config = config;
|
|
518
|
+
this.specificationVersion = "v4";
|
|
519
|
+
}
|
|
520
|
+
async getArgs({ text, voice, outputFormat = "mp3", instructions, language, speed, providerOptions }) {
|
|
521
|
+
const warnings = [];
|
|
522
|
+
const cartesiaOptions = await parseProviderOptions({
|
|
523
|
+
provider: "cartesia",
|
|
524
|
+
providerOptions,
|
|
525
|
+
schema: cartesiaSpeechModelOptionsSchema
|
|
526
|
+
});
|
|
527
|
+
if (!voice) throw new Error("Cartesia speech models require a `voice` to be set.");
|
|
528
|
+
const outputFormatObject = resolveOutputFormat({
|
|
529
|
+
outputFormat,
|
|
530
|
+
providerOptions: cartesiaOptions,
|
|
531
|
+
warnings
|
|
532
|
+
});
|
|
533
|
+
const requestBody = {
|
|
534
|
+
model_id: this.modelId,
|
|
535
|
+
transcript: text,
|
|
536
|
+
voice: {
|
|
537
|
+
mode: "id",
|
|
538
|
+
id: voice
|
|
539
|
+
},
|
|
540
|
+
output_format: outputFormatObject
|
|
541
|
+
};
|
|
542
|
+
if (language) requestBody.language = language;
|
|
543
|
+
if (cartesiaOptions) {
|
|
544
|
+
if (cartesiaOptions.language != null) requestBody.language = cartesiaOptions.language;
|
|
545
|
+
}
|
|
546
|
+
const resolvedSpeed = cartesiaOptions?.speed ?? speed;
|
|
547
|
+
if (resolvedSpeed != null) {
|
|
548
|
+
if (resolvedSpeed >= .6 && resolvedSpeed <= 1.5) requestBody.generation_config = { speed: resolvedSpeed };
|
|
549
|
+
else warnings.push({
|
|
550
|
+
type: "unsupported",
|
|
551
|
+
feature: "speed",
|
|
552
|
+
details: "Cartesia speed must be between 0.6 and 1.5. The speed option was ignored."
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
if (instructions) warnings.push({
|
|
556
|
+
type: "unsupported",
|
|
557
|
+
feature: "instructions",
|
|
558
|
+
details: `Cartesia speech models do not support instructions. Instructions parameter was ignored.`
|
|
559
|
+
});
|
|
560
|
+
return {
|
|
561
|
+
requestBody,
|
|
562
|
+
warnings
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
async doGenerate(options) {
|
|
566
|
+
const currentDate = this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date();
|
|
567
|
+
const { requestBody, warnings } = await this.getArgs(options);
|
|
568
|
+
const { value: audio, responseHeaders, rawValue: rawResponse } = await postJsonToApi({
|
|
569
|
+
url: this.config.url({
|
|
570
|
+
path: "/tts/bytes",
|
|
571
|
+
modelId: this.modelId
|
|
572
|
+
}),
|
|
573
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
574
|
+
body: requestBody,
|
|
575
|
+
failedResponseHandler: cartesiaFailedResponseHandler,
|
|
576
|
+
successfulResponseHandler: createBinaryResponseHandler(),
|
|
577
|
+
abortSignal: options.abortSignal,
|
|
578
|
+
fetch: this.config.fetch
|
|
579
|
+
});
|
|
580
|
+
return {
|
|
581
|
+
audio,
|
|
582
|
+
warnings,
|
|
583
|
+
request: { body: JSON.stringify(requestBody) },
|
|
584
|
+
response: {
|
|
585
|
+
timestamp: currentDate,
|
|
586
|
+
modelId: this.modelId,
|
|
587
|
+
headers: responseHeaders,
|
|
588
|
+
body: rawResponse
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
}
|
|
723
592
|
};
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
593
|
+
//#endregion
|
|
594
|
+
//#region src/cartesia-realtime-model.ts
|
|
595
|
+
/**
|
|
596
|
+
* Realtime Ink model using Cartesia's STT WebSocket APIs.
|
|
597
|
+
*/
|
|
729
598
|
var CartesiaRealtimeModel = class {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
const created = {
|
|
930
|
-
type: "session-created",
|
|
931
|
-
sessionId,
|
|
932
|
-
raw
|
|
933
|
-
};
|
|
934
|
-
return Array.isArray(event) ? [created, ...event] : [created, event];
|
|
935
|
-
}
|
|
599
|
+
constructor(modelId, config) {
|
|
600
|
+
this.specificationVersion = "v4";
|
|
601
|
+
this.manualTranscript = {
|
|
602
|
+
duration: 0,
|
|
603
|
+
events: [],
|
|
604
|
+
text: ""
|
|
605
|
+
};
|
|
606
|
+
this.sessionCreated = false;
|
|
607
|
+
this.useTurnDetection = true;
|
|
608
|
+
this.modelId = modelId;
|
|
609
|
+
this.provider = config.provider;
|
|
610
|
+
this.config = config;
|
|
611
|
+
}
|
|
612
|
+
async doCreateClientSecret(options) {
|
|
613
|
+
const expiresIn = options.expiresAfterSeconds;
|
|
614
|
+
if (expiresIn != null && (!Number.isInteger(expiresIn) || expiresIn <= 0 || expiresIn > 3600)) throw new Error("Cartesia realtime client secrets must expire between 1 and 3600 seconds.");
|
|
615
|
+
const sessionConfig = options.sessionConfig;
|
|
616
|
+
const language = sessionConfig?.inputAudioTranscription?.language;
|
|
617
|
+
if (language != null && language !== "en") throw new Error("Cartesia Ink 2 currently supports English only.");
|
|
618
|
+
const response = await (this.config.fetch ?? fetch)(`${this.config.baseURL}/access-token`, {
|
|
619
|
+
method: "POST",
|
|
620
|
+
headers: {
|
|
621
|
+
...this.config.headers(),
|
|
622
|
+
"Content-Type": "application/json"
|
|
623
|
+
},
|
|
624
|
+
body: JSON.stringify({
|
|
625
|
+
grants: { stt: true },
|
|
626
|
+
...expiresIn != null ? { expires_in: expiresIn } : {}
|
|
627
|
+
})
|
|
628
|
+
});
|
|
629
|
+
if (!response.ok) {
|
|
630
|
+
const text = await response.text();
|
|
631
|
+
throw new Error(`Cartesia realtime client secret request failed: ${response.status} ${text}`);
|
|
632
|
+
}
|
|
633
|
+
const data = await response.json();
|
|
634
|
+
if (typeof data.token !== "string" || data.token.length === 0) throw new Error("Cartesia realtime client secret response did not include a token.");
|
|
635
|
+
const turnDetection = sessionConfig?.turnDetection;
|
|
636
|
+
const useTurnDetection = turnDetection === void 0 || turnDetection !== null && turnDetection.type !== "disabled";
|
|
637
|
+
const inputAudioFormat = sessionConfig?.inputAudioFormat;
|
|
638
|
+
const url = new URL(useTurnDetection ? `${this.config.baseURL}/stt/turns/websocket` : `${this.config.baseURL}/stt/websocket`);
|
|
639
|
+
url.protocol = url.protocol === "http:" ? "ws:" : "wss:";
|
|
640
|
+
url.searchParams.set("model", this.modelId);
|
|
641
|
+
url.searchParams.set("encoding", resolveCartesiaEncoding(inputAudioFormat?.type));
|
|
642
|
+
url.searchParams.set("sample_rate", String(inputAudioFormat?.rate ?? 24e3));
|
|
643
|
+
url.searchParams.set("cartesia_version", this.config.version);
|
|
644
|
+
if (!useTurnDetection && language != null) url.searchParams.set("language", language);
|
|
645
|
+
return {
|
|
646
|
+
token: data.token,
|
|
647
|
+
url: url.toString(),
|
|
648
|
+
...expiresIn != null ? { expiresAt: Math.floor((this.config._internal?.currentDate?.() ?? /* @__PURE__ */ new Date()).getTime() / 1e3) + expiresIn } : {}
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
getWebSocketConfig(options) {
|
|
652
|
+
const url = new URL(options.url);
|
|
653
|
+
this.useTurnDetection = url.pathname.includes("/stt/turns/websocket");
|
|
654
|
+
url.searchParams.set("access_token", options.token);
|
|
655
|
+
return { url: url.toString() };
|
|
656
|
+
}
|
|
657
|
+
parseServerEvent(raw) {
|
|
658
|
+
const event = raw;
|
|
659
|
+
const requestId = event.request_id ?? "cartesia-realtime";
|
|
660
|
+
let mapped;
|
|
661
|
+
switch (event.type) {
|
|
662
|
+
case "connected":
|
|
663
|
+
this.sessionCreated = true;
|
|
664
|
+
return {
|
|
665
|
+
type: "session-created",
|
|
666
|
+
sessionId: event.request_id,
|
|
667
|
+
raw
|
|
668
|
+
};
|
|
669
|
+
case "turn.start":
|
|
670
|
+
mapped = {
|
|
671
|
+
type: "speech-started",
|
|
672
|
+
itemId: requestId,
|
|
673
|
+
raw
|
|
674
|
+
};
|
|
675
|
+
break;
|
|
676
|
+
case "turn.resume":
|
|
677
|
+
mapped = [{
|
|
678
|
+
type: "speech-started",
|
|
679
|
+
itemId: requestId,
|
|
680
|
+
raw
|
|
681
|
+
}, {
|
|
682
|
+
type: "custom",
|
|
683
|
+
rawType: event.type,
|
|
684
|
+
raw
|
|
685
|
+
}];
|
|
686
|
+
break;
|
|
687
|
+
case "turn.end":
|
|
688
|
+
mapped = [{
|
|
689
|
+
type: "speech-stopped",
|
|
690
|
+
itemId: requestId,
|
|
691
|
+
raw
|
|
692
|
+
}, {
|
|
693
|
+
type: "input-transcription-completed",
|
|
694
|
+
itemId: requestId,
|
|
695
|
+
transcript: event.transcript ?? "",
|
|
696
|
+
raw
|
|
697
|
+
}];
|
|
698
|
+
break;
|
|
699
|
+
case "transcript":
|
|
700
|
+
if (event.is_final === true) {
|
|
701
|
+
this.manualTranscript.text += event.text ?? "";
|
|
702
|
+
this.manualTranscript.duration += event.duration ?? 0;
|
|
703
|
+
this.manualTranscript.events.push(event);
|
|
704
|
+
}
|
|
705
|
+
mapped = {
|
|
706
|
+
type: "custom",
|
|
707
|
+
rawType: event.type,
|
|
708
|
+
raw
|
|
709
|
+
};
|
|
710
|
+
break;
|
|
711
|
+
case "flush_done":
|
|
712
|
+
mapped = this.finishManualTranscript(event, raw);
|
|
713
|
+
break;
|
|
714
|
+
case "done":
|
|
715
|
+
if (this.manualTranscript.text.length > 0) {
|
|
716
|
+
const completed = this.finishManualTranscript(event, raw);
|
|
717
|
+
mapped = Array.isArray(completed) ? [...completed, {
|
|
718
|
+
type: "custom",
|
|
719
|
+
rawType: event.type,
|
|
720
|
+
raw
|
|
721
|
+
}] : [completed, {
|
|
722
|
+
type: "custom",
|
|
723
|
+
rawType: event.type,
|
|
724
|
+
raw
|
|
725
|
+
}];
|
|
726
|
+
} else mapped = {
|
|
727
|
+
type: "custom",
|
|
728
|
+
rawType: event.type,
|
|
729
|
+
raw
|
|
730
|
+
};
|
|
731
|
+
break;
|
|
732
|
+
case "error":
|
|
733
|
+
mapped = {
|
|
734
|
+
type: "error",
|
|
735
|
+
message: event.message ?? "Unknown Cartesia realtime error",
|
|
736
|
+
code: event.error_code,
|
|
737
|
+
raw
|
|
738
|
+
};
|
|
739
|
+
break;
|
|
740
|
+
default: mapped = {
|
|
741
|
+
type: "custom",
|
|
742
|
+
rawType: event.type,
|
|
743
|
+
raw
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
return this.withSessionCreated(mapped, requestId, raw);
|
|
747
|
+
}
|
|
748
|
+
serializeClientEvent(event) {
|
|
749
|
+
switch (event.type) {
|
|
750
|
+
case "session-update":
|
|
751
|
+
case "input-audio-clear":
|
|
752
|
+
case "response-create": return null;
|
|
753
|
+
case "input-audio-append": return convertBase64ToUint8Array(event.audio);
|
|
754
|
+
case "input-audio-commit": return this.useTurnDetection ? null : "finalize";
|
|
755
|
+
default: throw new Error(`Cartesia Ink 2 does not support realtime client event "${event.type}".`);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
buildSessionConfig(_config) {
|
|
759
|
+
return null;
|
|
760
|
+
}
|
|
761
|
+
finishManualTranscript(event, raw) {
|
|
762
|
+
const state = this.manualTranscript;
|
|
763
|
+
this.manualTranscript = {
|
|
764
|
+
duration: 0,
|
|
765
|
+
events: [],
|
|
766
|
+
text: ""
|
|
767
|
+
};
|
|
768
|
+
if (state.text.length === 0) return {
|
|
769
|
+
type: "custom",
|
|
770
|
+
rawType: event.type,
|
|
771
|
+
raw
|
|
772
|
+
};
|
|
773
|
+
return [{
|
|
774
|
+
type: "audio-committed",
|
|
775
|
+
itemId: event.request_id,
|
|
776
|
+
raw
|
|
777
|
+
}, {
|
|
778
|
+
type: "input-transcription-completed",
|
|
779
|
+
itemId: event.request_id ?? "cartesia-realtime",
|
|
780
|
+
transcript: state.text,
|
|
781
|
+
raw: {
|
|
782
|
+
event,
|
|
783
|
+
transcriptEvents: state.events,
|
|
784
|
+
duration: state.duration
|
|
785
|
+
}
|
|
786
|
+
}];
|
|
787
|
+
}
|
|
788
|
+
withSessionCreated(event, sessionId, raw) {
|
|
789
|
+
if (this.sessionCreated) return event;
|
|
790
|
+
this.sessionCreated = true;
|
|
791
|
+
const created = {
|
|
792
|
+
type: "session-created",
|
|
793
|
+
sessionId,
|
|
794
|
+
raw
|
|
795
|
+
};
|
|
796
|
+
return Array.isArray(event) ? [created, ...event] : [created, event];
|
|
797
|
+
}
|
|
936
798
|
};
|
|
937
799
|
function resolveCartesiaEncoding(type) {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
return "pcm_alaw";
|
|
946
|
-
default:
|
|
947
|
-
throw new Error(`Unsupported Cartesia realtime audio format: ${type}`);
|
|
948
|
-
}
|
|
800
|
+
switch (type) {
|
|
801
|
+
case void 0:
|
|
802
|
+
case "audio/pcm": return "pcm_s16le";
|
|
803
|
+
case "audio/pcmu": return "pcm_mulaw";
|
|
804
|
+
case "audio/pcma": return "pcm_alaw";
|
|
805
|
+
default: throw new Error(`Unsupported Cartesia realtime audio format: ${type}`);
|
|
806
|
+
}
|
|
949
807
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
808
|
+
//#endregion
|
|
809
|
+
//#region src/version.ts
|
|
810
|
+
const VERSION = "3.0.47";
|
|
811
|
+
//#endregion
|
|
812
|
+
//#region src/cartesia-provider.ts
|
|
813
|
+
/**
|
|
814
|
+
* The Cartesia API version sent with every request via the `Cartesia-Version`
|
|
815
|
+
* header. See https://docs.cartesia.ai/api-reference/api-versioning
|
|
816
|
+
*/
|
|
817
|
+
const CARTESIA_API_VERSION = "2026-03-01";
|
|
818
|
+
/**
|
|
819
|
+
* Create a Cartesia provider instance.
|
|
820
|
+
*/
|
|
956
821
|
function createCartesia(options = {}) {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
message: "Cartesia does not provide embedding models"
|
|
1031
|
-
});
|
|
1032
|
-
};
|
|
1033
|
-
provider.textEmbeddingModel = provider.embeddingModel;
|
|
1034
|
-
provider.imageModel = (modelId) => {
|
|
1035
|
-
throw new NoSuchModelError({
|
|
1036
|
-
modelId,
|
|
1037
|
-
modelType: "imageModel",
|
|
1038
|
-
message: "Cartesia does not provide image models"
|
|
1039
|
-
});
|
|
1040
|
-
};
|
|
1041
|
-
return provider;
|
|
822
|
+
const getHeaders = () => withUserAgentSuffix({
|
|
823
|
+
Authorization: `Bearer ${loadApiKey({
|
|
824
|
+
apiKey: options.apiKey,
|
|
825
|
+
environmentVariableName: "CARTESIA_API_KEY",
|
|
826
|
+
description: "Cartesia"
|
|
827
|
+
})}`,
|
|
828
|
+
"Cartesia-Version": options.version ?? CARTESIA_API_VERSION,
|
|
829
|
+
...options.headers
|
|
830
|
+
}, `ai-sdk-cartesia/${VERSION}`);
|
|
831
|
+
const createTranscriptionModel = (modelId) => new CartesiaTranscriptionModel(modelId, {
|
|
832
|
+
provider: `cartesia.transcription`,
|
|
833
|
+
url: ({ path }) => `https://api.cartesia.ai${path}`,
|
|
834
|
+
headers: getHeaders,
|
|
835
|
+
fetch: options.fetch,
|
|
836
|
+
version: options.version ?? CARTESIA_API_VERSION,
|
|
837
|
+
webSocket: options.webSocket
|
|
838
|
+
});
|
|
839
|
+
const createSpeechModel = (modelId) => new CartesiaSpeechModel(modelId, {
|
|
840
|
+
provider: `cartesia.speech`,
|
|
841
|
+
url: ({ path }) => `https://api.cartesia.ai${path}`,
|
|
842
|
+
headers: getHeaders,
|
|
843
|
+
fetch: options.fetch
|
|
844
|
+
});
|
|
845
|
+
const createRealtimeModel = (modelId) => new CartesiaRealtimeModel(modelId, {
|
|
846
|
+
provider: `cartesia.realtime`,
|
|
847
|
+
baseURL: "https://api.cartesia.ai",
|
|
848
|
+
version: options.version ?? CARTESIA_API_VERSION,
|
|
849
|
+
headers: getHeaders,
|
|
850
|
+
fetch: options.fetch
|
|
851
|
+
});
|
|
852
|
+
const experimentalRealtimeFactory = Object.assign((modelId) => createRealtimeModel(modelId), { getToken: async (tokenOptions) => {
|
|
853
|
+
const secret = await createRealtimeModel(tokenOptions.model).doCreateClientSecret({
|
|
854
|
+
sessionConfig: tokenOptions.sessionConfig,
|
|
855
|
+
expiresAfterSeconds: tokenOptions.expiresAfterSeconds
|
|
856
|
+
});
|
|
857
|
+
return {
|
|
858
|
+
token: secret.token,
|
|
859
|
+
url: secret.url,
|
|
860
|
+
expiresAt: secret.expiresAt
|
|
861
|
+
};
|
|
862
|
+
} });
|
|
863
|
+
const provider = function(modelId) {
|
|
864
|
+
return { speech: createSpeechModel(modelId) };
|
|
865
|
+
};
|
|
866
|
+
provider.specificationVersion = "v4";
|
|
867
|
+
provider.transcription = createTranscriptionModel;
|
|
868
|
+
provider.transcriptionModel = createTranscriptionModel;
|
|
869
|
+
provider.speech = createSpeechModel;
|
|
870
|
+
provider.speechModel = createSpeechModel;
|
|
871
|
+
provider.experimental_realtime = experimentalRealtimeFactory;
|
|
872
|
+
provider.languageModel = (modelId) => {
|
|
873
|
+
throw new NoSuchModelError({
|
|
874
|
+
modelId,
|
|
875
|
+
modelType: "languageModel",
|
|
876
|
+
message: "Cartesia does not provide language models"
|
|
877
|
+
});
|
|
878
|
+
};
|
|
879
|
+
provider.embeddingModel = (modelId) => {
|
|
880
|
+
throw new NoSuchModelError({
|
|
881
|
+
modelId,
|
|
882
|
+
modelType: "embeddingModel",
|
|
883
|
+
message: "Cartesia does not provide embedding models"
|
|
884
|
+
});
|
|
885
|
+
};
|
|
886
|
+
provider.textEmbeddingModel = provider.embeddingModel;
|
|
887
|
+
provider.imageModel = (modelId) => {
|
|
888
|
+
throw new NoSuchModelError({
|
|
889
|
+
modelId,
|
|
890
|
+
modelType: "imageModel",
|
|
891
|
+
message: "Cartesia does not provide image models"
|
|
892
|
+
});
|
|
893
|
+
};
|
|
894
|
+
return provider;
|
|
1042
895
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
createCartesia
|
|
1051
|
-
};
|
|
896
|
+
/**
|
|
897
|
+
* Default Cartesia provider instance.
|
|
898
|
+
*/
|
|
899
|
+
const cartesia = createCartesia();
|
|
900
|
+
//#endregion
|
|
901
|
+
export { CartesiaRealtimeModel, CartesiaSpeechModel, CartesiaTranscriptionModel, VERSION, cartesia, createCartesia };
|
|
902
|
+
|
|
1052
903
|
//# sourceMappingURL=index.js.map
|