@livekit/agents-plugin-cartesia 1.4.4 → 1.4.6
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/README.md +1 -1
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/models.cjs +3 -0
- package/dist/models.cjs.map +1 -1
- package/dist/models.d.cts +17 -0
- package/dist/models.d.ts +17 -0
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +2 -0
- package/dist/models.js.map +1 -1
- package/dist/stt.cjs +409 -0
- package/dist/stt.cjs.map +1 -0
- package/dist/stt.d.cts +51 -0
- package/dist/stt.d.ts +51 -0
- package/dist/stt.d.ts.map +1 -0
- package/dist/stt.js +392 -0
- package/dist/stt.js.map +1 -0
- package/dist/stt.test.cjs +17 -0
- package/dist/stt.test.cjs.map +1 -0
- package/dist/stt.test.d.cts +2 -0
- package/dist/stt.test.d.ts +2 -0
- package/dist/stt.test.d.ts.map +1 -0
- package/dist/stt.test.js +16 -0
- package/dist/stt.test.js.map +1 -0
- package/dist/tts.cjs +31 -21
- package/dist/tts.cjs.map +1 -1
- package/dist/tts.d.ts.map +1 -1
- package/dist/tts.js +35 -22
- package/dist/tts.js.map +1 -1
- package/package.json +8 -7
- package/src/index.ts +1 -0
- package/src/models.ts +28 -6
- package/src/stt.test.ts +19 -0
- package/src/stt.ts +618 -0
- package/src/tts.ts +41 -24
package/src/tts.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import {
|
|
5
5
|
type APIConnectOptions,
|
|
6
6
|
APIConnectionError,
|
|
7
|
+
APIError,
|
|
8
|
+
APIStatusError,
|
|
7
9
|
APITimeoutError,
|
|
8
10
|
AudioByteStream,
|
|
9
11
|
Future,
|
|
@@ -36,6 +38,7 @@ import {
|
|
|
36
38
|
isChunkMessage,
|
|
37
39
|
isDoneMessage,
|
|
38
40
|
isErrorMessage,
|
|
41
|
+
isFlushDoneMessage,
|
|
39
42
|
} from './types.js';
|
|
40
43
|
|
|
41
44
|
const AUTHORIZATION_HEADER = 'X-API-Key';
|
|
@@ -433,34 +436,24 @@ export class SynthesizeStream extends tts.SynthesizeStream {
|
|
|
433
436
|
continue;
|
|
434
437
|
}
|
|
435
438
|
|
|
436
|
-
// Handle error messages
|
|
437
|
-
if (isErrorMessage(serverMsg)) {
|
|
438
|
-
this.#logger.error({ error: serverMsg.error }, 'Cartesia returned error');
|
|
439
|
-
continue;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
439
|
const segmentId = serverMsg.context_id;
|
|
443
440
|
|
|
444
|
-
//
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
}),
|
|
458
|
-
);
|
|
459
|
-
}
|
|
441
|
+
// Handle error frames first. 4xx (e.g. empty-transcript on
|
|
442
|
+
// function-call turns) is non-fatal — log and fall through so an
|
|
443
|
+
// accompanying done:true still triggers the unified close path
|
|
444
|
+
// below. 5xx bubbles up so the base SynthesizeStream can retry.
|
|
445
|
+
if (isErrorMessage(serverMsg)) {
|
|
446
|
+
if (serverMsg.status_code >= 400 && serverMsg.status_code < 500) {
|
|
447
|
+
this.#logger.debug({ error: serverMsg.error }, 'Cartesia sent a non-fatal error');
|
|
448
|
+
} else {
|
|
449
|
+
this.#logger.error({ error: serverMsg.error }, 'Cartesia returned error');
|
|
450
|
+
throw new APIStatusError({
|
|
451
|
+
message: `Cartesia returned error: ${serverMsg.error}`,
|
|
452
|
+
options: { statusCode: serverMsg.status_code, retryable: true },
|
|
453
|
+
});
|
|
460
454
|
}
|
|
461
455
|
}
|
|
462
456
|
|
|
463
|
-
// Handle audio chunk messages
|
|
464
457
|
if (isChunkMessage(serverMsg)) {
|
|
465
458
|
const audioBuffer = Buffer.from(serverMsg.data, 'base64');
|
|
466
459
|
// Extract ArrayBuffer from Buffer for AudioByteStream compatibility
|
|
@@ -484,7 +477,23 @@ export class SynthesizeStream extends tts.SynthesizeStream {
|
|
|
484
477
|
);
|
|
485
478
|
ws.close();
|
|
486
479
|
}, this.#opts.chunkTimeout);
|
|
487
|
-
} else if (
|
|
480
|
+
} else if (this.#opts.wordTimestamps !== false && hasWordTimestamps(serverMsg)) {
|
|
481
|
+
const wordTimestamps = serverMsg.word_timestamps;
|
|
482
|
+
for (let i = 0; i < wordTimestamps.words.length; i++) {
|
|
483
|
+
const word = wordTimestamps.words[i];
|
|
484
|
+
const startTime = wordTimestamps.start[i];
|
|
485
|
+
const endTime = wordTimestamps.end[i];
|
|
486
|
+
if (word !== undefined && startTime !== undefined && endTime !== undefined) {
|
|
487
|
+
pendingTimedTranscripts.push(
|
|
488
|
+
createTimedString({
|
|
489
|
+
text: word + ' ', // Add space after word for consistency
|
|
490
|
+
startTime,
|
|
491
|
+
endTime,
|
|
492
|
+
}),
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
} else if (isDoneMessage(serverMsg) || (isErrorMessage(serverMsg) && serverMsg.done)) {
|
|
488
497
|
// This ensures all sentences have been sent before closing
|
|
489
498
|
if (sentenceStreamClosed) {
|
|
490
499
|
for (const frame of bstream.flush()) {
|
|
@@ -504,9 +513,16 @@ export class SynthesizeStream extends tts.SynthesizeStream {
|
|
|
504
513
|
}
|
|
505
514
|
}
|
|
506
515
|
// If sentenceStreamClosed is false, continue receiving - more done messages will come
|
|
516
|
+
} else if (!isFlushDoneMessage(serverMsg) && !isErrorMessage(serverMsg)) {
|
|
517
|
+
// flush_done is an ack with nothing to do; error frames without
|
|
518
|
+
// done:true were already logged above.
|
|
519
|
+
this.#logger.warn({ message: serverMsg }, 'Unknown Cartesia message');
|
|
507
520
|
}
|
|
508
521
|
}
|
|
509
522
|
} catch (err) {
|
|
523
|
+
// Always propagate API errors so the base SynthesizeStream can retry
|
|
524
|
+
// and emit tts_error once retries are exhausted.
|
|
525
|
+
if (err instanceof APIError) throw err;
|
|
510
526
|
// skip log error for normal websocket close
|
|
511
527
|
if (err instanceof Error && !err.message.includes('WebSocket closed')) {
|
|
512
528
|
if (
|
|
@@ -549,6 +565,7 @@ export class SynthesizeStream extends tts.SynthesizeStream {
|
|
|
549
565
|
if (this.abortSignal.aborted) {
|
|
550
566
|
return;
|
|
551
567
|
}
|
|
568
|
+
if (e instanceof APIError) throw e;
|
|
552
569
|
throw toRetryableConnectionError(e);
|
|
553
570
|
} finally {
|
|
554
571
|
// Ensure we don't leak sockets/tasks across retry attempts.
|