@cartesia/cartesia-js 3.0.0-b5 → 3.0.0-b7

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/backcompat/errors.d.mts +16 -0
  3. package/backcompat/errors.d.mts.map +1 -0
  4. package/backcompat/errors.d.ts +16 -0
  5. package/backcompat/errors.d.ts.map +1 -0
  6. package/backcompat/errors.js +46 -0
  7. package/backcompat/errors.js.map +1 -0
  8. package/backcompat/errors.mjs +40 -0
  9. package/backcompat/errors.mjs.map +1 -0
  10. package/backcompat/index.d.mts +17 -31
  11. package/backcompat/index.d.mts.map +1 -1
  12. package/backcompat/index.d.ts +17 -31
  13. package/backcompat/index.d.ts.map +1 -1
  14. package/backcompat/index.js +26 -254
  15. package/backcompat/index.js.map +1 -1
  16. package/backcompat/index.mjs +25 -253
  17. package/backcompat/index.mjs.map +1 -1
  18. package/backcompat/tts-wrapper.d.mts +69 -0
  19. package/backcompat/tts-wrapper.d.mts.map +1 -0
  20. package/backcompat/tts-wrapper.d.ts +69 -0
  21. package/backcompat/tts-wrapper.d.ts.map +1 -0
  22. package/backcompat/tts-wrapper.js +264 -0
  23. package/backcompat/tts-wrapper.js.map +1 -0
  24. package/backcompat/tts-wrapper.mjs +258 -0
  25. package/backcompat/tts-wrapper.mjs.map +1 -0
  26. package/backcompat/types.d.mts +18 -0
  27. package/backcompat/types.d.mts.map +1 -0
  28. package/backcompat/types.d.ts +18 -0
  29. package/backcompat/types.d.ts.map +1 -0
  30. package/backcompat/types.js +3 -0
  31. package/backcompat/types.js.map +1 -0
  32. package/backcompat/types.mjs +2 -0
  33. package/backcompat/types.mjs.map +1 -0
  34. package/backcompat/voice-changer-wrapper.d.mts +19 -0
  35. package/backcompat/voice-changer-wrapper.d.mts.map +1 -0
  36. package/backcompat/voice-changer-wrapper.d.ts +19 -0
  37. package/backcompat/voice-changer-wrapper.d.ts.map +1 -0
  38. package/backcompat/voice-changer-wrapper.js +49 -0
  39. package/backcompat/voice-changer-wrapper.js.map +1 -0
  40. package/backcompat/voice-changer-wrapper.mjs +45 -0
  41. package/backcompat/voice-changer-wrapper.mjs.map +1 -0
  42. package/backcompat/voices-wrapper.d.mts +36 -0
  43. package/backcompat/voices-wrapper.d.mts.map +1 -0
  44. package/backcompat/voices-wrapper.d.ts +36 -0
  45. package/backcompat/voices-wrapper.d.ts.map +1 -0
  46. package/backcompat/voices-wrapper.js +82 -0
  47. package/backcompat/voices-wrapper.js.map +1 -0
  48. package/backcompat/voices-wrapper.mjs +78 -0
  49. package/backcompat/voices-wrapper.mjs.map +1 -0
  50. package/index.d.mts +1 -1
  51. package/index.d.mts.map +1 -1
  52. package/index.d.ts +1 -1
  53. package/index.d.ts.map +1 -1
  54. package/index.js +3 -3
  55. package/index.js.map +1 -1
  56. package/index.mjs +1 -1
  57. package/index.mjs.map +1 -1
  58. package/package.json +1 -1
  59. package/src/backcompat/errors.ts +52 -0
  60. package/src/backcompat/index.ts +31 -291
  61. package/src/backcompat/tts-wrapper.ts +328 -0
  62. package/src/backcompat/types.ts +19 -0
  63. package/src/backcompat/voice-changer-wrapper.ts +70 -0
  64. package/src/backcompat/voices-wrapper.ts +163 -0
  65. package/src/index.ts +1 -1
  66. package/src/version.ts +1 -1
  67. package/version.d.mts +1 -1
  68. package/version.d.ts +1 -1
  69. package/version.js +1 -1
  70. package/version.mjs +1 -1
@@ -1,302 +1,42 @@
1
- import WebSocket from "ws";
2
- import { Cartesia } from "../client";
3
-
4
- class AudioSource {
5
- private buffers: Buffer[] = [];
6
- private waiter: ((val?: any) => void) | null = null;
7
- public isDone = false;
8
-
9
- push(data: Buffer) {
10
- this.buffers.push(data);
11
- if (this.waiter) {
12
- this.waiter();
13
- this.waiter = null;
14
- }
15
- }
16
-
17
- markDone() {
18
- this.isDone = true;
19
- if (this.waiter) {
20
- this.waiter();
21
- this.waiter = null;
22
- }
23
- }
24
-
25
- async read(outBuffer: Float32Array): Promise<number> {
26
- if (this.buffers.length === 0 && !this.isDone) {
27
- await new Promise<void>((resolve) => { this.waiter = resolve; });
28
- }
29
-
30
- if (this.buffers.length === 0 && this.isDone) {
31
- return 0;
32
- }
33
-
34
- let totalFloatsRead = 0;
35
- let outOffset = 0;
36
- const maxFloats = outBuffer.length;
37
-
38
- while (this.buffers.length > 0 && totalFloatsRead < maxFloats) {
39
- const buf = this.buffers[0] as Buffer; // ts not smart enough to check loop condition
40
- const floatsInBuf = buf.length / 4;
41
- const floatsNeeded = maxFloats - totalFloatsRead;
42
-
43
- const floatsToCopy = Math.min(floatsInBuf, floatsNeeded);
44
- const bytesToCopy = floatsToCopy * 4;
45
-
46
- // Copy to outBuffer.
47
- // Create a view on the buffer to read floats.
48
-
49
- // We need to ensure byteOffset is a multiple of 4.
50
- // If not, we must copy the buffer to a new one.
51
- let srcFloats: Float32Array;
52
- if (buf.byteOffset % 4 === 0) {
53
- srcFloats = new Float32Array(buf.buffer, buf.byteOffset, floatsInBuf);
54
- } else {
55
- const alignedBuf = new Uint8Array(buf);
56
- srcFloats = new Float32Array(alignedBuf.buffer, alignedBuf.byteOffset, floatsInBuf);
57
- }
58
-
59
- outBuffer.set(srcFloats.subarray(0, floatsToCopy), outOffset);
60
-
61
- totalFloatsRead += floatsToCopy;
62
- outOffset += floatsToCopy;
63
-
64
- if (floatsToCopy < floatsInBuf) {
65
- // We didn't use the whole buffer. Update it.
66
- this.buffers[0] = buf.subarray(bytesToCopy);
67
- } else {
68
- // We used the whole buffer. Remove it.
69
- this.buffers.shift();
70
- }
71
- }
72
-
73
- return totalFloatsRead;
74
- }
75
- }
76
-
77
- class WebSocketWrapper {
78
- private client: Cartesia;
79
- private config: any;
80
- private socket: WebSocket | null = null;
81
- private sources: Map<string, AudioSource> = new Map();
82
- // Fallback source for messages without context_id or if we just want to capture everything (legacy behavior?)
83
- // The original test didn't use context_id explicitly in send() but expected a response source.
84
- // We'll map context_id to source.
85
- private defaultSource: AudioSource | null = null;
86
-
87
- constructor(client: Cartesia, config: any) {
88
- this.client = client;
89
- this.config = config;
90
- }
91
-
92
- async connect() {
93
- const baseURL = this.client.baseURL;
94
- // Construct WebSocket URL
95
- // baseURL is like https://api.cartesia.ai
96
- let urlStr = baseURL.replace(/^http/, "ws");
97
- if (!urlStr.includes("/tts/websocket")) {
98
- if (urlStr.endsWith("/")) {
99
- urlStr += "tts/websocket";
100
- } else {
101
- urlStr += "/tts/websocket";
102
- }
103
- }
104
-
105
- const url = new URL(urlStr);
106
-
107
- const headers: any = {
108
- "cartesia-version": "2025-04-16",
109
- };
110
- if (this.client.apiKey) {
111
- headers["Authorization"] = `Bearer ${this.client.apiKey}`;
112
- }
113
-
114
- this.socket = new WebSocket(url.toString(), {
115
- headers: headers,
116
- });
117
-
118
- return new Promise<void>((resolve, reject) => {
119
- this.socket!.on("open", () => {
120
- console.log("WebSocket connected.");
121
- resolve();
122
- });
123
-
124
- this.socket!.on("error", (err) => {
125
- console.error("WebSocket error:", err);
126
- reject(err);
127
- });
128
-
129
- this.socket!.on("message", (data) => {
130
- this.handleMessage(data);
131
- });
132
-
133
- this.socket!.on("close", () => {
134
- console.log("WebSocket closed.");
135
- this.sources.forEach((s) => { s.markDone(); });
136
- if (this.defaultSource) this.defaultSource.markDone();
137
- });
138
- });
139
- }
140
-
141
- private handleMessage(data: WebSocket.Data) {
142
- try {
143
- const str = data.toString();
144
- const msg = JSON.parse(str);
145
-
146
- const contextId = msg.context_id;
147
- let source = contextId ? this.sources.get(contextId) : this.defaultSource;
148
-
149
- // If we received a message for a context we don't know about, and we have a default source, use it
150
- if (!source && this.defaultSource) {
151
- source = this.defaultSource;
152
- }
153
-
154
- if (msg.type === "chunk" && msg.data) {
155
- const audioData = Buffer.from(msg.data, "base64");
156
- if (source) source.push(audioData);
157
- } else if (msg.type === "done") {
158
- if (source) source.markDone();
159
- } else if (msg.type === "error") {
160
- console.error("Server error:", msg);
161
- if (source) source.markDone(); // Fail the stream?
162
- }
163
- } catch (e) {
164
- console.error("Error parsing message:", e);
165
- }
166
- }
167
-
168
- async send(request: any) {
169
- if (!this.socket) {
170
- throw new Error("WebSocket not connected");
171
- }
172
-
173
- // Ensure request has a context_id so we can route the response
174
- if (!request.context_id) {
175
- request.context_id = uuidv4();
176
- }
177
-
178
- const source = new AudioSource();
179
- this.sources.set(request.context_id, source);
180
- // Also set as default source if none exists, for compatibility with simple tests
181
- if (!this.defaultSource) {
182
- this.defaultSource = source;
183
- }
184
-
185
- // Add output format from config if not present
186
- if (!request.output_format && this.config) {
187
- request.output_format = {
188
- container: this.config.container,
189
- encoding: this.config.encoding,
190
- sample_rate: this.config.sampleRate,
191
- };
192
- }
193
- // Fix camelCase to snake_case for output_format if needed
194
- // The new API expects snake_case keys in JSON usually, but let's check.
195
- // The GenerationRequest interface has `output_format`.
196
- // The config passed to .websocket() uses `sampleRate`.
197
- // We might need to map it.
198
-
199
- if (request.output_format) {
200
- // Ensure sample_rate is set (mapping from sampleRate)
201
- if (request.output_format.sampleRate && !request.output_format.sample_rate) {
202
- request.output_format.sample_rate = request.output_format.sampleRate;
203
- delete request.output_format.sampleRate;
204
- }
205
- }
206
-
207
- // Map camelCase request fields to snake_case if necessary?
208
- // The old test uses `modelId`, `generationConfig`.
209
- // The new API expects `model_id`, `generation_config`.
210
- const payload = {
211
- ...request,
212
- model_id: request.modelId || request.model_id,
213
- generation_config: request.generationConfig || request.generation_config,
214
- context_id: request.context_id,
215
- };
216
- // Remove camelCase keys if they persist?
217
- // JSON.stringify handles it, but we should clean up if we want to be strict.
218
-
219
- // Also `voice` object. Old test: `voice: { mode: 'id', id: ... }`. New API: same.
220
-
221
- this.socket.send(JSON.stringify(payload));
222
-
223
- return {
224
- source: source
225
- };
226
- }
227
-
228
- disconnect() {
229
- if (this.socket) {
230
- this.socket.close();
231
- }
232
- }
233
- }
234
-
235
- class TTSWrapper {
1
+ import { Cartesia, type ClientOptions } from "../client";
2
+ import { TTSWrapper } from "./tts-wrapper";
3
+ import { VoicesWrapper } from "./voices-wrapper";
4
+ import { VoiceChangerWrapper } from "./voice-changer-wrapper";
5
+ import type { CartesiaClientOptions } from "./types";
6
+
7
+ /**
8
+ * @deprecated Use the {@link Cartesia} class directly instead.
9
+ *
10
+ * This class is provided for backward compatibility with the legacy SDK and may be removed in a future release.
11
+ */
12
+ export class CartesiaClient {
236
13
  private client: Cartesia;
14
+ public tts: TTSWrapper;
15
+ public voices: VoicesWrapper;
16
+ public voiceChanger: VoiceChangerWrapper;
237
17
 
238
- constructor(client: Cartesia) {
239
- this.client = client;
240
- }
241
-
242
- websocket(config: any) {
243
- return new WebSocketWrapper(this.client, config);
244
- }
245
-
246
- async bytes(request: any, requestOptions?: any) {
247
- const params: any = {
248
- model_id: request.modelId,
249
- transcript: request.transcript,
250
- voice: request.voice,
251
- generation_config: request.generationConfig,
252
- context_id: request.contextId,
253
- };
18
+ constructor(options: CartesiaClientOptions = {}) {
19
+ const newOptions: ClientOptions = {};
254
20
 
255
- if (request.outputFormat) {
256
- params.output_format = {
257
- ...request.outputFormat,
258
- sample_rate: request.outputFormat.sampleRate,
259
- bit_rate: request.outputFormat.bitRate,
260
- };
261
- // Remove camelCase keys
262
- delete params.output_format.sampleRate;
263
- delete params.output_format.bitRate;
21
+ if (options.apiKey) {
22
+ newOptions.apiKey = options.apiKey as any;
264
23
  }
265
24
 
266
- const options: any = {};
267
- if (requestOptions) {
268
- if (requestOptions.timeoutInSeconds) {
269
- options.timeout = requestOptions.timeoutInSeconds * 1000;
270
- }
271
- options.maxRetries = requestOptions.maxRetries;
272
- options.headers = requestOptions.headers;
273
- options.signal = requestOptions.abortSignal;
25
+ if (options.baseUrl) {
26
+ newOptions.baseURL = options.baseUrl as any;
27
+ } else if (options.environment) {
28
+ newOptions.baseURL = options.environment as any;
274
29
  }
275
30
 
276
- // @ts-ignore
277
- return this.client.tts.synthesizeBytes(params, options);
278
- }
279
- }
280
-
281
- /*
282
- * CartesiaClient - deprecated backcompat class.
283
- * New code should use Cartesia class directly instead.
284
- */
285
- export class CartesiaClient {
286
- private client: Cartesia;
287
- public tts: TTSWrapper;
288
-
289
- constructor(options: any) {
290
- this.client = new Cartesia(options);
31
+ this.client = new Cartesia(newOptions);
291
32
  this.tts = new TTSWrapper(this.client);
33
+ this.voices = new VoicesWrapper(this.client);
34
+ this.voiceChanger = new VoiceChangerWrapper(this.client);
292
35
  }
293
36
  }
294
37
 
295
-
296
- // Helper for generating UUIDs. Not cryptographically secure.
297
- function uuidv4() {
298
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
299
- var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
300
- return v.toString(16);
301
- });
302
- }
38
+ export * from "./tts-wrapper";
39
+ export * from "./voices-wrapper";
40
+ export * from "./voice-changer-wrapper";
41
+ export * from "./types";
42
+ export * from "./errors";
@@ -0,0 +1,328 @@
1
+ import WebSocket from "ws";
2
+ import { Cartesia } from "../client";
3
+ import { type RequestOptions as InternalRequestOptions } from "../internal/request-options";
4
+ import { BackCompatRequestOptions } from "./types";
5
+ import { wrap } from "./errors";
6
+
7
+ // Define compatible interfaces to match the old SDK types for WebSocket
8
+ export interface BackCompatWebSocketOptions {
9
+ container?: "raw" | "wav" | "mp3";
10
+ encoding?: "pcm_f32le" | "pcm_s16le" | "pcm_alaw" | "pcm_mulaw";
11
+ sampleRate: number;
12
+ }
13
+
14
+ export type BackCompatTtsRequestVoiceSpecifier =
15
+ | { mode: "id"; id: string }
16
+ | { mode: "embedding"; embedding: number[] };
17
+
18
+ export interface BackCompatGenerationConfig {
19
+ volume?: number;
20
+ speed?: number;
21
+ emotion?: string[]; // Simplified from strict union for backcompat flexibility
22
+ }
23
+
24
+ export interface BackCompatWebSocketTtsRequest {
25
+ modelId: string;
26
+ transcript: string;
27
+ voice: BackCompatTtsRequestVoiceSpecifier;
28
+ generationConfig?: BackCompatGenerationConfig;
29
+ outputFormat?: {
30
+ container?: "raw" | "wav" | "mp3";
31
+ encoding?: "pcm_f32le" | "pcm_s16le" | "pcm_alaw" | "pcm_mulaw";
32
+ sampleRate?: number;
33
+ bitRate?: number;
34
+ };
35
+ contextId?: string; // Backcompat might pass this in request?
36
+ // Add other fields as needed
37
+ continue?: boolean;
38
+ duration?: number;
39
+ addTimestamps?: boolean;
40
+ addPhonemeTimestamps?: boolean;
41
+ }
42
+
43
+ // Helper for generating UUIDs. Not cryptographically secure.
44
+ function uuidv4() {
45
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
46
+ var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
47
+ return v.toString(16);
48
+ });
49
+ }
50
+
51
+ class AudioSource {
52
+ private buffers: Buffer[] = [];
53
+ private waiter: ((val?: any) => void) | null = null;
54
+ public isDone = false;
55
+
56
+ push(data: Buffer) {
57
+ this.buffers.push(data);
58
+ if (this.waiter) {
59
+ this.waiter();
60
+ this.waiter = null;
61
+ }
62
+ }
63
+
64
+ markDone() {
65
+ this.isDone = true;
66
+ if (this.waiter) {
67
+ this.waiter();
68
+ this.waiter = null;
69
+ }
70
+ }
71
+
72
+ async read(outBuffer: Float32Array): Promise<number> {
73
+ if (this.buffers.length === 0 && !this.isDone) {
74
+ await new Promise<void>((resolve) => { this.waiter = resolve; });
75
+ }
76
+
77
+ if (this.buffers.length === 0 && this.isDone) {
78
+ return 0;
79
+ }
80
+
81
+ let totalFloatsRead = 0;
82
+ let outOffset = 0;
83
+ const maxFloats = outBuffer.length;
84
+
85
+ while (this.buffers.length > 0 && totalFloatsRead < maxFloats) {
86
+ const buf = this.buffers[0] as Buffer; // ts not smart enough to check loop condition
87
+ const floatsInBuf = buf.length / 4;
88
+ const floatsNeeded = maxFloats - totalFloatsRead;
89
+
90
+ const floatsToCopy = Math.min(floatsInBuf, floatsNeeded);
91
+ const bytesToCopy = floatsToCopy * 4;
92
+
93
+ // Copy to outBuffer.
94
+ // Create a view on the buffer to read floats.
95
+
96
+ // We need to ensure byteOffset is a multiple of 4.
97
+ // If not, we must copy the buffer to a new one.
98
+ let srcFloats: Float32Array;
99
+ if (buf.byteOffset % 4 === 0) {
100
+ srcFloats = new Float32Array(buf.buffer, buf.byteOffset, floatsInBuf);
101
+ } else {
102
+ const alignedBuf = new Uint8Array(buf);
103
+ srcFloats = new Float32Array(alignedBuf.buffer, alignedBuf.byteOffset, floatsInBuf);
104
+ }
105
+
106
+ outBuffer.set(srcFloats.subarray(0, floatsToCopy), outOffset);
107
+
108
+ totalFloatsRead += floatsToCopy;
109
+ outOffset += floatsToCopy;
110
+
111
+ if (floatsToCopy < floatsInBuf) {
112
+ // We didn't use the whole buffer. Update it.
113
+ this.buffers[0] = buf.subarray(bytesToCopy);
114
+ } else {
115
+ // We used the whole buffer. Remove it.
116
+ this.buffers.shift();
117
+ }
118
+ }
119
+
120
+ return totalFloatsRead;
121
+ }
122
+ }
123
+
124
+ export class WebSocketWrapper {
125
+ private client: Cartesia;
126
+ private config: BackCompatWebSocketOptions;
127
+ private socket: WebSocket | null = null;
128
+ private sources: Map<string, AudioSource> = new Map();
129
+ // Fallback source for messages without context_id or if we just want to capture everything (legacy behavior?)
130
+ // The original test didn't use context_id explicitly in send() but expected a response source.
131
+ // We'll map context_id to source.
132
+ private defaultSource: AudioSource | null = null;
133
+
134
+ constructor(client: Cartesia, config: BackCompatWebSocketOptions) {
135
+ this.client = client;
136
+ this.config = config;
137
+ }
138
+
139
+ async connect() {
140
+ const baseURL = this.client.baseURL;
141
+ // Construct WebSocket URL
142
+ // baseURL is like https://api.cartesia.ai
143
+ let urlStr = baseURL.replace(/^http/, "ws");
144
+ if (!urlStr.includes("/tts/websocket")) {
145
+ if (urlStr.endsWith("/")) {
146
+ urlStr += "tts/websocket";
147
+ } else {
148
+ urlStr += "/tts/websocket";
149
+ }
150
+ }
151
+
152
+ const url = new URL(urlStr);
153
+
154
+ const headers: any = {
155
+ "cartesia-version": "2025-04-16",
156
+ };
157
+ if (this.client.apiKey) {
158
+ headers["Authorization"] = `Bearer ${this.client.apiKey}`;
159
+ }
160
+
161
+ this.socket = new WebSocket(url.toString(), {
162
+ headers: headers,
163
+ });
164
+
165
+ return new Promise<void>((resolve, reject) => {
166
+ this.socket!.on("open", () => {
167
+ console.log("WebSocket connected.");
168
+ resolve();
169
+ });
170
+
171
+ this.socket!.on("error", (err) => {
172
+ console.error("WebSocket error:", err);
173
+ reject(err);
174
+ });
175
+
176
+ this.socket!.on("message", (data) => {
177
+ this.handleMessage(data);
178
+ });
179
+
180
+ this.socket!.on("close", () => {
181
+ console.log("WebSocket closed.");
182
+ this.sources.forEach((s) => { s.markDone(); });
183
+ if (this.defaultSource) this.defaultSource.markDone();
184
+ });
185
+ });
186
+ }
187
+
188
+ private handleMessage(data: WebSocket.Data) {
189
+ try {
190
+ const str = data.toString();
191
+ const msg = JSON.parse(str);
192
+
193
+ const contextId = msg.context_id;
194
+ let source = contextId ? this.sources.get(contextId) : this.defaultSource;
195
+
196
+ // If we received a message for a context we don't know about, and we have a default source, use it
197
+ if (!source && this.defaultSource) {
198
+ source = this.defaultSource;
199
+ }
200
+
201
+ if (msg.type === "chunk" && msg.data) {
202
+ const audioData = Buffer.from(msg.data, "base64");
203
+ if (source) source.push(audioData);
204
+ } else if (msg.type === "done") {
205
+ if (source) source.markDone();
206
+ } else if (msg.type === "error") {
207
+ console.error("Server error:", msg);
208
+ if (source) source.markDone(); // Fail the stream?
209
+ }
210
+ } catch (e) {
211
+ console.error("Error parsing message:", e);
212
+ }
213
+ }
214
+
215
+ async send(request: BackCompatWebSocketTtsRequest) {
216
+ if (!this.socket) {
217
+ throw new Error("WebSocket not connected");
218
+ }
219
+
220
+ // Ensure request has a context_id so we can route the response
221
+ const contextId = request.contextId || uuidv4();
222
+
223
+ const source = new AudioSource();
224
+ this.sources.set(contextId, source);
225
+ // Also set as default source if none exists, for compatibility with simple tests
226
+ if (!this.defaultSource) {
227
+ this.defaultSource = source;
228
+ }
229
+
230
+ // Construct payload
231
+ const payload: any = {
232
+ model_id: request.modelId,
233
+ transcript: request.transcript,
234
+ voice: request.voice,
235
+ context_id: contextId,
236
+ };
237
+
238
+ // Output Format
239
+ if (request.outputFormat) {
240
+ payload.output_format = {
241
+ container: request.outputFormat.container,
242
+ encoding: request.outputFormat.encoding,
243
+ sample_rate: request.outputFormat.sampleRate,
244
+ bit_rate: request.outputFormat.bitRate,
245
+ };
246
+ } else if (this.config) {
247
+ payload.output_format = {
248
+ container: this.config.container,
249
+ encoding: this.config.encoding,
250
+ sample_rate: this.config.sampleRate,
251
+ };
252
+ }
253
+
254
+ // Generation Config
255
+ if (request.generationConfig) {
256
+ payload.generation_config = request.generationConfig;
257
+ }
258
+
259
+ // Other fields
260
+ if (request.continue !== undefined) payload.continue = request.continue;
261
+ if (request.duration !== undefined) payload.duration = request.duration;
262
+ if (request.addTimestamps !== undefined) payload.add_timestamps = request.addTimestamps;
263
+ if (request.addPhonemeTimestamps !== undefined) payload.add_phoneme_timestamps = request.addPhonemeTimestamps;
264
+
265
+ this.socket.send(JSON.stringify(payload));
266
+
267
+ return {
268
+ source: source
269
+ };
270
+ }
271
+
272
+ disconnect() {
273
+ if (this.socket) {
274
+ this.socket.close();
275
+ }
276
+ }
277
+ }
278
+
279
+ /** @deprecated Use the new SDK's tts methods on the {@link Cartesia} instance instead. */
280
+ export class TTSWrapper {
281
+ private client: Cartesia;
282
+
283
+ constructor(client: Cartesia) {
284
+ this.client = client;
285
+ }
286
+
287
+ /** @deprecated Use {@link Cartesia.tts.websocket} instead. */
288
+ websocket(config: BackCompatWebSocketOptions) {
289
+ return new WebSocketWrapper(this.client, config);
290
+ }
291
+
292
+ /** @deprecated Use {@link Cartesia.tts.synthesizeBytes} instead. */
293
+ async bytes(request: any, requestOptions?: BackCompatRequestOptions) {
294
+ const params: any = {
295
+ model_id: request.modelId,
296
+ transcript: request.transcript,
297
+ voice: request.voice,
298
+ generation_config: request.generationConfig,
299
+ context_id: request.contextId,
300
+ };
301
+
302
+ if (request.outputFormat) {
303
+ params.output_format = {
304
+ ...request.outputFormat,
305
+ sample_rate: request.outputFormat.sampleRate,
306
+ bit_rate: request.outputFormat.bitRate,
307
+ };
308
+ // Remove camelCase keys
309
+ delete params.output_format.sampleRate;
310
+ delete params.output_format.bitRate;
311
+ }
312
+
313
+ const options: any = {};
314
+ if (requestOptions) {
315
+ if (requestOptions.timeoutInSeconds) {
316
+ options.timeout = requestOptions.timeoutInSeconds * 1000;
317
+ }
318
+ if (requestOptions.maxRetries !== undefined) {
319
+ options.maxRetries = requestOptions.maxRetries;
320
+ }
321
+ options.headers = requestOptions.headers;
322
+ options.signal = requestOptions.abortSignal;
323
+ }
324
+
325
+ // @ts-ignore
326
+ return wrap(this.client.tts.synthesizeBytes(params, options));
327
+ }
328
+ }
@@ -0,0 +1,19 @@
1
+ export type Supplier<T> = T | Promise<T> | (() => T | Promise<T>);
2
+
3
+ export interface CartesiaClientOptions {
4
+ environment?: Supplier<"https://api.cartesia.ai" | string>;
5
+ /** Specify a custom URL to connect the client to. */
6
+ baseUrl?: Supplier<string>;
7
+ apiKey?: Supplier<string | undefined>;
8
+ /** Override the Cartesia-Version header */
9
+ cartesiaVersion?: string;
10
+ fetcher?: any;
11
+ }
12
+
13
+ export interface BackCompatRequestOptions {
14
+ timeoutInSeconds?: number;
15
+ maxRetries?: number;
16
+ abortSignal?: AbortSignal;
17
+ cartesiaVersion?: string;
18
+ headers?: Record<string, string>;
19
+ }