@livekit/agents-plugin-rime 1.0.17 → 1.0.27
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/tts.cjs +8 -5
- package/dist/tts.cjs.map +1 -1
- package/dist/tts.d.cts +5 -3
- package/dist/tts.d.ts +5 -3
- package/dist/tts.d.ts.map +1 -1
- package/dist/tts.js +8 -5
- package/dist/tts.js.map +1 -1
- package/package.json +6 -6
- package/src/tts.ts +18 -5
package/dist/tts.cjs
CHANGED
|
@@ -81,8 +81,8 @@ class TTS extends import_agents.tts.TTS {
|
|
|
81
81
|
* @param text - Text to synthesize
|
|
82
82
|
* @returns A chunked stream of synthesized audio
|
|
83
83
|
*/
|
|
84
|
-
synthesize(text) {
|
|
85
|
-
return new ChunkedStream(this, text, this.opts);
|
|
84
|
+
synthesize(text, connOptions, abortSignal) {
|
|
85
|
+
return new ChunkedStream(this, text, this.opts, connOptions, abortSignal);
|
|
86
86
|
}
|
|
87
87
|
stream() {
|
|
88
88
|
throw new Error("Streaming is not supported on RimeTTS");
|
|
@@ -98,9 +98,11 @@ class ChunkedStream extends import_agents.tts.ChunkedStream {
|
|
|
98
98
|
* @param tts - The parent TTS instance
|
|
99
99
|
* @param text - Text to synthesize
|
|
100
100
|
* @param opts - TTS configuration options
|
|
101
|
+
* @param connOptions - API connection options
|
|
102
|
+
* @param abortSignal - Abort signal for cancellation
|
|
101
103
|
*/
|
|
102
|
-
constructor(tts2, text, opts) {
|
|
103
|
-
super(text, tts2);
|
|
104
|
+
constructor(tts2, text, opts, connOptions, abortSignal) {
|
|
105
|
+
super(text, tts2, connOptions, abortSignal);
|
|
104
106
|
this.text = text;
|
|
105
107
|
this.opts = opts;
|
|
106
108
|
}
|
|
@@ -118,7 +120,8 @@ class ChunkedStream extends import_agents.tts.ChunkedStream {
|
|
|
118
120
|
Object.entries(this.opts).filter(([k]) => !["apiKey", "baseURL"].includes(k))
|
|
119
121
|
),
|
|
120
122
|
text: this.text
|
|
121
|
-
})
|
|
123
|
+
}),
|
|
124
|
+
signal: this.abortSignal
|
|
122
125
|
});
|
|
123
126
|
if (!response.ok) {
|
|
124
127
|
throw new Error(`Rime AI TTS request failed: ${response.status} ${response.statusText}`);
|
package/dist/tts.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tts.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AudioByteStream, shortuuid, tts } from '@livekit/agents';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport type { DefaultLanguages, TTSModels } from './models.js';\n\nconst RIME_BASE_URL = 'https://users.rime.ai/v1/rime-tts';\nconst RIME_TTS_SAMPLE_RATE = 24000;\nconst RIME_TTS_CHANNELS = 1;\n\n/**\n * Get the appropriate sample rate based on TTS options.\n *\n * @param opts - Optional TTS configuration options\n * @returns The sample rate in Hz. Returns the explicit samplingRate if provided,\n * otherwise returns model-specific defaults (24000 for arcana, 16000 for mistv2,\n * or the default RIME_TTS_SAMPLE_RATE for other models)\n */\nfunction getSampleRate(opts?: Partial<TTSOptions>): number {\n if (opts?.samplingRate && typeof opts.samplingRate === 'number') {\n return opts.samplingRate;\n }\n switch (opts?.modelId) {\n case 'arcana':\n return 24000;\n case 'mistv2':\n return 16000;\n default:\n return RIME_TTS_SAMPLE_RATE;\n }\n}\n\n/** Configuration options for Rime AI TTS */\nexport interface TTSOptions {\n speaker: string;\n modelId: TTSModels | string;\n baseURL?: string;\n apiKey?: string;\n lang?: DefaultLanguages | string;\n repetition_penalty?: number;\n temperature?: number;\n top_p?: number;\n max_tokens?: number;\n samplingRate?: number;\n speedAlpha?: number;\n pauseBetweenBrackets?: boolean;\n phonemizeBetweenBrackets?: boolean;\n inlineSpeedAlpha?: string;\n noTextNormalization?: boolean;\n saveOovs?: boolean;\n /** Additional Rime API parameters */\n [key: string]: string | number | boolean | undefined;\n}\n\nconst defaultTTSOptions: TTSOptions = {\n modelId: 'arcana',\n speaker: 'luna',\n apiKey: process.env.RIME_API_KEY,\n baseURL: RIME_BASE_URL,\n};\n\nexport class TTS extends tts.TTS {\n private opts: TTSOptions;\n label = 'rime.TTS';\n\n /**\n * Create a new instance of Rime TTS.\n *\n * @remarks\n * `apiKey` must be set to your Rime AI API key, either using the argument or by setting the\n * `RIME_API_KEY` environmental variable.\n *\n * @param opts - Configuration options for the TTS instance\n */\n\n constructor(opts: Partial<TTSOptions> = defaultTTSOptions) {\n const sampleRate = getSampleRate(opts);\n super(sampleRate, RIME_TTS_CHANNELS, {\n streaming: false,\n });\n\n this.opts = { ...defaultTTSOptions, ...opts };\n if (this.opts.apiKey === undefined) {\n throw new Error('RIME API key is required, whether as an argument or as $RIME_API_KEY');\n }\n }\n\n /**\n * Update TTS options after initialization\n *\n * @param opts - Partial options to update\n */\n updateOptions(opts: Partial<TTSOptions>) {\n this.opts = { ...this.opts, ...opts };\n }\n\n /**\n * Synthesize text to audio using Rime AI TTS.\n *\n * @param text - Text to synthesize\n * @returns A chunked stream of synthesized audio\n */\n synthesize(text: string): ChunkedStream {\n return new ChunkedStream(this, text, this.opts);\n }\n\n stream(): tts.SynthesizeStream {\n throw new Error('Streaming is not supported on RimeTTS');\n }\n}\n\nexport class ChunkedStream extends tts.ChunkedStream {\n label = 'rime-tts.ChunkedStream';\n private opts: TTSOptions;\n private text: string;\n\n /**\n * Create a new ChunkedStream instance.\n *\n * @param tts - The parent TTS instance\n * @param text - Text to synthesize\n * @param opts - TTS configuration options\n */\n constructor(tts: TTS
|
|
1
|
+
{"version":3,"sources":["../src/tts.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { type APIConnectOptions, AudioByteStream, shortuuid, tts } from '@livekit/agents';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport type { DefaultLanguages, TTSModels } from './models.js';\n\nconst RIME_BASE_URL = 'https://users.rime.ai/v1/rime-tts';\nconst RIME_TTS_SAMPLE_RATE = 24000;\nconst RIME_TTS_CHANNELS = 1;\n\n/**\n * Get the appropriate sample rate based on TTS options.\n *\n * @param opts - Optional TTS configuration options\n * @returns The sample rate in Hz. Returns the explicit samplingRate if provided,\n * otherwise returns model-specific defaults (24000 for arcana, 16000 for mistv2,\n * or the default RIME_TTS_SAMPLE_RATE for other models)\n */\nfunction getSampleRate(opts?: Partial<TTSOptions>): number {\n if (opts?.samplingRate && typeof opts.samplingRate === 'number') {\n return opts.samplingRate;\n }\n switch (opts?.modelId) {\n case 'arcana':\n return 24000;\n case 'mistv2':\n return 16000;\n default:\n return RIME_TTS_SAMPLE_RATE;\n }\n}\n\n/** Configuration options for Rime AI TTS */\nexport interface TTSOptions {\n speaker: string;\n modelId: TTSModels | string;\n baseURL?: string;\n apiKey?: string;\n lang?: DefaultLanguages | string;\n repetition_penalty?: number;\n temperature?: number;\n top_p?: number;\n max_tokens?: number;\n samplingRate?: number;\n speedAlpha?: number;\n pauseBetweenBrackets?: boolean;\n phonemizeBetweenBrackets?: boolean;\n inlineSpeedAlpha?: string;\n noTextNormalization?: boolean;\n saveOovs?: boolean;\n /** Additional Rime API parameters */\n [key: string]: string | number | boolean | undefined;\n}\n\nconst defaultTTSOptions: TTSOptions = {\n modelId: 'arcana',\n speaker: 'luna',\n apiKey: process.env.RIME_API_KEY,\n baseURL: RIME_BASE_URL,\n};\n\nexport class TTS extends tts.TTS {\n private opts: TTSOptions;\n label = 'rime.TTS';\n\n /**\n * Create a new instance of Rime TTS.\n *\n * @remarks\n * `apiKey` must be set to your Rime AI API key, either using the argument or by setting the\n * `RIME_API_KEY` environmental variable.\n *\n * @param opts - Configuration options for the TTS instance\n */\n\n constructor(opts: Partial<TTSOptions> = defaultTTSOptions) {\n const sampleRate = getSampleRate(opts);\n super(sampleRate, RIME_TTS_CHANNELS, {\n streaming: false,\n });\n\n this.opts = { ...defaultTTSOptions, ...opts };\n if (this.opts.apiKey === undefined) {\n throw new Error('RIME API key is required, whether as an argument or as $RIME_API_KEY');\n }\n }\n\n /**\n * Update TTS options after initialization\n *\n * @param opts - Partial options to update\n */\n updateOptions(opts: Partial<TTSOptions>) {\n this.opts = { ...this.opts, ...opts };\n }\n\n /**\n * Synthesize text to audio using Rime AI TTS.\n *\n * @param text - Text to synthesize\n * @returns A chunked stream of synthesized audio\n */\n synthesize(\n text: string,\n connOptions?: APIConnectOptions,\n abortSignal?: AbortSignal,\n ): ChunkedStream {\n return new ChunkedStream(this, text, this.opts, connOptions, abortSignal);\n }\n\n stream(): tts.SynthesizeStream {\n throw new Error('Streaming is not supported on RimeTTS');\n }\n}\n\nexport class ChunkedStream extends tts.ChunkedStream {\n label = 'rime-tts.ChunkedStream';\n private opts: TTSOptions;\n private text: string;\n\n /**\n * Create a new ChunkedStream instance.\n *\n * @param tts - The parent TTS instance\n * @param text - Text to synthesize\n * @param opts - TTS configuration options\n * @param connOptions - API connection options\n * @param abortSignal - Abort signal for cancellation\n */\n constructor(\n tts: TTS,\n text: string,\n opts: TTSOptions,\n connOptions?: APIConnectOptions,\n abortSignal?: AbortSignal,\n ) {\n super(text, tts, connOptions, abortSignal);\n this.text = text;\n this.opts = opts;\n }\n\n protected async run() {\n const requestId = shortuuid();\n const response = await fetch(`${this.opts.baseURL}`, {\n method: 'POST',\n headers: {\n Accept: 'audio/pcm',\n Authorization: `Bearer ${this.opts.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n ...Object.fromEntries(\n Object.entries(this.opts).filter(([k]) => !['apiKey', 'baseURL'].includes(k)),\n ),\n text: this.text,\n }),\n signal: this.abortSignal,\n });\n\n if (!response.ok) {\n throw new Error(`Rime AI TTS request failed: ${response.status} ${response.statusText}`);\n }\n\n const buffer = await response.arrayBuffer();\n const sampleRate = getSampleRate(this.opts);\n const audioByteStream = new AudioByteStream(sampleRate, RIME_TTS_CHANNELS);\n const frames = audioByteStream.write(buffer);\n let lastFrame: AudioFrame | undefined;\n const sendLastFrame = (segmentId: string, final: boolean) => {\n if (lastFrame) {\n this.queue.put({ requestId, segmentId, frame: lastFrame, final });\n lastFrame = undefined;\n }\n };\n\n for (const frame of frames) {\n sendLastFrame(requestId, false);\n lastFrame = frame;\n }\n sendLastFrame(requestId, true);\n\n this.queue.close();\n }\n}\n"],"mappings":"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","names":["tts"]}
|
package/dist/tts.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { tts } from '@livekit/agents';
|
|
1
|
+
import { type APIConnectOptions, tts } from '@livekit/agents';
|
|
2
2
|
import type { DefaultLanguages, TTSModels } from './models.js';
|
|
3
3
|
/** Configuration options for Rime AI TTS */
|
|
4
4
|
export interface TTSOptions {
|
|
@@ -46,7 +46,7 @@ export declare class TTS extends tts.TTS {
|
|
|
46
46
|
* @param text - Text to synthesize
|
|
47
47
|
* @returns A chunked stream of synthesized audio
|
|
48
48
|
*/
|
|
49
|
-
synthesize(text: string): ChunkedStream;
|
|
49
|
+
synthesize(text: string, connOptions?: APIConnectOptions, abortSignal?: AbortSignal): ChunkedStream;
|
|
50
50
|
stream(): tts.SynthesizeStream;
|
|
51
51
|
}
|
|
52
52
|
export declare class ChunkedStream extends tts.ChunkedStream {
|
|
@@ -59,8 +59,10 @@ export declare class ChunkedStream extends tts.ChunkedStream {
|
|
|
59
59
|
* @param tts - The parent TTS instance
|
|
60
60
|
* @param text - Text to synthesize
|
|
61
61
|
* @param opts - TTS configuration options
|
|
62
|
+
* @param connOptions - API connection options
|
|
63
|
+
* @param abortSignal - Abort signal for cancellation
|
|
62
64
|
*/
|
|
63
|
-
constructor(tts: TTS, text: string, opts: TTSOptions);
|
|
65
|
+
constructor(tts: TTS, text: string, opts: TTSOptions, connOptions?: APIConnectOptions, abortSignal?: AbortSignal);
|
|
64
66
|
protected run(): Promise<void>;
|
|
65
67
|
}
|
|
66
68
|
//# sourceMappingURL=tts.d.ts.map
|
package/dist/tts.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { tts } from '@livekit/agents';
|
|
1
|
+
import { type APIConnectOptions, tts } from '@livekit/agents';
|
|
2
2
|
import type { DefaultLanguages, TTSModels } from './models.js';
|
|
3
3
|
/** Configuration options for Rime AI TTS */
|
|
4
4
|
export interface TTSOptions {
|
|
@@ -46,7 +46,7 @@ export declare class TTS extends tts.TTS {
|
|
|
46
46
|
* @param text - Text to synthesize
|
|
47
47
|
* @returns A chunked stream of synthesized audio
|
|
48
48
|
*/
|
|
49
|
-
synthesize(text: string): ChunkedStream;
|
|
49
|
+
synthesize(text: string, connOptions?: APIConnectOptions, abortSignal?: AbortSignal): ChunkedStream;
|
|
50
50
|
stream(): tts.SynthesizeStream;
|
|
51
51
|
}
|
|
52
52
|
export declare class ChunkedStream extends tts.ChunkedStream {
|
|
@@ -59,8 +59,10 @@ export declare class ChunkedStream extends tts.ChunkedStream {
|
|
|
59
59
|
* @param tts - The parent TTS instance
|
|
60
60
|
* @param text - Text to synthesize
|
|
61
61
|
* @param opts - TTS configuration options
|
|
62
|
+
* @param connOptions - API connection options
|
|
63
|
+
* @param abortSignal - Abort signal for cancellation
|
|
62
64
|
*/
|
|
63
|
-
constructor(tts: TTS, text: string, opts: TTSOptions);
|
|
65
|
+
constructor(tts: TTS, text: string, opts: TTSOptions, connOptions?: APIConnectOptions, abortSignal?: AbortSignal);
|
|
64
66
|
protected run(): Promise<void>;
|
|
65
67
|
}
|
|
66
68
|
//# sourceMappingURL=tts.d.ts.map
|
package/dist/tts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../src/tts.ts"],"names":[],"mappings":"AAGA,OAAO,EAA8B,GAAG,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../src/tts.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,iBAAiB,EAA8B,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAE1F,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AA4B/D,4CAA4C;AAC5C,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,SAAS,GAAG,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qCAAqC;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CACtD;AASD,qBAAa,GAAI,SAAQ,GAAG,CAAC,GAAG;IAC9B,OAAO,CAAC,IAAI,CAAa;IACzB,KAAK,SAAc;IAEnB;;;;;;;;OAQG;gBAES,IAAI,GAAE,OAAO,CAAC,UAAU,CAAqB;IAYzD;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC;IAIvC;;;;;OAKG;IACH,UAAU,CACR,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,iBAAiB,EAC/B,WAAW,CAAC,EAAE,WAAW,GACxB,aAAa;IAIhB,MAAM,IAAI,GAAG,CAAC,gBAAgB;CAG/B;AAED,qBAAa,aAAc,SAAQ,GAAG,CAAC,aAAa;IAClD,KAAK,SAA4B;IACjC,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,IAAI,CAAS;IAErB;;;;;;;;OAQG;gBAED,GAAG,EAAE,GAAG,EACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,WAAW,CAAC,EAAE,iBAAiB,EAC/B,WAAW,CAAC,EAAE,WAAW;cAOX,GAAG;CA0CpB"}
|
package/dist/tts.js
CHANGED
|
@@ -57,8 +57,8 @@ class TTS extends tts.TTS {
|
|
|
57
57
|
* @param text - Text to synthesize
|
|
58
58
|
* @returns A chunked stream of synthesized audio
|
|
59
59
|
*/
|
|
60
|
-
synthesize(text) {
|
|
61
|
-
return new ChunkedStream(this, text, this.opts);
|
|
60
|
+
synthesize(text, connOptions, abortSignal) {
|
|
61
|
+
return new ChunkedStream(this, text, this.opts, connOptions, abortSignal);
|
|
62
62
|
}
|
|
63
63
|
stream() {
|
|
64
64
|
throw new Error("Streaming is not supported on RimeTTS");
|
|
@@ -74,9 +74,11 @@ class ChunkedStream extends tts.ChunkedStream {
|
|
|
74
74
|
* @param tts - The parent TTS instance
|
|
75
75
|
* @param text - Text to synthesize
|
|
76
76
|
* @param opts - TTS configuration options
|
|
77
|
+
* @param connOptions - API connection options
|
|
78
|
+
* @param abortSignal - Abort signal for cancellation
|
|
77
79
|
*/
|
|
78
|
-
constructor(tts2, text, opts) {
|
|
79
|
-
super(text, tts2);
|
|
80
|
+
constructor(tts2, text, opts, connOptions, abortSignal) {
|
|
81
|
+
super(text, tts2, connOptions, abortSignal);
|
|
80
82
|
this.text = text;
|
|
81
83
|
this.opts = opts;
|
|
82
84
|
}
|
|
@@ -94,7 +96,8 @@ class ChunkedStream extends tts.ChunkedStream {
|
|
|
94
96
|
Object.entries(this.opts).filter(([k]) => !["apiKey", "baseURL"].includes(k))
|
|
95
97
|
),
|
|
96
98
|
text: this.text
|
|
97
|
-
})
|
|
99
|
+
}),
|
|
100
|
+
signal: this.abortSignal
|
|
98
101
|
});
|
|
99
102
|
if (!response.ok) {
|
|
100
103
|
throw new Error(`Rime AI TTS request failed: ${response.status} ${response.statusText}`);
|
package/dist/tts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tts.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AudioByteStream, shortuuid, tts } from '@livekit/agents';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport type { DefaultLanguages, TTSModels } from './models.js';\n\nconst RIME_BASE_URL = 'https://users.rime.ai/v1/rime-tts';\nconst RIME_TTS_SAMPLE_RATE = 24000;\nconst RIME_TTS_CHANNELS = 1;\n\n/**\n * Get the appropriate sample rate based on TTS options.\n *\n * @param opts - Optional TTS configuration options\n * @returns The sample rate in Hz. Returns the explicit samplingRate if provided,\n * otherwise returns model-specific defaults (24000 for arcana, 16000 for mistv2,\n * or the default RIME_TTS_SAMPLE_RATE for other models)\n */\nfunction getSampleRate(opts?: Partial<TTSOptions>): number {\n if (opts?.samplingRate && typeof opts.samplingRate === 'number') {\n return opts.samplingRate;\n }\n switch (opts?.modelId) {\n case 'arcana':\n return 24000;\n case 'mistv2':\n return 16000;\n default:\n return RIME_TTS_SAMPLE_RATE;\n }\n}\n\n/** Configuration options for Rime AI TTS */\nexport interface TTSOptions {\n speaker: string;\n modelId: TTSModels | string;\n baseURL?: string;\n apiKey?: string;\n lang?: DefaultLanguages | string;\n repetition_penalty?: number;\n temperature?: number;\n top_p?: number;\n max_tokens?: number;\n samplingRate?: number;\n speedAlpha?: number;\n pauseBetweenBrackets?: boolean;\n phonemizeBetweenBrackets?: boolean;\n inlineSpeedAlpha?: string;\n noTextNormalization?: boolean;\n saveOovs?: boolean;\n /** Additional Rime API parameters */\n [key: string]: string | number | boolean | undefined;\n}\n\nconst defaultTTSOptions: TTSOptions = {\n modelId: 'arcana',\n speaker: 'luna',\n apiKey: process.env.RIME_API_KEY,\n baseURL: RIME_BASE_URL,\n};\n\nexport class TTS extends tts.TTS {\n private opts: TTSOptions;\n label = 'rime.TTS';\n\n /**\n * Create a new instance of Rime TTS.\n *\n * @remarks\n * `apiKey` must be set to your Rime AI API key, either using the argument or by setting the\n * `RIME_API_KEY` environmental variable.\n *\n * @param opts - Configuration options for the TTS instance\n */\n\n constructor(opts: Partial<TTSOptions> = defaultTTSOptions) {\n const sampleRate = getSampleRate(opts);\n super(sampleRate, RIME_TTS_CHANNELS, {\n streaming: false,\n });\n\n this.opts = { ...defaultTTSOptions, ...opts };\n if (this.opts.apiKey === undefined) {\n throw new Error('RIME API key is required, whether as an argument or as $RIME_API_KEY');\n }\n }\n\n /**\n * Update TTS options after initialization\n *\n * @param opts - Partial options to update\n */\n updateOptions(opts: Partial<TTSOptions>) {\n this.opts = { ...this.opts, ...opts };\n }\n\n /**\n * Synthesize text to audio using Rime AI TTS.\n *\n * @param text - Text to synthesize\n * @returns A chunked stream of synthesized audio\n */\n synthesize(text: string): ChunkedStream {\n return new ChunkedStream(this, text, this.opts);\n }\n\n stream(): tts.SynthesizeStream {\n throw new Error('Streaming is not supported on RimeTTS');\n }\n}\n\nexport class ChunkedStream extends tts.ChunkedStream {\n label = 'rime-tts.ChunkedStream';\n private opts: TTSOptions;\n private text: string;\n\n /**\n * Create a new ChunkedStream instance.\n *\n * @param tts - The parent TTS instance\n * @param text - Text to synthesize\n * @param opts - TTS configuration options\n */\n constructor(tts: TTS
|
|
1
|
+
{"version":3,"sources":["../src/tts.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { type APIConnectOptions, AudioByteStream, shortuuid, tts } from '@livekit/agents';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport type { DefaultLanguages, TTSModels } from './models.js';\n\nconst RIME_BASE_URL = 'https://users.rime.ai/v1/rime-tts';\nconst RIME_TTS_SAMPLE_RATE = 24000;\nconst RIME_TTS_CHANNELS = 1;\n\n/**\n * Get the appropriate sample rate based on TTS options.\n *\n * @param opts - Optional TTS configuration options\n * @returns The sample rate in Hz. Returns the explicit samplingRate if provided,\n * otherwise returns model-specific defaults (24000 for arcana, 16000 for mistv2,\n * or the default RIME_TTS_SAMPLE_RATE for other models)\n */\nfunction getSampleRate(opts?: Partial<TTSOptions>): number {\n if (opts?.samplingRate && typeof opts.samplingRate === 'number') {\n return opts.samplingRate;\n }\n switch (opts?.modelId) {\n case 'arcana':\n return 24000;\n case 'mistv2':\n return 16000;\n default:\n return RIME_TTS_SAMPLE_RATE;\n }\n}\n\n/** Configuration options for Rime AI TTS */\nexport interface TTSOptions {\n speaker: string;\n modelId: TTSModels | string;\n baseURL?: string;\n apiKey?: string;\n lang?: DefaultLanguages | string;\n repetition_penalty?: number;\n temperature?: number;\n top_p?: number;\n max_tokens?: number;\n samplingRate?: number;\n speedAlpha?: number;\n pauseBetweenBrackets?: boolean;\n phonemizeBetweenBrackets?: boolean;\n inlineSpeedAlpha?: string;\n noTextNormalization?: boolean;\n saveOovs?: boolean;\n /** Additional Rime API parameters */\n [key: string]: string | number | boolean | undefined;\n}\n\nconst defaultTTSOptions: TTSOptions = {\n modelId: 'arcana',\n speaker: 'luna',\n apiKey: process.env.RIME_API_KEY,\n baseURL: RIME_BASE_URL,\n};\n\nexport class TTS extends tts.TTS {\n private opts: TTSOptions;\n label = 'rime.TTS';\n\n /**\n * Create a new instance of Rime TTS.\n *\n * @remarks\n * `apiKey` must be set to your Rime AI API key, either using the argument or by setting the\n * `RIME_API_KEY` environmental variable.\n *\n * @param opts - Configuration options for the TTS instance\n */\n\n constructor(opts: Partial<TTSOptions> = defaultTTSOptions) {\n const sampleRate = getSampleRate(opts);\n super(sampleRate, RIME_TTS_CHANNELS, {\n streaming: false,\n });\n\n this.opts = { ...defaultTTSOptions, ...opts };\n if (this.opts.apiKey === undefined) {\n throw new Error('RIME API key is required, whether as an argument or as $RIME_API_KEY');\n }\n }\n\n /**\n * Update TTS options after initialization\n *\n * @param opts - Partial options to update\n */\n updateOptions(opts: Partial<TTSOptions>) {\n this.opts = { ...this.opts, ...opts };\n }\n\n /**\n * Synthesize text to audio using Rime AI TTS.\n *\n * @param text - Text to synthesize\n * @returns A chunked stream of synthesized audio\n */\n synthesize(\n text: string,\n connOptions?: APIConnectOptions,\n abortSignal?: AbortSignal,\n ): ChunkedStream {\n return new ChunkedStream(this, text, this.opts, connOptions, abortSignal);\n }\n\n stream(): tts.SynthesizeStream {\n throw new Error('Streaming is not supported on RimeTTS');\n }\n}\n\nexport class ChunkedStream extends tts.ChunkedStream {\n label = 'rime-tts.ChunkedStream';\n private opts: TTSOptions;\n private text: string;\n\n /**\n * Create a new ChunkedStream instance.\n *\n * @param tts - The parent TTS instance\n * @param text - Text to synthesize\n * @param opts - TTS configuration options\n * @param connOptions - API connection options\n * @param abortSignal - Abort signal for cancellation\n */\n constructor(\n tts: TTS,\n text: string,\n opts: TTSOptions,\n connOptions?: APIConnectOptions,\n abortSignal?: AbortSignal,\n ) {\n super(text, tts, connOptions, abortSignal);\n this.text = text;\n this.opts = opts;\n }\n\n protected async run() {\n const requestId = shortuuid();\n const response = await fetch(`${this.opts.baseURL}`, {\n method: 'POST',\n headers: {\n Accept: 'audio/pcm',\n Authorization: `Bearer ${this.opts.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n ...Object.fromEntries(\n Object.entries(this.opts).filter(([k]) => !['apiKey', 'baseURL'].includes(k)),\n ),\n text: this.text,\n }),\n signal: this.abortSignal,\n });\n\n if (!response.ok) {\n throw new Error(`Rime AI TTS request failed: ${response.status} ${response.statusText}`);\n }\n\n const buffer = await response.arrayBuffer();\n const sampleRate = getSampleRate(this.opts);\n const audioByteStream = new AudioByteStream(sampleRate, RIME_TTS_CHANNELS);\n const frames = audioByteStream.write(buffer);\n let lastFrame: AudioFrame | undefined;\n const sendLastFrame = (segmentId: string, final: boolean) => {\n if (lastFrame) {\n this.queue.put({ requestId, segmentId, frame: lastFrame, final });\n lastFrame = undefined;\n }\n };\n\n for (const frame of frames) {\n sendLastFrame(requestId, false);\n lastFrame = frame;\n }\n sendLastFrame(requestId, true);\n\n this.queue.close();\n }\n}\n"],"mappings":"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","names":["tts"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/agents-plugin-rime",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.27",
|
|
4
4
|
"description": "Rime plugin for LiveKit Node Agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"require": "dist/index.cjs",
|
|
@@ -30,17 +30,17 @@
|
|
|
30
30
|
"@types/ws": "^8.5.10",
|
|
31
31
|
"tsup": "^8.3.5",
|
|
32
32
|
"typescript": "^5.0.0",
|
|
33
|
-
"@livekit/agents": "1.0.
|
|
34
|
-
"@livekit/agents-plugin-
|
|
35
|
-
"@livekit/agents
|
|
36
|
-
"@livekit/agents-plugins-test": "1.0.
|
|
33
|
+
"@livekit/agents-plugin-openai": "1.0.27",
|
|
34
|
+
"@livekit/agents-plugin-silero": "1.0.27",
|
|
35
|
+
"@livekit/agents": "1.0.27",
|
|
36
|
+
"@livekit/agents-plugins-test": "1.0.27"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"ws": "^8.16.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@livekit/rtc-node": "^0.13.12",
|
|
43
|
-
"@livekit/agents": "1.0.
|
|
43
|
+
"@livekit/agents": "1.0.27"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "tsup --onSuccess \"pnpm build:types\"",
|
package/src/tts.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
import { AudioByteStream, shortuuid, tts } from '@livekit/agents';
|
|
4
|
+
import { type APIConnectOptions, AudioByteStream, shortuuid, tts } from '@livekit/agents';
|
|
5
5
|
import type { AudioFrame } from '@livekit/rtc-node';
|
|
6
6
|
import type { DefaultLanguages, TTSModels } from './models.js';
|
|
7
7
|
|
|
@@ -101,8 +101,12 @@ export class TTS extends tts.TTS {
|
|
|
101
101
|
* @param text - Text to synthesize
|
|
102
102
|
* @returns A chunked stream of synthesized audio
|
|
103
103
|
*/
|
|
104
|
-
synthesize(
|
|
105
|
-
|
|
104
|
+
synthesize(
|
|
105
|
+
text: string,
|
|
106
|
+
connOptions?: APIConnectOptions,
|
|
107
|
+
abortSignal?: AbortSignal,
|
|
108
|
+
): ChunkedStream {
|
|
109
|
+
return new ChunkedStream(this, text, this.opts, connOptions, abortSignal);
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
stream(): tts.SynthesizeStream {
|
|
@@ -121,9 +125,17 @@ export class ChunkedStream extends tts.ChunkedStream {
|
|
|
121
125
|
* @param tts - The parent TTS instance
|
|
122
126
|
* @param text - Text to synthesize
|
|
123
127
|
* @param opts - TTS configuration options
|
|
128
|
+
* @param connOptions - API connection options
|
|
129
|
+
* @param abortSignal - Abort signal for cancellation
|
|
124
130
|
*/
|
|
125
|
-
constructor(
|
|
126
|
-
|
|
131
|
+
constructor(
|
|
132
|
+
tts: TTS,
|
|
133
|
+
text: string,
|
|
134
|
+
opts: TTSOptions,
|
|
135
|
+
connOptions?: APIConnectOptions,
|
|
136
|
+
abortSignal?: AbortSignal,
|
|
137
|
+
) {
|
|
138
|
+
super(text, tts, connOptions, abortSignal);
|
|
127
139
|
this.text = text;
|
|
128
140
|
this.opts = opts;
|
|
129
141
|
}
|
|
@@ -143,6 +155,7 @@ export class ChunkedStream extends tts.ChunkedStream {
|
|
|
143
155
|
),
|
|
144
156
|
text: this.text,
|
|
145
157
|
}),
|
|
158
|
+
signal: this.abortSignal,
|
|
146
159
|
});
|
|
147
160
|
|
|
148
161
|
if (!response.ok) {
|