@livekit/agents-plugin-cartesia 1.4.4 → 1.4.5
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/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/dist/index.cjs
CHANGED
|
@@ -16,12 +16,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
16
16
|
var index_exports = {};
|
|
17
17
|
module.exports = __toCommonJS(index_exports);
|
|
18
18
|
var import_agents = require("@livekit/agents");
|
|
19
|
+
__reExport(index_exports, require("./stt.cjs"), module.exports);
|
|
19
20
|
__reExport(index_exports, require("./tts.cjs"), module.exports);
|
|
20
21
|
class CartesiaPlugin extends import_agents.Plugin {
|
|
21
22
|
constructor() {
|
|
22
23
|
super({
|
|
23
24
|
title: "cartesia",
|
|
24
|
-
version: "1.4.
|
|
25
|
+
version: "1.4.5",
|
|
25
26
|
package: "@livekit/agents-plugin-cartesia"
|
|
26
27
|
});
|
|
27
28
|
}
|
|
@@ -29,6 +30,7 @@ class CartesiaPlugin extends import_agents.Plugin {
|
|
|
29
30
|
import_agents.Plugin.registerPlugin(new CartesiaPlugin());
|
|
30
31
|
// Annotate the CommonJS export names for ESM import in node:
|
|
31
32
|
0 && (module.exports = {
|
|
33
|
+
...require("./stt.cjs"),
|
|
32
34
|
...require("./tts.cjs")
|
|
33
35
|
});
|
|
34
36
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Plugin } from '@livekit/agents';\n\nexport * from './tts.js';\n\nclass CartesiaPlugin extends Plugin {\n constructor() {\n super({\n title: 'cartesia',\n version: __PACKAGE_VERSION__,\n package: __PACKAGE_NAME__,\n });\n }\n}\n\nPlugin.registerPlugin(new CartesiaPlugin());\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAGA,oBAAuB;AAEvB,0BAAc,qBALd;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Plugin } from '@livekit/agents';\n\nexport * from './stt.js';\nexport * from './tts.js';\n\nclass CartesiaPlugin extends Plugin {\n constructor() {\n super({\n title: 'cartesia',\n version: __PACKAGE_VERSION__,\n package: __PACKAGE_NAME__,\n });\n }\n}\n\nPlugin.registerPlugin(new CartesiaPlugin());\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA;AAGA,oBAAuB;AAEvB,0BAAc,qBALd;AAMA,0BAAc,qBANd;AAQA,MAAM,uBAAuB,qBAAO;AAAA,EAClC,cAAc;AACZ,UAAM;AAAA,MACJ,OAAO;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAEA,qBAAO,eAAe,IAAI,eAAe,CAAC;","names":[]}
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Plugin } from "@livekit/agents";
|
|
2
|
+
export * from "./stt.js";
|
|
2
3
|
export * from "./tts.js";
|
|
3
4
|
class CartesiaPlugin extends Plugin {
|
|
4
5
|
constructor() {
|
|
5
6
|
super({
|
|
6
7
|
title: "cartesia",
|
|
7
|
-
version: "1.4.
|
|
8
|
+
version: "1.4.5",
|
|
8
9
|
package: "@livekit/agents-plugin-cartesia"
|
|
9
10
|
});
|
|
10
11
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Plugin } from '@livekit/agents';\n\nexport * from './tts.js';\n\nclass CartesiaPlugin extends Plugin {\n constructor() {\n super({\n title: 'cartesia',\n version: __PACKAGE_VERSION__,\n package: __PACKAGE_NAME__,\n });\n }\n}\n\nPlugin.registerPlugin(new CartesiaPlugin());\n"],"mappings":"AAGA,SAAS,cAAc;AAEvB,cAAc;AAEd,MAAM,uBAAuB,OAAO;AAAA,EAClC,cAAc;AACZ,UAAM;AAAA,MACJ,OAAO;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAEA,OAAO,eAAe,IAAI,eAAe,CAAC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { Plugin } from '@livekit/agents';\n\nexport * from './stt.js';\nexport * from './tts.js';\n\nclass CartesiaPlugin extends Plugin {\n constructor() {\n super({\n title: 'cartesia',\n version: __PACKAGE_VERSION__,\n package: __PACKAGE_NAME__,\n });\n }\n}\n\nPlugin.registerPlugin(new CartesiaPlugin());\n"],"mappings":"AAGA,SAAS,cAAc;AAEvB,cAAc;AACd,cAAc;AAEd,MAAM,uBAAuB,OAAO;AAAA,EAClC,cAAc;AACZ,UAAM;AAAA,MACJ,OAAO;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAEA,OAAO,eAAe,IAAI,eAAe,CAAC;","names":[]}
|
package/dist/models.cjs
CHANGED
|
@@ -18,14 +18,17 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var models_exports = {};
|
|
20
20
|
__export(models_exports, {
|
|
21
|
+
AUDIO_ENCODING: () => AUDIO_ENCODING,
|
|
21
22
|
TTSDefaultVoiceId: () => TTSDefaultVoiceId,
|
|
22
23
|
isSonic3: () => isSonic3
|
|
23
24
|
});
|
|
24
25
|
module.exports = __toCommonJS(models_exports);
|
|
26
|
+
const AUDIO_ENCODING = "pcm_s16le";
|
|
25
27
|
const TTSDefaultVoiceId = "f786b574-daa5-4673-aa0c-cbe3e8534c02";
|
|
26
28
|
const isSonic3 = (model) => model.startsWith("sonic-3");
|
|
27
29
|
// Annotate the CommonJS export names for ESM import in node:
|
|
28
30
|
0 && (module.exports = {
|
|
31
|
+
AUDIO_ENCODING,
|
|
29
32
|
TTSDefaultVoiceId,
|
|
30
33
|
isSonic3
|
|
31
34
|
});
|
package/dist/models.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/models.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\nexport type TTSModels =\n | 'sonic'\n | 'sonic-2'\n | 'sonic-3'\n | 'sonic-lite'\n | 'sonic-preview'\n | 'sonic-turbo';\n\nexport type TTSLanguages = 'en' | 'es' | 'fr' | 'de' | 'pt' | 'zh' | 'ja';\n\nexport const TTSDefaultVoiceId = 'f786b574-daa5-4673-aa0c-cbe3e8534c02';\n\nexport const isSonic3 = (model: string): boolean => model.startsWith('sonic-3');\n\nexport type TTSVoiceSpeed = 'fastest' | 'fast' | 'normal' | 'slow' | 'slowest';\n\nexport type TTSVoiceEmotion =\n | 'anger:lowest'\n | 'anger:low'\n | 'anger'\n | 'anger:high'\n | 'anger:highest'\n | 'positivity:lowest'\n | 'positivity:low'\n | 'positivity'\n | 'positivity:high'\n | 'positivity:highest'\n | 'surprise:lowest'\n | 'surprise:low'\n | 'surprise'\n | 'surprise:high'\n | 'surprise:highest'\n | 'sadness:lowest'\n | 'sadness:low'\n | 'sadness'\n | 'sadness:high'\n | 'sadness:highest'\n | 'curiosity:lowest'\n | 'curiosity:low'\n | 'curiosity'\n | 'curiosity:high'\n | 'curiosity:highest';\n\
|
|
1
|
+
{"version":3,"sources":["../src/models.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * LiveKit uses this encoding for all audio\n */\nexport const AUDIO_ENCODING = 'pcm_s16le';\n\n// ============================================================================\n// TTS\n// ============================================================================\n\n/**\n * See [the docs](https://docs.cartesia.ai/build-with-cartesia/tts-models/latest) for all options.\n */\nexport type TTSModels =\n | 'sonic'\n | 'sonic-2'\n | 'sonic-3'\n | 'sonic-lite'\n | 'sonic-preview'\n | 'sonic-turbo';\n\n/**\n * See [the docs](https://docs.cartesia.ai/build-with-cartesia/tts-models/latest) for all options.\n */\nexport type TTSLanguages = 'en' | 'es' | 'fr' | 'de' | 'pt' | 'zh' | 'ja';\n\nexport const TTSDefaultVoiceId = 'f786b574-daa5-4673-aa0c-cbe3e8534c02';\n\nexport const isSonic3 = (model: string): boolean => model.startsWith('sonic-3');\n\nexport type TTSVoiceSpeed = 'fastest' | 'fast' | 'normal' | 'slow' | 'slowest';\n\nexport type TTSVoiceEmotion =\n | 'anger:lowest'\n | 'anger:low'\n | 'anger'\n | 'anger:high'\n | 'anger:highest'\n | 'positivity:lowest'\n | 'positivity:low'\n | 'positivity'\n | 'positivity:high'\n | 'positivity:highest'\n | 'surprise:lowest'\n | 'surprise:low'\n | 'surprise'\n | 'surprise:high'\n | 'surprise:highest'\n | 'sadness:lowest'\n | 'sadness:low'\n | 'sadness'\n | 'sadness:high'\n | 'sadness:highest'\n | 'curiosity:lowest'\n | 'curiosity:low'\n | 'curiosity'\n | 'curiosity:high'\n | 'curiosity:highest';\n\n/**\n * @deprecated Encoding should not be parameterized. Only `pcm_s16le`is allowed. Prefer using {@link AUDIO_ENCODING}.\n */\nexport type TTSEncoding = 'pcm_s16le';\n\n// ============================================================================\n// STT\n// ============================================================================\n\n/**\n * See [the docs](https://docs.cartesia.ai/build-with-cartesia/stt-models/latest) for all options.\n */\nexport type STTModel = 'ink-2';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,MAAM,iBAAiB;AAsBvB,MAAM,oBAAoB;AAE1B,MAAM,WAAW,CAAC,UAA2B,MAAM,WAAW,SAAS;","names":[]}
|
package/dist/models.d.cts
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LiveKit uses this encoding for all audio
|
|
3
|
+
*/
|
|
4
|
+
export declare const AUDIO_ENCODING = "pcm_s16le";
|
|
5
|
+
/**
|
|
6
|
+
* See [the docs](https://docs.cartesia.ai/build-with-cartesia/tts-models/latest) for all options.
|
|
7
|
+
*/
|
|
1
8
|
export type TTSModels = 'sonic' | 'sonic-2' | 'sonic-3' | 'sonic-lite' | 'sonic-preview' | 'sonic-turbo';
|
|
9
|
+
/**
|
|
10
|
+
* See [the docs](https://docs.cartesia.ai/build-with-cartesia/tts-models/latest) for all options.
|
|
11
|
+
*/
|
|
2
12
|
export type TTSLanguages = 'en' | 'es' | 'fr' | 'de' | 'pt' | 'zh' | 'ja';
|
|
3
13
|
export declare const TTSDefaultVoiceId = "f786b574-daa5-4673-aa0c-cbe3e8534c02";
|
|
4
14
|
export declare const isSonic3: (model: string) => boolean;
|
|
5
15
|
export type TTSVoiceSpeed = 'fastest' | 'fast' | 'normal' | 'slow' | 'slowest';
|
|
6
16
|
export type TTSVoiceEmotion = 'anger:lowest' | 'anger:low' | 'anger' | 'anger:high' | 'anger:highest' | 'positivity:lowest' | 'positivity:low' | 'positivity' | 'positivity:high' | 'positivity:highest' | 'surprise:lowest' | 'surprise:low' | 'surprise' | 'surprise:high' | 'surprise:highest' | 'sadness:lowest' | 'sadness:low' | 'sadness' | 'sadness:high' | 'sadness:highest' | 'curiosity:lowest' | 'curiosity:low' | 'curiosity' | 'curiosity:high' | 'curiosity:highest';
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated Encoding should not be parameterized. Only `pcm_s16le`is allowed. Prefer using {@link AUDIO_ENCODING}.
|
|
19
|
+
*/
|
|
7
20
|
export type TTSEncoding = 'pcm_s16le';
|
|
21
|
+
/**
|
|
22
|
+
* See [the docs](https://docs.cartesia.ai/build-with-cartesia/stt-models/latest) for all options.
|
|
23
|
+
*/
|
|
24
|
+
export type STTModel = 'ink-2';
|
|
8
25
|
//# sourceMappingURL=models.d.ts.map
|
package/dist/models.d.ts
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LiveKit uses this encoding for all audio
|
|
3
|
+
*/
|
|
4
|
+
export declare const AUDIO_ENCODING = "pcm_s16le";
|
|
5
|
+
/**
|
|
6
|
+
* See [the docs](https://docs.cartesia.ai/build-with-cartesia/tts-models/latest) for all options.
|
|
7
|
+
*/
|
|
1
8
|
export type TTSModels = 'sonic' | 'sonic-2' | 'sonic-3' | 'sonic-lite' | 'sonic-preview' | 'sonic-turbo';
|
|
9
|
+
/**
|
|
10
|
+
* See [the docs](https://docs.cartesia.ai/build-with-cartesia/tts-models/latest) for all options.
|
|
11
|
+
*/
|
|
2
12
|
export type TTSLanguages = 'en' | 'es' | 'fr' | 'de' | 'pt' | 'zh' | 'ja';
|
|
3
13
|
export declare const TTSDefaultVoiceId = "f786b574-daa5-4673-aa0c-cbe3e8534c02";
|
|
4
14
|
export declare const isSonic3: (model: string) => boolean;
|
|
5
15
|
export type TTSVoiceSpeed = 'fastest' | 'fast' | 'normal' | 'slow' | 'slowest';
|
|
6
16
|
export type TTSVoiceEmotion = 'anger:lowest' | 'anger:low' | 'anger' | 'anger:high' | 'anger:highest' | 'positivity:lowest' | 'positivity:low' | 'positivity' | 'positivity:high' | 'positivity:highest' | 'surprise:lowest' | 'surprise:low' | 'surprise' | 'surprise:high' | 'surprise:highest' | 'sadness:lowest' | 'sadness:low' | 'sadness' | 'sadness:high' | 'sadness:highest' | 'curiosity:lowest' | 'curiosity:low' | 'curiosity' | 'curiosity:high' | 'curiosity:highest';
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated Encoding should not be parameterized. Only `pcm_s16le`is allowed. Prefer using {@link AUDIO_ENCODING}.
|
|
19
|
+
*/
|
|
7
20
|
export type TTSEncoding = 'pcm_s16le';
|
|
21
|
+
/**
|
|
22
|
+
* See [the docs](https://docs.cartesia.ai/build-with-cartesia/stt-models/latest) for all options.
|
|
23
|
+
*/
|
|
24
|
+
export type STTModel = 'ink-2';
|
|
8
25
|
//# sourceMappingURL=models.d.ts.map
|
package/dist/models.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,SAAS,GACT,SAAS,GACT,YAAY,GACZ,eAAe,GACf,aAAa,CAAC;AAElB,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE1E,eAAO,MAAM,iBAAiB,yCAAyC,CAAC;AAExE,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,KAAG,OAAsC,CAAC;AAEhF,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE/E,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,WAAW,GACX,OAAO,GACP,YAAY,GACZ,eAAe,GACf,mBAAmB,GACnB,gBAAgB,GAChB,YAAY,GACZ,iBAAiB,GACjB,oBAAoB,GACpB,iBAAiB,GACjB,cAAc,GACd,UAAU,GACV,eAAe,GACf,kBAAkB,GAClB,gBAAgB,GAChB,aAAa,GACb,SAAS,GACT,cAAc,GACd,iBAAiB,GACjB,kBAAkB,GAClB,eAAe,GACf,WAAW,GACX,gBAAgB,GAChB,mBAAmB,CAAC;AAExB,MAAM,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,eAAO,MAAM,cAAc,cAAc,CAAC;AAM1C;;GAEG;AACH,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,SAAS,GACT,SAAS,GACT,YAAY,GACZ,eAAe,GACf,aAAa,CAAC;AAElB;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE1E,eAAO,MAAM,iBAAiB,yCAAyC,CAAC;AAExE,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,KAAG,OAAsC,CAAC;AAEhF,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE/E,MAAM,MAAM,eAAe,GACvB,cAAc,GACd,WAAW,GACX,OAAO,GACP,YAAY,GACZ,eAAe,GACf,mBAAmB,GACnB,gBAAgB,GAChB,YAAY,GACZ,iBAAiB,GACjB,oBAAoB,GACpB,iBAAiB,GACjB,cAAc,GACd,UAAU,GACV,eAAe,GACf,kBAAkB,GAClB,gBAAgB,GAChB,aAAa,GACb,SAAS,GACT,cAAc,GACd,iBAAiB,GACjB,kBAAkB,GAClB,eAAe,GACf,WAAW,GACX,gBAAgB,GAChB,mBAAmB,CAAC;AAExB;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC;AAMtC;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,CAAC"}
|
package/dist/models.js
CHANGED
package/dist/models.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/models.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\nexport type TTSModels =\n | 'sonic'\n | 'sonic-2'\n | 'sonic-3'\n | 'sonic-lite'\n | 'sonic-preview'\n | 'sonic-turbo';\n\nexport type TTSLanguages = 'en' | 'es' | 'fr' | 'de' | 'pt' | 'zh' | 'ja';\n\nexport const TTSDefaultVoiceId = 'f786b574-daa5-4673-aa0c-cbe3e8534c02';\n\nexport const isSonic3 = (model: string): boolean => model.startsWith('sonic-3');\n\nexport type TTSVoiceSpeed = 'fastest' | 'fast' | 'normal' | 'slow' | 'slowest';\n\nexport type TTSVoiceEmotion =\n | 'anger:lowest'\n | 'anger:low'\n | 'anger'\n | 'anger:high'\n | 'anger:highest'\n | 'positivity:lowest'\n | 'positivity:low'\n | 'positivity'\n | 'positivity:high'\n | 'positivity:highest'\n | 'surprise:lowest'\n | 'surprise:low'\n | 'surprise'\n | 'surprise:high'\n | 'surprise:highest'\n | 'sadness:lowest'\n | 'sadness:low'\n | 'sadness'\n | 'sadness:high'\n | 'sadness:highest'\n | 'curiosity:lowest'\n | 'curiosity:low'\n | 'curiosity'\n | 'curiosity:high'\n | 'curiosity:highest';\n\
|
|
1
|
+
{"version":3,"sources":["../src/models.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * LiveKit uses this encoding for all audio\n */\nexport const AUDIO_ENCODING = 'pcm_s16le';\n\n// ============================================================================\n// TTS\n// ============================================================================\n\n/**\n * See [the docs](https://docs.cartesia.ai/build-with-cartesia/tts-models/latest) for all options.\n */\nexport type TTSModels =\n | 'sonic'\n | 'sonic-2'\n | 'sonic-3'\n | 'sonic-lite'\n | 'sonic-preview'\n | 'sonic-turbo';\n\n/**\n * See [the docs](https://docs.cartesia.ai/build-with-cartesia/tts-models/latest) for all options.\n */\nexport type TTSLanguages = 'en' | 'es' | 'fr' | 'de' | 'pt' | 'zh' | 'ja';\n\nexport const TTSDefaultVoiceId = 'f786b574-daa5-4673-aa0c-cbe3e8534c02';\n\nexport const isSonic3 = (model: string): boolean => model.startsWith('sonic-3');\n\nexport type TTSVoiceSpeed = 'fastest' | 'fast' | 'normal' | 'slow' | 'slowest';\n\nexport type TTSVoiceEmotion =\n | 'anger:lowest'\n | 'anger:low'\n | 'anger'\n | 'anger:high'\n | 'anger:highest'\n | 'positivity:lowest'\n | 'positivity:low'\n | 'positivity'\n | 'positivity:high'\n | 'positivity:highest'\n | 'surprise:lowest'\n | 'surprise:low'\n | 'surprise'\n | 'surprise:high'\n | 'surprise:highest'\n | 'sadness:lowest'\n | 'sadness:low'\n | 'sadness'\n | 'sadness:high'\n | 'sadness:highest'\n | 'curiosity:lowest'\n | 'curiosity:low'\n | 'curiosity'\n | 'curiosity:high'\n | 'curiosity:highest';\n\n/**\n * @deprecated Encoding should not be parameterized. Only `pcm_s16le`is allowed. Prefer using {@link AUDIO_ENCODING}.\n */\nexport type TTSEncoding = 'pcm_s16le';\n\n// ============================================================================\n// STT\n// ============================================================================\n\n/**\n * See [the docs](https://docs.cartesia.ai/build-with-cartesia/stt-models/latest) for all options.\n */\nexport type STTModel = 'ink-2';\n"],"mappings":"AAOO,MAAM,iBAAiB;AAsBvB,MAAM,oBAAoB;AAE1B,MAAM,WAAW,CAAC,UAA2B,MAAM,WAAW,SAAS;","names":[]}
|
package/dist/stt.cjs
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var stt_exports = {};
|
|
20
|
+
__export(stt_exports, {
|
|
21
|
+
STT: () => STT,
|
|
22
|
+
SpeechStream: () => SpeechStream
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(stt_exports);
|
|
25
|
+
var import_agents = require("@livekit/agents");
|
|
26
|
+
var import_ws = require("ws");
|
|
27
|
+
var import_models = require("./models.cjs");
|
|
28
|
+
const AUTHORIZATION_HEADER = "X-API-Key";
|
|
29
|
+
const VERSION_HEADER = "Cartesia-Version";
|
|
30
|
+
const REQUEST_ID_HEADER = "cartesia-request-id";
|
|
31
|
+
const API_VERSION = "2026-03-01";
|
|
32
|
+
const DRAIN_TIMEOUT_MS = 5e3;
|
|
33
|
+
const KEEPALIVE_INTERVAL_MS = 3e4;
|
|
34
|
+
const defaultSTTOptions = {
|
|
35
|
+
model: "ink-2",
|
|
36
|
+
/** recommended default */
|
|
37
|
+
sampleRate: 16e3,
|
|
38
|
+
/** recommended default */
|
|
39
|
+
audioChunkDurationMS: 160,
|
|
40
|
+
baseUrl: "https://api.cartesia.ai"
|
|
41
|
+
};
|
|
42
|
+
function mergeSTTOptions(base, override) {
|
|
43
|
+
return {
|
|
44
|
+
apiKey: override.apiKey ?? base.apiKey,
|
|
45
|
+
baseUrl: override.baseUrl ?? base.baseUrl,
|
|
46
|
+
model: override.model ?? base.model,
|
|
47
|
+
sampleRate: override.sampleRate ?? base.sampleRate,
|
|
48
|
+
audioChunkDurationMS: override.audioChunkDurationMS ?? base.audioChunkDurationMS
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
class STT extends import_agents.stt.STT {
|
|
52
|
+
#opts;
|
|
53
|
+
constructor(opts = {}) {
|
|
54
|
+
super({
|
|
55
|
+
streaming: true,
|
|
56
|
+
interimResults: true,
|
|
57
|
+
alignedTranscript: false,
|
|
58
|
+
diarization: false
|
|
59
|
+
});
|
|
60
|
+
const apiKey = opts.apiKey ?? process.env.CARTESIA_API_KEY;
|
|
61
|
+
if (!apiKey) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
"Cartesia API key is required, whether as an argument or as $CARTESIA_API_KEY"
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
this.#opts = mergeSTTOptions({ ...defaultSTTOptions, apiKey }, opts);
|
|
67
|
+
}
|
|
68
|
+
get label() {
|
|
69
|
+
return "cartesia.STT";
|
|
70
|
+
}
|
|
71
|
+
get model() {
|
|
72
|
+
return this.#opts.model;
|
|
73
|
+
}
|
|
74
|
+
get provider() {
|
|
75
|
+
return "Cartesia";
|
|
76
|
+
}
|
|
77
|
+
async _recognize() {
|
|
78
|
+
throw new Error("Cartesia STT does not support batch recognition, use stream() instead");
|
|
79
|
+
}
|
|
80
|
+
stream(options) {
|
|
81
|
+
return new SpeechStream(this, this.#opts, options == null ? void 0 : options.connOptions);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
class SpeechStream extends import_agents.stt.SpeechStream {
|
|
85
|
+
#opts;
|
|
86
|
+
#logger = (0, import_agents.log)();
|
|
87
|
+
#ws = null;
|
|
88
|
+
#requestId;
|
|
89
|
+
#speaking = false;
|
|
90
|
+
#currentTranscript = "";
|
|
91
|
+
#speechDuration = 0;
|
|
92
|
+
#closingWs = false;
|
|
93
|
+
constructor(sttInstance, opts, connOptions) {
|
|
94
|
+
super(sttInstance, opts.sampleRate, connOptions);
|
|
95
|
+
this.#opts = { ...opts };
|
|
96
|
+
}
|
|
97
|
+
get label() {
|
|
98
|
+
return "cartesia.SpeechStream";
|
|
99
|
+
}
|
|
100
|
+
async run() {
|
|
101
|
+
var _a;
|
|
102
|
+
if (this.closed) {
|
|
103
|
+
this.close();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
this.#speaking = false;
|
|
107
|
+
this.#currentTranscript = "";
|
|
108
|
+
this.#speechDuration = 0;
|
|
109
|
+
this.#closingWs = false;
|
|
110
|
+
let keepaliveInterval;
|
|
111
|
+
const abortController = new AbortController();
|
|
112
|
+
try {
|
|
113
|
+
const url = this.#getCartesiaUrl();
|
|
114
|
+
this.#logger.debug(`Connecting to Cartesia STT: ${url}`);
|
|
115
|
+
const ws = new import_ws.WebSocket(url, {
|
|
116
|
+
headers: {
|
|
117
|
+
[AUTHORIZATION_HEADER]: this.#opts.apiKey,
|
|
118
|
+
[VERSION_HEADER]: API_VERSION
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
this.#ws = ws;
|
|
122
|
+
ws.once("upgrade", (response) => {
|
|
123
|
+
const headerValue = response.headers[REQUEST_ID_HEADER];
|
|
124
|
+
const requestId = Array.isArray(headerValue) ? headerValue[0] : headerValue;
|
|
125
|
+
if (requestId) {
|
|
126
|
+
this.#requestId = requestId;
|
|
127
|
+
this.#logger.debug({ cartesiaRequestId: requestId }, "Cartesia STT WebSocket connected");
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
await new Promise((resolve, reject) => {
|
|
131
|
+
const onOpen = () => {
|
|
132
|
+
ws.off("error", onError);
|
|
133
|
+
resolve();
|
|
134
|
+
};
|
|
135
|
+
const onError = (err) => {
|
|
136
|
+
ws.off("open", onOpen);
|
|
137
|
+
reject(new import_agents.APIConnectionError({ message: err.message, options: { retryable: true } }));
|
|
138
|
+
};
|
|
139
|
+
ws.once("open", onOpen);
|
|
140
|
+
ws.once("error", onError);
|
|
141
|
+
});
|
|
142
|
+
let firstError;
|
|
143
|
+
const stopPeer = (err) => {
|
|
144
|
+
if (firstError === void 0) firstError = err;
|
|
145
|
+
abortController.abort();
|
|
146
|
+
if (ws.readyState === import_ws.WebSocket.OPEN) ws.close();
|
|
147
|
+
};
|
|
148
|
+
const sendPromise = this.#sendTask(ws, abortController.signal).catch(stopPeer);
|
|
149
|
+
const recvPromise = this.#recvTask(ws).catch(stopPeer);
|
|
150
|
+
keepaliveInterval = setInterval(() => {
|
|
151
|
+
try {
|
|
152
|
+
if (ws.readyState === import_ws.WebSocket.OPEN) {
|
|
153
|
+
ws.ping();
|
|
154
|
+
}
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
}, KEEPALIVE_INTERVAL_MS);
|
|
158
|
+
await Promise.all([sendPromise, recvPromise]);
|
|
159
|
+
if (firstError !== void 0) throw firstError;
|
|
160
|
+
} catch (error) {
|
|
161
|
+
this.#logger.error("Cartesia STT stream error", { error });
|
|
162
|
+
throw error;
|
|
163
|
+
} finally {
|
|
164
|
+
abortController.abort();
|
|
165
|
+
if (keepaliveInterval) clearInterval(keepaliveInterval);
|
|
166
|
+
if (((_a = this.#ws) == null ? void 0 : _a.readyState) === import_ws.WebSocket.OPEN) {
|
|
167
|
+
this.#ws.close();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
this.close();
|
|
171
|
+
}
|
|
172
|
+
async #sendTask(ws, abortSignal) {
|
|
173
|
+
const samplesPerChunk = Math.floor(
|
|
174
|
+
this.#opts.sampleRate * this.#opts.audioChunkDurationMS / 1e3
|
|
175
|
+
);
|
|
176
|
+
const audioBstream = new import_agents.AudioByteStream(this.#opts.sampleRate, 1, samplesPerChunk);
|
|
177
|
+
let hasEnded = false;
|
|
178
|
+
const iterator = this.input[Symbol.asyncIterator]();
|
|
179
|
+
const abortPromise = (0, import_agents.waitForAbort)(abortSignal);
|
|
180
|
+
while (true) {
|
|
181
|
+
const result = await Promise.race([iterator.next(), abortPromise]);
|
|
182
|
+
if (result === void 0) return;
|
|
183
|
+
if (result.done) {
|
|
184
|
+
hasEnded = true;
|
|
185
|
+
} else {
|
|
186
|
+
const data = result.value;
|
|
187
|
+
const frames = [];
|
|
188
|
+
if (data === SpeechStream.FLUSH_SENTINEL) {
|
|
189
|
+
frames.push(...audioBstream.flush());
|
|
190
|
+
} else {
|
|
191
|
+
frames.push(...audioBstream.write(data.data));
|
|
192
|
+
}
|
|
193
|
+
for (const frame of frames) {
|
|
194
|
+
this.#speechDuration += (0, import_agents.calculateAudioDurationSeconds)(frame);
|
|
195
|
+
if (ws.readyState === import_ws.WebSocket.OPEN) {
|
|
196
|
+
ws.send(frame.data);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (hasEnded) break;
|
|
201
|
+
}
|
|
202
|
+
if (ws.readyState === import_ws.WebSocket.OPEN) {
|
|
203
|
+
this.#closingWs = true;
|
|
204
|
+
this.#logger.debug("Sending close message to Cartesia STT");
|
|
205
|
+
ws.send(JSON.stringify({ type: "close" }));
|
|
206
|
+
const drainTimer = setTimeout(() => {
|
|
207
|
+
this.#logger.warn(
|
|
208
|
+
`Cartesia STT did not close within ${DRAIN_TIMEOUT_MS}ms after done; forcing close`
|
|
209
|
+
);
|
|
210
|
+
if (ws.readyState === import_ws.WebSocket.OPEN || ws.readyState === import_ws.WebSocket.CLOSING) {
|
|
211
|
+
ws.terminate();
|
|
212
|
+
}
|
|
213
|
+
}, DRAIN_TIMEOUT_MS);
|
|
214
|
+
ws.once("close", () => clearTimeout(drainTimer));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async #recvTask(ws) {
|
|
218
|
+
let pendingError = void 0;
|
|
219
|
+
return new Promise((resolve, reject) => {
|
|
220
|
+
const settle = (err) => {
|
|
221
|
+
if (err) reject(err);
|
|
222
|
+
else resolve();
|
|
223
|
+
};
|
|
224
|
+
ws.on("message", (data, isBinary) => {
|
|
225
|
+
if (isBinary) {
|
|
226
|
+
this.#logger.warn("Received unexpected binary message from Cartesia STT");
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
let msg;
|
|
230
|
+
try {
|
|
231
|
+
msg = JSON.parse(data.toString());
|
|
232
|
+
} catch (error) {
|
|
233
|
+
this.#logger.error("Failed to parse Cartesia STT message", { error });
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
if (msg.type === "error") {
|
|
238
|
+
this.#logger.error("Cartesia sent an error", msg);
|
|
239
|
+
if (msg.status_code === void 0 || msg.status_code >= 500) {
|
|
240
|
+
pendingError = new import_agents.APIConnectionError({
|
|
241
|
+
message: msg.message || msg.title,
|
|
242
|
+
options: {
|
|
243
|
+
retryable: true
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
ws.close();
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
this.#processStreamEvent(msg);
|
|
251
|
+
}
|
|
252
|
+
} catch (error) {
|
|
253
|
+
this.#logger.error("Failed to process Cartesia STT message", { error });
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
ws.on("close", (code, reason) => {
|
|
257
|
+
if (this.#speaking) {
|
|
258
|
+
if (this.#currentTranscript) {
|
|
259
|
+
this.#sendTranscriptEvent(
|
|
260
|
+
import_agents.stt.SpeechEventType.FINAL_TRANSCRIPT,
|
|
261
|
+
this.#currentTranscript
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
if (!this.queue.closed)
|
|
265
|
+
this.queue.put({
|
|
266
|
+
type: import_agents.stt.SpeechEventType.END_OF_SPEECH,
|
|
267
|
+
requestId: this.#requestId
|
|
268
|
+
});
|
|
269
|
+
this.#logger.debug("Cartesia STT END_OF_SPEECH");
|
|
270
|
+
if (this.#speechDuration > 0 && !this.queue.closed) {
|
|
271
|
+
this.queue.put({
|
|
272
|
+
type: import_agents.stt.SpeechEventType.RECOGNITION_USAGE,
|
|
273
|
+
requestId: this.#requestId,
|
|
274
|
+
recognitionUsage: { audioDuration: this.#speechDuration }
|
|
275
|
+
});
|
|
276
|
+
this.#speechDuration = 0;
|
|
277
|
+
}
|
|
278
|
+
this.#speaking = false;
|
|
279
|
+
this.#currentTranscript = "";
|
|
280
|
+
}
|
|
281
|
+
if (pendingError) {
|
|
282
|
+
settle(pendingError);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (this.#closingWs || this.closed) {
|
|
286
|
+
settle();
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
this.#logger.warn(`Cartesia STT WebSocket closed: ${code} ${reason.toString()}`);
|
|
290
|
+
settle(
|
|
291
|
+
new import_agents.APIConnectionError({
|
|
292
|
+
message: `Cartesia STT connection closed unexpectedly (code=${code})`,
|
|
293
|
+
options: { retryable: true }
|
|
294
|
+
})
|
|
295
|
+
);
|
|
296
|
+
});
|
|
297
|
+
ws.on("error", (err) => {
|
|
298
|
+
if (this.closed) {
|
|
299
|
+
settle();
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
settle(new import_agents.APIConnectionError({ message: err.message, options: { retryable: true } }));
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
#processStreamEvent(data) {
|
|
307
|
+
if (data.request_id) {
|
|
308
|
+
this.#requestId = data.request_id;
|
|
309
|
+
}
|
|
310
|
+
switch (data.type) {
|
|
311
|
+
case "connected":
|
|
312
|
+
return;
|
|
313
|
+
case "turn.start": {
|
|
314
|
+
if (this.#speaking) return;
|
|
315
|
+
this.#speaking = true;
|
|
316
|
+
this.#currentTranscript = "";
|
|
317
|
+
if (!this.queue.closed)
|
|
318
|
+
this.queue.put({
|
|
319
|
+
type: import_agents.stt.SpeechEventType.START_OF_SPEECH,
|
|
320
|
+
requestId: this.#requestId
|
|
321
|
+
});
|
|
322
|
+
this.#logger.debug("Cartesia STT START_OF_SPEECH");
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
case "turn.update": {
|
|
326
|
+
if (!this.#speaking) return;
|
|
327
|
+
const transcript = data.transcript;
|
|
328
|
+
if (!transcript) return;
|
|
329
|
+
if (this.#currentTranscript === transcript) return;
|
|
330
|
+
this.#currentTranscript = transcript;
|
|
331
|
+
this.#sendTranscriptEvent(import_agents.stt.SpeechEventType.INTERIM_TRANSCRIPT, transcript);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
case "turn.eager_end": {
|
|
335
|
+
if (!this.#speaking) return;
|
|
336
|
+
const transcript = data.transcript;
|
|
337
|
+
if (!transcript) return;
|
|
338
|
+
this.#currentTranscript = transcript;
|
|
339
|
+
this.#sendTranscriptEvent(import_agents.stt.SpeechEventType.PREFLIGHT_TRANSCRIPT, transcript);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
case "turn.resume":
|
|
343
|
+
if (!this.#speaking || !this.#currentTranscript) return;
|
|
344
|
+
this.#sendTranscriptEvent(import_agents.stt.SpeechEventType.INTERIM_TRANSCRIPT, this.#currentTranscript);
|
|
345
|
+
return;
|
|
346
|
+
case "turn.end": {
|
|
347
|
+
if (!this.#speaking) return;
|
|
348
|
+
const transcript = data.transcript;
|
|
349
|
+
this.#sendTranscriptEvent(import_agents.stt.SpeechEventType.FINAL_TRANSCRIPT, transcript);
|
|
350
|
+
this.#speaking = false;
|
|
351
|
+
if (!this.queue.closed)
|
|
352
|
+
this.queue.put({
|
|
353
|
+
type: import_agents.stt.SpeechEventType.END_OF_SPEECH,
|
|
354
|
+
requestId: this.#requestId
|
|
355
|
+
});
|
|
356
|
+
this.#logger.debug("Cartesia STT END_OF_SPEECH");
|
|
357
|
+
this.#currentTranscript = "";
|
|
358
|
+
if (this.#speechDuration > 0 && !this.queue.closed) {
|
|
359
|
+
this.queue.put({
|
|
360
|
+
type: import_agents.stt.SpeechEventType.RECOGNITION_USAGE,
|
|
361
|
+
requestId: this.#requestId,
|
|
362
|
+
recognitionUsage: { audioDuration: this.#speechDuration }
|
|
363
|
+
});
|
|
364
|
+
this.#speechDuration = 0;
|
|
365
|
+
}
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
default:
|
|
369
|
+
this.#logger.warn("received unexpected message from Cartesia STT", { data });
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
#sendTranscriptEvent(eventType, transcript) {
|
|
373
|
+
if (this.queue.closed) return;
|
|
374
|
+
this.queue.put({
|
|
375
|
+
type: eventType,
|
|
376
|
+
requestId: this.#requestId,
|
|
377
|
+
alternatives: [
|
|
378
|
+
{
|
|
379
|
+
// Cartesia STT only supports English at this time.
|
|
380
|
+
language: (0, import_agents.asLanguageCode)("en"),
|
|
381
|
+
text: transcript,
|
|
382
|
+
startTime: 0,
|
|
383
|
+
endTime: 0,
|
|
384
|
+
confidence: 0
|
|
385
|
+
}
|
|
386
|
+
]
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
#getCartesiaUrl() {
|
|
390
|
+
const params = new URLSearchParams({
|
|
391
|
+
model: this.#opts.model,
|
|
392
|
+
sample_rate: this.#opts.sampleRate.toString(),
|
|
393
|
+
encoding: import_models.AUDIO_ENCODING
|
|
394
|
+
});
|
|
395
|
+
const wsBase = this.#opts.baseUrl.replace(/^http/, "ws");
|
|
396
|
+
return `${wsBase}/stt/turns/websocket?${params.toString()}`;
|
|
397
|
+
}
|
|
398
|
+
close() {
|
|
399
|
+
var _a;
|
|
400
|
+
super.close();
|
|
401
|
+
(_a = this.#ws) == null ? void 0 : _a.close();
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
405
|
+
0 && (module.exports = {
|
|
406
|
+
STT,
|
|
407
|
+
SpeechStream
|
|
408
|
+
});
|
|
409
|
+
//# sourceMappingURL=stt.cjs.map
|
package/dist/stt.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/stt.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport {\n type APIConnectOptions,\n APIConnectionError,\n AudioByteStream,\n asLanguageCode,\n calculateAudioDurationSeconds,\n log,\n stt,\n waitForAbort,\n} from '@livekit/agents';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport type { IncomingMessage } from 'node:http';\nimport { WebSocket } from 'ws';\nimport { AUDIO_ENCODING, type STTModel } from './models.js';\n\nconst AUTHORIZATION_HEADER = 'X-API-Key';\nconst VERSION_HEADER = 'Cartesia-Version';\nconst REQUEST_ID_HEADER = 'cartesia-request-id';\nconst API_VERSION = '2026-03-01';\nconst DRAIN_TIMEOUT_MS = 5000;\nconst KEEPALIVE_INTERVAL_MS = 30000;\n\n/**\n * Fires once when the WebSocket connection is established.\n *\n * You do not need to wait for this event before sending audio.\n */\ntype STTConnectedEvent = {\n type: 'connected';\n /**\n * Unique identifier for this connection. Does not change between turns.\n */\n request_id: string;\n};\n\n/**\n * Model predicts {@link stt.SpeechEventType.START_OF_SPEECH}.\n */\ntype STTTurnStartEvent = {\n type: 'turn.start';\n /**\n * Unique identifier for this connection. Does not change between turns.\n */\n request_id: string;\n};\n\n/**\n * Fires repeatedly as the model transcribes the current user turn.\n *\n * Can be used for {@link stt.SpeechEventType.INTERIM_TRANSCRIPT}.\n */\ntype STTTurnUpdateEvent = {\n type: 'turn.update';\n /**\n * Cumulative text for the current turn, i.e. the full text transcribed so far in this turn, not a delta.\n */\n transcript: string;\n /**\n * Unique identifier for this connection. Does not change between turns.\n */\n request_id: string;\n};\n\n/**\n * Fires when the model predicts that the user might be done speaking.\n *\n * Can be used for {@link stt.SpeechEventType.PREFLIGHT_TRANSCRIPT}.\n */\ntype STTTurnEagerEndEvent = {\n type: 'turn.eager_end';\n /**\n * Cumulative text for the current turn, i.e. the full text transcribed so far in this turn, not a delta.\n */\n transcript: string;\n /**\n * Unique identifier for this connection. Does not change between turns.\n */\n request_id: string;\n};\n\n/**\n * Fires after {@link STTTurnEagerEndEvent} if the user turn has not actually ended.\n */\ntype STTTurnResumeEvent = {\n type: 'turn.resume';\n /**\n * Unique identifier for this connection. Does not change between turns.\n */\n request_id: string;\n};\n\n/**\n * Marks the end of a user turn.\n *\n * This is used for {@link stt.SpeechEventType.END_OF_SPEECH} and {@link stt.SpeechEventType.FINAL_TRANSCRIPT}.\n */\ntype STTTurnEndEvent = {\n type: 'turn.end';\n /**\n * Cumulative text for the current turn, i.e. the full text transcribed so far in this turn, not a delta.\n */\n transcript: string;\n /**\n * Unique identifier for this connection. Does not change between turns.\n */\n request_id: string;\n};\n\ntype STTErrorEvent = {\n type: 'error';\n error_code?: string;\n status_code?: number;\n title?: string;\n message?: string;\n doc_url?: string;\n request_id?: string;\n};\n\n/**\n * Server-sent event on the `/stt/turns/websocket` endpoint.\n *\n * See https://docs.cartesia.ai/api-reference/stt/turns/websocket.\n */\ntype STTEventMessage =\n | STTConnectedEvent\n | STTTurnStartEvent\n | STTTurnUpdateEvent\n | STTTurnEagerEndEvent\n | STTTurnResumeEvent\n | STTTurnEndEvent\n | STTErrorEvent;\n\nexport type STTOptions = {\n apiKey: string;\n // eslint-disable-next-line @typescript-eslint/ban-types\n model: STTModel | (string & {});\n sampleRate: number;\n baseUrl: string;\n audioChunkDurationMS: number;\n};\n\nconst defaultSTTOptions = {\n model: 'ink-2' satisfies STTModel,\n /** recommended default */\n sampleRate: 16_000,\n /** recommended default */\n audioChunkDurationMS: 160,\n baseUrl: 'https://api.cartesia.ai',\n};\n\nfunction mergeSTTOptions(base: STTOptions, override: Partial<STTOptions>): STTOptions {\n return {\n apiKey: override.apiKey ?? base.apiKey,\n baseUrl: override.baseUrl ?? base.baseUrl,\n model: override.model ?? base.model,\n sampleRate: override.sampleRate ?? base.sampleRate,\n audioChunkDurationMS: override.audioChunkDurationMS ?? base.audioChunkDurationMS,\n };\n}\n\n/**\n * Cartesia speech to text.\n *\n * Supports:\n * - Streaming\n * - Turn detection\n * - Interim results\n *\n * See https://docs.cartesia.ai/build-with-cartesia/stt-models/latest\n *\n * @example\n * ```typescript\n * import { voice } from '@livekit/agents';\n * import { STT, TTS } from '@livekit/agents-plugin-cartesia';\n *\n * const session = new voice.AgentSession({\n * stt: new STT(),\n * llm: new LLM(), // choose your favorite LLM\n * tts: new TTS(),\n * turnHandling: { turnDetection: 'stt' },\n * });\n * ```\n */\nexport class STT extends stt.STT {\n #opts: STTOptions;\n\n constructor(opts: Partial<STTOptions> = {}) {\n super({\n streaming: true,\n interimResults: true,\n alignedTranscript: false,\n diarization: false,\n });\n\n const apiKey = opts.apiKey ?? process.env.CARTESIA_API_KEY;\n if (!apiKey) {\n throw new Error(\n 'Cartesia API key is required, whether as an argument or as $CARTESIA_API_KEY',\n );\n }\n\n this.#opts = mergeSTTOptions({ ...defaultSTTOptions, apiKey }, opts);\n }\n\n override get label(): string {\n return 'cartesia.STT';\n }\n\n override get model(): string {\n return this.#opts.model;\n }\n\n override get provider(): string {\n return 'Cartesia';\n }\n\n protected override async _recognize(): Promise<stt.SpeechEvent> {\n throw new Error('Cartesia STT does not support batch recognition, use stream() instead');\n }\n\n override stream(options?: { connOptions?: APIConnectOptions }): SpeechStream {\n return new SpeechStream(this, this.#opts, options?.connOptions);\n }\n}\n\nexport class SpeechStream extends stt.SpeechStream {\n #opts: STTOptions;\n #logger = log();\n #ws: WebSocket | null = null;\n #requestId: string | undefined;\n #speaking = false;\n #currentTranscript = '';\n #speechDuration = 0;\n #closingWs = false;\n\n constructor(sttInstance: STT, opts: STTOptions, connOptions?: APIConnectOptions) {\n super(sttInstance, opts.sampleRate, connOptions);\n this.#opts = { ...opts };\n }\n\n override get label(): string {\n return 'cartesia.SpeechStream';\n }\n\n protected override async run() {\n if (this.closed) {\n this.close();\n return;\n }\n\n this.#speaking = false;\n this.#currentTranscript = '';\n this.#speechDuration = 0;\n this.#closingWs = false;\n\n let keepaliveInterval: NodeJS.Timeout | undefined;\n const abortController = new AbortController();\n\n try {\n const url = this.#getCartesiaUrl();\n this.#logger.debug(`Connecting to Cartesia STT: ${url}`);\n\n const ws = new WebSocket(url, {\n headers: {\n [AUTHORIZATION_HEADER]: this.#opts.apiKey,\n [VERSION_HEADER]: API_VERSION,\n },\n });\n this.#ws = ws;\n\n // Cartesia returns the request id on the WS upgrade response, before any\n // turn events are sent. Capture it so logs and metrics emitted on the\n // connection (and any pre-`turn.start` errors) are attributable.\n ws.once('upgrade', (response: IncomingMessage) => {\n const headerValue = response.headers[REQUEST_ID_HEADER];\n const requestId = Array.isArray(headerValue) ? headerValue[0] : headerValue;\n if (requestId) {\n this.#requestId = requestId;\n this.#logger.debug({ cartesiaRequestId: requestId }, 'Cartesia STT WebSocket connected');\n }\n });\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n ws.off('error', onError);\n resolve();\n };\n const onError = (err: Error) => {\n ws.off('open', onOpen);\n reject(new APIConnectionError({ message: err.message, options: { retryable: true } }));\n };\n\n ws.once('open', onOpen);\n ws.once('error', onError);\n });\n\n // If one task fails, abort its peer and close the WS so the peer can\n // exit before we re-throw. Otherwise a dangling task would survive\n // into the next retry attempt (sendTask blocked on input.next() would\n // steal frames; recvTask's close handler could still push events to\n // the queue and surface an unhandled rejection).\n let firstError: unknown;\n const stopPeer = (err: unknown) => {\n if (firstError === undefined) firstError = err;\n abortController.abort();\n if (ws.readyState === WebSocket.OPEN) ws.close();\n };\n const sendPromise = this.#sendTask(ws, abortController.signal).catch(stopPeer);\n const recvPromise = this.#recvTask(ws).catch(stopPeer);\n\n keepaliveInterval = setInterval(() => {\n try {\n if (ws.readyState === WebSocket.OPEN) {\n ws.ping();\n }\n } catch {\n // ignore\n }\n }, KEEPALIVE_INTERVAL_MS);\n await Promise.all([sendPromise, recvPromise]);\n if (firstError !== undefined) throw firstError;\n } catch (error) {\n this.#logger.error('Cartesia STT stream error', { error });\n throw error;\n } finally {\n abortController.abort();\n if (keepaliveInterval) clearInterval(keepaliveInterval);\n if (this.#ws?.readyState === WebSocket.OPEN) {\n this.#ws.close();\n }\n }\n\n this.close();\n }\n\n async #sendTask(ws: WebSocket, abortSignal: AbortSignal) {\n const samplesPerChunk = Math.floor(\n (this.#opts.sampleRate * this.#opts.audioChunkDurationMS) / 1000,\n );\n const audioBstream = new AudioByteStream(this.#opts.sampleRate, 1, samplesPerChunk);\n\n let hasEnded = false;\n const iterator = this.input[Symbol.asyncIterator]();\n const abortPromise = waitForAbort(abortSignal);\n\n while (true) {\n const result = await Promise.race([iterator.next(), abortPromise]);\n\n if (result === undefined) return; // aborted\n\n if (result.done) {\n hasEnded = true;\n } else {\n const data = result.value;\n const frames: AudioFrame[] = [];\n\n if (data === SpeechStream.FLUSH_SENTINEL) {\n frames.push(...audioBstream.flush());\n } else {\n // Pass the typed array directly so AudioByteStream uses byteOffset/\n // byteLength — `.buffer` would include foreign bytes when rtc-node\n // hands us a view over a pooled allocator.\n frames.push(...audioBstream.write(data.data));\n }\n\n for (const frame of frames) {\n this.#speechDuration += calculateAudioDurationSeconds(frame);\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(frame.data);\n }\n }\n }\n\n if (hasEnded) break;\n }\n\n if (ws.readyState === WebSocket.OPEN) {\n this.#closingWs = true;\n this.#logger.debug('Sending close message to Cartesia STT');\n ws.send(JSON.stringify({ type: 'close' }));\n\n // After `close`, the server should flush any pending turn events and\n // close the socket. If it hangs, force the issue rather than letting\n // the stream wait forever.\n const drainTimer = setTimeout(() => {\n this.#logger.warn(\n `Cartesia STT did not close within ${DRAIN_TIMEOUT_MS}ms after done; forcing close`,\n );\n if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CLOSING) {\n ws.terminate();\n }\n }, DRAIN_TIMEOUT_MS);\n ws.once('close', () => clearTimeout(drainTimer));\n }\n }\n\n async #recvTask(ws: WebSocket) {\n let pendingError: Error | undefined = undefined;\n\n return new Promise<void>((resolve, reject) => {\n const settle = (err?: Error) => {\n if (err) reject(err);\n else resolve();\n };\n\n ws.on('message', (data: Buffer, isBinary: boolean) => {\n if (isBinary) {\n this.#logger.warn('Received unexpected binary message from Cartesia STT');\n return;\n }\n let msg: STTEventMessage;\n try {\n msg = JSON.parse(data.toString());\n } catch (error) {\n this.#logger.error('Failed to parse Cartesia STT message', { error });\n return;\n }\n try {\n if (msg.type === 'error') {\n this.#logger.error('Cartesia sent an error', msg);\n\n // do not close the websocket on bad requests since that may be caused by invalid messages\n if (msg.status_code === undefined || msg.status_code >= 500) {\n // Defer until the WS is fully closed so we don't race the `close`\n // handler with a rejected `recvTask`. Close the socket explicitly\n // in case the server doesn't, otherwise recv would hang.\n pendingError = new APIConnectionError({\n message: msg.message || msg.title,\n options: {\n retryable: true,\n },\n });\n ws.close();\n return;\n }\n } else {\n this.#processStreamEvent(msg);\n }\n } catch (error) {\n this.#logger.error('Failed to process Cartesia STT message', { error });\n }\n });\n\n ws.on('close', (code, reason) => {\n // If a turn was in progress, close it out so consumers see a balanced\n // START_OF_SPEECH/END_OF_SPEECH pair and don't carry stale turn state\n // into the next reconnect.\n if (this.#speaking) {\n if (this.#currentTranscript) {\n this.#sendTranscriptEvent(\n stt.SpeechEventType.FINAL_TRANSCRIPT,\n this.#currentTranscript,\n );\n }\n if (!this.queue.closed)\n this.queue.put({\n type: stt.SpeechEventType.END_OF_SPEECH,\n requestId: this.#requestId,\n });\n this.#logger.debug('Cartesia STT END_OF_SPEECH');\n if (this.#speechDuration > 0 && !this.queue.closed) {\n this.queue.put({\n type: stt.SpeechEventType.RECOGNITION_USAGE,\n requestId: this.#requestId,\n recognitionUsage: { audioDuration: this.#speechDuration },\n });\n this.#speechDuration = 0;\n }\n this.#speaking = false;\n this.#currentTranscript = '';\n }\n\n if (pendingError) {\n settle(pendingError);\n return;\n }\n if (this.#closingWs || this.closed) {\n settle();\n return;\n }\n this.#logger.warn(`Cartesia STT WebSocket closed: ${code} ${reason.toString()}`);\n settle(\n new APIConnectionError({\n message: `Cartesia STT connection closed unexpectedly (code=${code})`,\n options: { retryable: true },\n }),\n );\n });\n\n ws.on('error', (err) => {\n if (this.closed) {\n settle();\n return;\n }\n settle(new APIConnectionError({ message: err.message, options: { retryable: true } }));\n });\n });\n }\n\n #processStreamEvent(data: Exclude<STTEventMessage, { type: 'error' }>) {\n if (data.request_id) {\n this.#requestId = data.request_id;\n }\n\n switch (data.type) {\n case 'connected':\n return;\n\n case 'turn.start': {\n if (this.#speaking) return;\n this.#speaking = true;\n this.#currentTranscript = '';\n if (!this.queue.closed)\n this.queue.put({\n type: stt.SpeechEventType.START_OF_SPEECH,\n requestId: this.#requestId,\n });\n this.#logger.debug('Cartesia STT START_OF_SPEECH');\n return;\n }\n\n case 'turn.update': {\n if (!this.#speaking) return;\n const transcript = data.transcript;\n if (!transcript) return;\n // Only emit interim updates when the cumulative transcript actually\n // changed; this avoids canceling preflight generation needlessly.\n if (this.#currentTranscript === transcript) return;\n this.#currentTranscript = transcript;\n this.#sendTranscriptEvent(stt.SpeechEventType.INTERIM_TRANSCRIPT, transcript);\n return;\n }\n\n case 'turn.eager_end': {\n if (!this.#speaking) return;\n const transcript = data.transcript;\n if (!transcript) return;\n this.#currentTranscript = transcript;\n this.#sendTranscriptEvent(stt.SpeechEventType.PREFLIGHT_TRANSCRIPT, transcript);\n return;\n }\n\n case 'turn.resume':\n // turn.resume has no transcript; re-emit the latest cumulative transcript\n // as an interim event so the pipeline cancels the pending preflight.\n if (!this.#speaking || !this.#currentTranscript) return;\n this.#sendTranscriptEvent(stt.SpeechEventType.INTERIM_TRANSCRIPT, this.#currentTranscript);\n return;\n\n case 'turn.end': {\n if (!this.#speaking) return;\n const transcript = data.transcript;\n\n this.#sendTranscriptEvent(stt.SpeechEventType.FINAL_TRANSCRIPT, transcript);\n\n this.#speaking = false;\n if (!this.queue.closed)\n this.queue.put({\n type: stt.SpeechEventType.END_OF_SPEECH,\n requestId: this.#requestId,\n });\n this.#logger.debug('Cartesia STT END_OF_SPEECH');\n this.#currentTranscript = '';\n\n if (this.#speechDuration > 0 && !this.queue.closed) {\n this.queue.put({\n type: stt.SpeechEventType.RECOGNITION_USAGE,\n requestId: this.#requestId,\n recognitionUsage: { audioDuration: this.#speechDuration },\n });\n this.#speechDuration = 0;\n }\n\n return;\n }\n\n default:\n this.#logger.warn('received unexpected message from Cartesia STT', { data });\n }\n }\n\n #sendTranscriptEvent(eventType: stt.SpeechEventType, transcript: string) {\n if (this.queue.closed) return;\n this.queue.put({\n type: eventType,\n requestId: this.#requestId,\n alternatives: [\n {\n // Cartesia STT only supports English at this time.\n language: asLanguageCode('en'),\n text: transcript,\n startTime: 0,\n endTime: 0,\n confidence: 0,\n },\n ],\n });\n }\n\n #getCartesiaUrl(): string {\n const params = new URLSearchParams({\n model: this.#opts.model,\n sample_rate: this.#opts.sampleRate.toString(),\n encoding: AUDIO_ENCODING,\n });\n\n const wsBase = this.#opts.baseUrl.replace(/^http/, 'ws');\n return `${wsBase}/stt/turns/websocket?${params.toString()}`;\n }\n\n override close() {\n super.close();\n this.#ws?.close();\n }\n}\n"],"mappings":"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","names":[]}
|