@livekit/agents-plugin-rime 1.0.18 → 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 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, text: string, opts: TTSOptions) {\n super(text, tts);\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 });\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"]}
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;AAElE,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,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa;IAIvC,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;;;;;;OAMG;gBACS,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU;cAMpC,GAAG;CAyCpB"}
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, text: string, opts: TTSOptions) {\n super(text, tts);\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 });\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"]}
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.18",
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.25",
34
- "@livekit/agents-plugin-openai": "1.0.25",
35
- "@livekit/agents-plugin-silero": "1.0.25",
36
- "@livekit/agents-plugins-test": "1.0.25"
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.25"
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(text: string): ChunkedStream {
105
- return new ChunkedStream(this, text, this.opts);
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(tts: TTS, text: string, opts: TTSOptions) {
126
- super(text, tts);
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) {