@livekit/agents-plugin-openai 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +18 -0
  2. package/dist/index.cjs +55 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.js +13 -8
  5. package/dist/index.js.map +1 -1
  6. package/dist/llm.cjs +506 -0
  7. package/dist/llm.cjs.map +1 -0
  8. package/dist/llm.d.ts.map +1 -1
  9. package/dist/llm.js +438 -423
  10. package/dist/llm.js.map +1 -1
  11. package/dist/llm.test.cjs +8 -0
  12. package/dist/llm.test.cjs.map +1 -0
  13. package/dist/llm.test.d.ts +2 -0
  14. package/dist/llm.test.d.ts.map +1 -0
  15. package/dist/llm.test.js +7 -0
  16. package/dist/llm.test.js.map +1 -0
  17. package/dist/models.cjs +17 -0
  18. package/dist/models.cjs.map +1 -0
  19. package/dist/models.js +0 -4
  20. package/dist/models.js.map +1 -1
  21. package/dist/realtime/api_proto.cjs +41 -0
  22. package/dist/realtime/api_proto.cjs.map +1 -0
  23. package/dist/realtime/api_proto.js +12 -8
  24. package/dist/realtime/api_proto.js.map +1 -1
  25. package/dist/realtime/index.cjs +25 -0
  26. package/dist/realtime/index.cjs.map +1 -0
  27. package/dist/realtime/index.js +2 -5
  28. package/dist/realtime/index.js.map +1 -1
  29. package/dist/realtime/realtime_model.cjs +878 -0
  30. package/dist/realtime/realtime_model.cjs.map +1 -0
  31. package/dist/realtime/realtime_model.js +828 -777
  32. package/dist/realtime/realtime_model.js.map +1 -1
  33. package/dist/stt.cjs +130 -0
  34. package/dist/stt.cjs.map +1 -0
  35. package/dist/stt.js +99 -102
  36. package/dist/stt.js.map +1 -1
  37. package/dist/stt.test.cjs +9 -0
  38. package/dist/stt.test.cjs.map +1 -0
  39. package/dist/stt.test.d.ts +2 -0
  40. package/dist/stt.test.d.ts.map +1 -0
  41. package/dist/stt.test.js +8 -0
  42. package/dist/stt.test.js.map +1 -0
  43. package/dist/tts.cjs +100 -0
  44. package/dist/tts.cjs.map +1 -0
  45. package/dist/tts.d.ts +1 -1
  46. package/dist/tts.d.ts.map +1 -1
  47. package/dist/tts.js +67 -65
  48. package/dist/tts.js.map +1 -1
  49. package/dist/tts.test.cjs +9 -0
  50. package/dist/tts.test.cjs.map +1 -0
  51. package/dist/tts.test.d.ts +2 -0
  52. package/dist/tts.test.d.ts.map +1 -0
  53. package/dist/tts.test.js +8 -0
  54. package/dist/tts.test.js.map +1 -0
  55. package/package.json +20 -8
  56. package/src/llm.test.ts +10 -0
  57. package/src/llm.ts +7 -2
  58. package/src/stt.test.ts +11 -0
  59. package/src/tts.test.ts +11 -0
  60. package/src/tts.ts +2 -1
package/dist/tts.cjs ADDED
@@ -0,0 +1,100 @@
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 tts_exports = {};
20
+ __export(tts_exports, {
21
+ ChunkedStream: () => ChunkedStream,
22
+ TTS: () => TTS
23
+ });
24
+ module.exports = __toCommonJS(tts_exports);
25
+ var import_agents = require("@livekit/agents");
26
+ var import_openai = require("openai");
27
+ const OPENAI_TTS_SAMPLE_RATE = 24e3;
28
+ const OPENAI_TTS_CHANNELS = 1;
29
+ const defaultTTSOptions = {
30
+ apiKey: process.env.OPENAI_API_KEY,
31
+ model: "tts-1",
32
+ voice: "alloy",
33
+ speed: 1
34
+ };
35
+ class TTS extends import_agents.tts.TTS {
36
+ #opts;
37
+ #client;
38
+ /**
39
+ * Create a new instance of OpenAI TTS.
40
+ *
41
+ * @remarks
42
+ * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the
43
+ * `OPENAI_API_KEY` environmental variable.
44
+ */
45
+ constructor(opts = defaultTTSOptions) {
46
+ super(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS, { streaming: false });
47
+ this.#opts = { ...defaultTTSOptions, ...opts };
48
+ if (this.#opts.apiKey === void 0) {
49
+ throw new Error("OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY");
50
+ }
51
+ this.#client = this.#opts.client || new import_openai.OpenAI({
52
+ baseURL: opts.baseURL,
53
+ apiKey: opts.apiKey
54
+ });
55
+ }
56
+ updateOptions(opts) {
57
+ this.#opts = { ...this.#opts, ...opts };
58
+ }
59
+ synthesize(text) {
60
+ return new ChunkedStream(
61
+ this.#client.audio.speech.create({
62
+ input: text,
63
+ model: this.#opts.model,
64
+ voice: this.#opts.voice,
65
+ response_format: "pcm",
66
+ speed: this.#opts.speed
67
+ })
68
+ );
69
+ }
70
+ stream() {
71
+ throw new Error("Streaming is not supported on OpenAI TTS");
72
+ }
73
+ }
74
+ class ChunkedStream extends import_agents.tts.ChunkedStream {
75
+ // set Promise<T> to any because OpenAI returns an annoying Response type
76
+ constructor(stream) {
77
+ super();
78
+ this.#run(stream);
79
+ }
80
+ async #run(stream) {
81
+ const buffer = await stream.then((r) => r.arrayBuffer());
82
+ const requestId = crypto.randomUUID();
83
+ const audioByteStream = new import_agents.AudioByteStream(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS);
84
+ const frames = audioByteStream.write(buffer);
85
+ for (const frame of frames) {
86
+ this.queue.put({
87
+ frame,
88
+ requestId,
89
+ segmentId: requestId
90
+ });
91
+ }
92
+ this.queue.close();
93
+ }
94
+ }
95
+ // Annotate the CommonJS export names for ESM import in node:
96
+ 0 && (module.exports = {
97
+ ChunkedStream,
98
+ TTS
99
+ });
100
+ //# sourceMappingURL=tts.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tts.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AudioByteStream, tts } from '@livekit/agents';\nimport { OpenAI } from 'openai';\nimport type { TTSModels, TTSVoices } from './models.js';\n\nconst OPENAI_TTS_SAMPLE_RATE = 24000;\nconst OPENAI_TTS_CHANNELS = 1;\n\nexport interface TTSOptions {\n model: TTSModels | string;\n voice: TTSVoices;\n speed: number;\n baseURL?: string;\n client?: OpenAI;\n apiKey?: string;\n}\n\nconst defaultTTSOptions: TTSOptions = {\n apiKey: process.env.OPENAI_API_KEY,\n model: 'tts-1',\n voice: 'alloy',\n speed: 1,\n};\n\nexport class TTS extends tts.TTS {\n #opts: TTSOptions;\n #client: OpenAI;\n\n /**\n * Create a new instance of OpenAI TTS.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the\n * `OPENAI_API_KEY` environmental variable.\n */\n constructor(opts: Partial<TTSOptions> = defaultTTSOptions) {\n super(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS, { streaming: false });\n\n this.#opts = { ...defaultTTSOptions, ...opts };\n if (this.#opts.apiKey === undefined) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#client =\n this.#opts.client ||\n new OpenAI({\n baseURL: opts.baseURL,\n apiKey: opts.apiKey,\n });\n }\n\n updateOptions(opts: { model?: TTSModels | string; voice?: TTSVoices; speed?: number }) {\n this.#opts = { ...this.#opts, ...opts };\n }\n\n synthesize(text: string): ChunkedStream {\n return new ChunkedStream(\n this.#client.audio.speech.create({\n input: text,\n model: this.#opts.model,\n voice: this.#opts.voice,\n response_format: 'pcm',\n speed: this.#opts.speed,\n }),\n );\n }\n\n stream(): tts.SynthesizeStream {\n throw new Error('Streaming is not supported on OpenAI TTS');\n }\n}\n\nexport class ChunkedStream extends tts.ChunkedStream {\n // set Promise<T> to any because OpenAI returns an annoying Response type\n constructor(stream: Promise<any>) {\n super();\n this.#run(stream);\n }\n\n async #run(stream: Promise<Response>) {\n const buffer = await stream.then((r) => r.arrayBuffer());\n const requestId = crypto.randomUUID();\n const audioByteStream = new AudioByteStream(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS);\n const frames = audioByteStream.write(buffer);\n\n for (const frame of frames) {\n this.queue.put({\n frame,\n requestId,\n segmentId: requestId,\n });\n }\n this.queue.close();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,oBAAqC;AACrC,oBAAuB;AAGvB,MAAM,yBAAyB;AAC/B,MAAM,sBAAsB;AAW5B,MAAM,oBAAgC;AAAA,EACpC,QAAQ,QAAQ,IAAI;AAAA,EACpB,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;AAEO,MAAM,YAAY,kBAAI,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAY,OAA4B,mBAAmB;AACzD,UAAM,wBAAwB,qBAAqB,EAAE,WAAW,MAAM,CAAC;AAEvE,SAAK,QAAQ,EAAE,GAAG,mBAAmB,GAAG,KAAK;AAC7C,QAAI,KAAK,MAAM,WAAW,QAAW;AACnC,YAAM,IAAI,MAAM,0EAA0E;AAAA,IAC5F;AAEA,SAAK,UACH,KAAK,MAAM,UACX,IAAI,qBAAO;AAAA,MACT,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACL;AAAA,EAEA,cAAc,MAAyE;AACrF,SAAK,QAAQ,EAAE,GAAG,KAAK,OAAO,GAAG,KAAK;AAAA,EACxC;AAAA,EAEA,WAAW,MAA6B;AACtC,WAAO,IAAI;AAAA,MACT,KAAK,QAAQ,MAAM,OAAO,OAAO;AAAA,QAC/B,OAAO;AAAA,QACP,OAAO,KAAK,MAAM;AAAA,QAClB,OAAO,KAAK,MAAM;AAAA,QAClB,iBAAiB;AAAA,QACjB,OAAO,KAAK,MAAM;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,SAA+B;AAC7B,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACF;AAEO,MAAM,sBAAsB,kBAAI,cAAc;AAAA;AAAA,EAEnD,YAAY,QAAsB;AAChC,UAAM;AACN,SAAK,KAAK,MAAM;AAAA,EAClB;AAAA,EAEA,MAAM,KAAK,QAA2B;AACpC,UAAM,SAAS,MAAM,OAAO,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC;AACvD,UAAM,YAAY,OAAO,WAAW;AACpC,UAAM,kBAAkB,IAAI,8BAAgB,wBAAwB,mBAAmB;AACvF,UAAM,SAAS,gBAAgB,MAAM,MAAM;AAE3C,eAAW,SAAS,QAAQ;AAC1B,WAAK,MAAM,IAAI;AAAA,QACb;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,SAAK,MAAM,MAAM;AAAA,EACnB;AACF;","names":[]}
package/dist/tts.d.ts CHANGED
@@ -29,6 +29,6 @@ export declare class TTS extends tts.TTS {
29
29
  }
30
30
  export declare class ChunkedStream extends tts.ChunkedStream {
31
31
  #private;
32
- constructor(stream: Promise<Response>);
32
+ constructor(stream: Promise<any>);
33
33
  }
34
34
  //# 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,EAAmB,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKxD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AASD,qBAAa,GAAI,SAAQ,GAAG,CAAC,GAAG;;IAI9B;;;;;;OAMG;gBACS,IAAI,GAAE,OAAO,CAAC,UAAU,CAAqB;IAgBzD,aAAa,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,SAAS,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAIrF,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa;IAYvC,MAAM,IAAI,GAAG,CAAC,gBAAgB;CAG/B;AAED,qBAAa,aAAc,SAAQ,GAAG,CAAC,aAAa;;gBACtC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC;CAoBtC"}
1
+ {"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../src/tts.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKxD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AASD,qBAAa,GAAI,SAAQ,GAAG,CAAC,GAAG;;IAI9B;;;;;;OAMG;gBACS,IAAI,GAAE,OAAO,CAAC,UAAU,CAAqB;IAgBzD,aAAa,CAAC,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,SAAS,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAIrF,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa;IAYvC,MAAM,IAAI,GAAG,CAAC,gBAAgB;CAG/B;AAED,qBAAa,aAAc,SAAQ,GAAG,CAAC,aAAa;;gBAEtC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC;CAoBjC"}
package/dist/tts.js CHANGED
@@ -1,73 +1,75 @@
1
- // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
- //
3
- // SPDX-License-Identifier: Apache-2.0
4
- import { AudioByteStream, tts } from '@livekit/agents';
5
- import { OpenAI } from 'openai';
6
- const OPENAI_TTS_SAMPLE_RATE = 24000;
1
+ import { AudioByteStream, tts } from "@livekit/agents";
2
+ import { OpenAI } from "openai";
3
+ const OPENAI_TTS_SAMPLE_RATE = 24e3;
7
4
  const OPENAI_TTS_CHANNELS = 1;
8
5
  const defaultTTSOptions = {
9
- apiKey: process.env.OPENAI_API_KEY,
10
- model: 'tts-1',
11
- voice: 'alloy',
12
- speed: 1,
6
+ apiKey: process.env.OPENAI_API_KEY,
7
+ model: "tts-1",
8
+ voice: "alloy",
9
+ speed: 1
13
10
  };
14
- export class TTS extends tts.TTS {
15
- #opts;
16
- #client;
17
- /**
18
- * Create a new instance of OpenAI TTS.
19
- *
20
- * @remarks
21
- * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the
22
- * `OPENAI_API_KEY` environmental variable.
23
- */
24
- constructor(opts = defaultTTSOptions) {
25
- super(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS, { streaming: false });
26
- this.#opts = { ...defaultTTSOptions, ...opts };
27
- if (this.#opts.apiKey === undefined) {
28
- throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');
29
- }
30
- this.#client =
31
- this.#opts.client ||
32
- new OpenAI({
33
- baseURL: opts.baseURL,
34
- apiKey: opts.apiKey,
35
- });
36
- }
37
- updateOptions(opts) {
38
- this.#opts = { ...this.#opts, ...opts };
39
- }
40
- synthesize(text) {
41
- return new ChunkedStream(this.#client.audio.speech.create({
42
- input: text,
43
- model: this.#opts.model,
44
- voice: this.#opts.voice,
45
- response_format: 'pcm',
46
- speed: this.#opts.speed,
47
- }));
48
- }
49
- stream() {
50
- throw new Error('Streaming is not supported on OpenAI TTS');
11
+ class TTS extends tts.TTS {
12
+ #opts;
13
+ #client;
14
+ /**
15
+ * Create a new instance of OpenAI TTS.
16
+ *
17
+ * @remarks
18
+ * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the
19
+ * `OPENAI_API_KEY` environmental variable.
20
+ */
21
+ constructor(opts = defaultTTSOptions) {
22
+ super(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS, { streaming: false });
23
+ this.#opts = { ...defaultTTSOptions, ...opts };
24
+ if (this.#opts.apiKey === void 0) {
25
+ throw new Error("OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY");
51
26
  }
27
+ this.#client = this.#opts.client || new OpenAI({
28
+ baseURL: opts.baseURL,
29
+ apiKey: opts.apiKey
30
+ });
31
+ }
32
+ updateOptions(opts) {
33
+ this.#opts = { ...this.#opts, ...opts };
34
+ }
35
+ synthesize(text) {
36
+ return new ChunkedStream(
37
+ this.#client.audio.speech.create({
38
+ input: text,
39
+ model: this.#opts.model,
40
+ voice: this.#opts.voice,
41
+ response_format: "pcm",
42
+ speed: this.#opts.speed
43
+ })
44
+ );
45
+ }
46
+ stream() {
47
+ throw new Error("Streaming is not supported on OpenAI TTS");
48
+ }
52
49
  }
53
- export class ChunkedStream extends tts.ChunkedStream {
54
- constructor(stream) {
55
- super();
56
- this.#run(stream);
57
- }
58
- async #run(stream) {
59
- const buffer = await stream.then((r) => r.arrayBuffer());
60
- const requestId = crypto.randomUUID();
61
- const audioByteStream = new AudioByteStream(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS);
62
- const frames = audioByteStream.write(buffer);
63
- for (const frame of frames) {
64
- this.queue.put({
65
- frame,
66
- requestId,
67
- segmentId: requestId,
68
- });
69
- }
70
- this.queue.close();
50
+ class ChunkedStream extends tts.ChunkedStream {
51
+ // set Promise<T> to any because OpenAI returns an annoying Response type
52
+ constructor(stream) {
53
+ super();
54
+ this.#run(stream);
55
+ }
56
+ async #run(stream) {
57
+ const buffer = await stream.then((r) => r.arrayBuffer());
58
+ const requestId = crypto.randomUUID();
59
+ const audioByteStream = new AudioByteStream(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS);
60
+ const frames = audioByteStream.write(buffer);
61
+ for (const frame of frames) {
62
+ this.queue.put({
63
+ frame,
64
+ requestId,
65
+ segmentId: requestId
66
+ });
71
67
  }
68
+ this.queue.close();
69
+ }
72
70
  }
71
+ export {
72
+ ChunkedStream,
73
+ TTS
74
+ };
73
75
  //# sourceMappingURL=tts.js.map
package/dist/tts.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tts.js","sourceRoot":"","sources":["../src/tts.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,EAAE;AACF,sCAAsC;AACtC,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,MAAM,sBAAsB,GAAG,KAAK,CAAC;AACrC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAW9B,MAAM,iBAAiB,GAAe;IACpC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;IAClC,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,CAAC;CACT,CAAC;AAEF,MAAM,OAAO,GAAI,SAAQ,GAAG,CAAC,GAAG;IAC9B,KAAK,CAAa;IAClB,OAAO,CAAS;IAEhB;;;;;;OAMG;IACH,YAAY,OAA4B,iBAAiB;QACvD,KAAK,CAAC,sBAAsB,EAAE,mBAAmB,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QAEzE,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,iBAAiB,EAAE,GAAG,IAAI,EAAE,CAAC;QAC/C,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;QAC9F,CAAC;QAED,IAAI,CAAC,OAAO;YACV,IAAI,CAAC,KAAK,CAAC,MAAM;gBACjB,IAAI,MAAM,CAAC;oBACT,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,MAAM,EAAE,IAAI,CAAC,MAAM;iBACpB,CAAC,CAAC;IACP,CAAC;IAED,aAAa,CAAC,IAAuE;QACnF,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC;IAC1C,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,aAAa,CACtB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;YAC/B,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;YACvB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;YACvB,eAAe,EAAE,KAAK;YACtB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;SACxB,CAAC,CACH,CAAC;IACJ,CAAC;IAED,MAAM;QACJ,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,GAAG,CAAC,aAAa;IAClD,YAAY,MAAyB;QACnC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAyB;QAClC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACzD,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QACtC,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;QACzF,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAE7C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;gBACb,KAAK;gBACL,SAAS;gBACT,SAAS,EAAE,SAAS;aACrB,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF"}
1
+ {"version":3,"sources":["../src/tts.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AudioByteStream, tts } from '@livekit/agents';\nimport { OpenAI } from 'openai';\nimport type { TTSModels, TTSVoices } from './models.js';\n\nconst OPENAI_TTS_SAMPLE_RATE = 24000;\nconst OPENAI_TTS_CHANNELS = 1;\n\nexport interface TTSOptions {\n model: TTSModels | string;\n voice: TTSVoices;\n speed: number;\n baseURL?: string;\n client?: OpenAI;\n apiKey?: string;\n}\n\nconst defaultTTSOptions: TTSOptions = {\n apiKey: process.env.OPENAI_API_KEY,\n model: 'tts-1',\n voice: 'alloy',\n speed: 1,\n};\n\nexport class TTS extends tts.TTS {\n #opts: TTSOptions;\n #client: OpenAI;\n\n /**\n * Create a new instance of OpenAI TTS.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the\n * `OPENAI_API_KEY` environmental variable.\n */\n constructor(opts: Partial<TTSOptions> = defaultTTSOptions) {\n super(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS, { streaming: false });\n\n this.#opts = { ...defaultTTSOptions, ...opts };\n if (this.#opts.apiKey === undefined) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#client =\n this.#opts.client ||\n new OpenAI({\n baseURL: opts.baseURL,\n apiKey: opts.apiKey,\n });\n }\n\n updateOptions(opts: { model?: TTSModels | string; voice?: TTSVoices; speed?: number }) {\n this.#opts = { ...this.#opts, ...opts };\n }\n\n synthesize(text: string): ChunkedStream {\n return new ChunkedStream(\n this.#client.audio.speech.create({\n input: text,\n model: this.#opts.model,\n voice: this.#opts.voice,\n response_format: 'pcm',\n speed: this.#opts.speed,\n }),\n );\n }\n\n stream(): tts.SynthesizeStream {\n throw new Error('Streaming is not supported on OpenAI TTS');\n }\n}\n\nexport class ChunkedStream extends tts.ChunkedStream {\n // set Promise<T> to any because OpenAI returns an annoying Response type\n constructor(stream: Promise<any>) {\n super();\n this.#run(stream);\n }\n\n async #run(stream: Promise<Response>) {\n const buffer = await stream.then((r) => r.arrayBuffer());\n const requestId = crypto.randomUUID();\n const audioByteStream = new AudioByteStream(OPENAI_TTS_SAMPLE_RATE, OPENAI_TTS_CHANNELS);\n const frames = audioByteStream.write(buffer);\n\n for (const frame of frames) {\n this.queue.put({\n frame,\n requestId,\n segmentId: requestId,\n });\n }\n this.queue.close();\n }\n}\n"],"mappings":"AAGA,SAAS,iBAAiB,WAAW;AACrC,SAAS,cAAc;AAGvB,MAAM,yBAAyB;AAC/B,MAAM,sBAAsB;AAW5B,MAAM,oBAAgC;AAAA,EACpC,QAAQ,QAAQ,IAAI;AAAA,EACpB,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;AAEO,MAAM,YAAY,IAAI,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAY,OAA4B,mBAAmB;AACzD,UAAM,wBAAwB,qBAAqB,EAAE,WAAW,MAAM,CAAC;AAEvE,SAAK,QAAQ,EAAE,GAAG,mBAAmB,GAAG,KAAK;AAC7C,QAAI,KAAK,MAAM,WAAW,QAAW;AACnC,YAAM,IAAI,MAAM,0EAA0E;AAAA,IAC5F;AAEA,SAAK,UACH,KAAK,MAAM,UACX,IAAI,OAAO;AAAA,MACT,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACL;AAAA,EAEA,cAAc,MAAyE;AACrF,SAAK,QAAQ,EAAE,GAAG,KAAK,OAAO,GAAG,KAAK;AAAA,EACxC;AAAA,EAEA,WAAW,MAA6B;AACtC,WAAO,IAAI;AAAA,MACT,KAAK,QAAQ,MAAM,OAAO,OAAO;AAAA,QAC/B,OAAO;AAAA,QACP,OAAO,KAAK,MAAM;AAAA,QAClB,OAAO,KAAK,MAAM;AAAA,QAClB,iBAAiB;AAAA,QACjB,OAAO,KAAK,MAAM;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,SAA+B;AAC7B,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACF;AAEO,MAAM,sBAAsB,IAAI,cAAc;AAAA;AAAA,EAEnD,YAAY,QAAsB;AAChC,UAAM;AACN,SAAK,KAAK,MAAM;AAAA,EAClB;AAAA,EAEA,MAAM,KAAK,QAA2B;AACpC,UAAM,SAAS,MAAM,OAAO,KAAK,CAAC,MAAM,EAAE,YAAY,CAAC;AACvD,UAAM,YAAY,OAAO,WAAW;AACpC,UAAM,kBAAkB,IAAI,gBAAgB,wBAAwB,mBAAmB;AACvF,UAAM,SAAS,gBAAgB,MAAM,MAAM;AAE3C,eAAW,SAAS,QAAQ;AAC1B,WAAK,MAAM,IAAI;AAAA,QACb;AAAA,QACA;AAAA,QACA,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,SAAK,MAAM,MAAM;AAAA,EACnB;AACF;","names":[]}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ var import_agents_plugins_test = require("@livekit/agents-plugins-test");
3
+ var import_vitest = require("vitest");
4
+ var import_stt = require("./stt.cjs");
5
+ var import_tts = require("./tts.cjs");
6
+ (0, import_vitest.describe)("OpenAI", async () => {
7
+ await (0, import_agents_plugins_test.tts)(new import_tts.TTS(), new import_stt.STT(), { streaming: false });
8
+ });
9
+ //# sourceMappingURL=tts.test.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tts.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { tts } from '@livekit/agents-plugins-test';\nimport { describe } from 'vitest';\nimport { STT } from './stt.js';\nimport { TTS } from './tts.js';\n\ndescribe('OpenAI', async () => {\n await tts(new TTS(), new STT(), { streaming: false });\n});\n"],"mappings":";AAGA,iCAAoB;AACpB,oBAAyB;AACzB,iBAAoB;AACpB,iBAAoB;AAAA,IAEpB,wBAAS,UAAU,YAAY;AAC7B,YAAM,gCAAI,IAAI,eAAI,GAAG,IAAI,eAAI,GAAG,EAAE,WAAW,MAAM,CAAC;AACtD,CAAC;","names":[]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tts.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tts.test.d.ts","sourceRoot":"","sources":["../src/tts.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ import { tts } from "@livekit/agents-plugins-test";
2
+ import { describe } from "vitest";
3
+ import { STT } from "./stt.js";
4
+ import { TTS } from "./tts.js";
5
+ describe("OpenAI", async () => {
6
+ await tts(new TTS(), new STT(), { streaming: false });
7
+ });
8
+ //# sourceMappingURL=tts.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tts.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { tts } from '@livekit/agents-plugins-test';\nimport { describe } from 'vitest';\nimport { STT } from './stt.js';\nimport { TTS } from './tts.js';\n\ndescribe('OpenAI', async () => {\n await tts(new TTS(), new STT(), { streaming: false });\n});\n"],"mappings":"AAGA,SAAS,WAAW;AACpB,SAAS,gBAAgB;AACzB,SAAS,WAAW;AACpB,SAAS,WAAW;AAEpB,SAAS,UAAU,YAAY;AAC7B,QAAM,IAAI,IAAI,IAAI,GAAG,IAAI,IAAI,GAAG,EAAE,WAAW,MAAM,CAAC;AACtD,CAAC;","names":[]}
package/package.json CHANGED
@@ -1,23 +1,35 @@
1
1
  {
2
2
  "name": "@livekit/agents-plugin-openai",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "OpenAI plugin for LiveKit Node Agents",
5
5
  "main": "dist/index.js",
6
+ "require": "dist/index.cjs",
6
7
  "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
7
15
  "author": "LiveKit",
8
16
  "type": "module",
9
17
  "repository": "git@github.com:livekit/agents-js.git",
10
18
  "license": "Apache-2.0",
11
19
  "files": [
12
20
  "dist",
13
- "src"
21
+ "src",
22
+ "README.md"
14
23
  ],
15
24
  "devDependencies": {
25
+ "@livekit/agents": "^x",
26
+ "@livekit/agents-plugin-silero": "^x",
27
+ "@livekit/agents-plugins-test": "^x",
28
+ "@livekit/rtc-node": "^0.12.1",
16
29
  "@microsoft/api-extractor": "^7.35.0",
17
- "@livekit/rtc-node": "^0.11.1",
18
30
  "@types/ws": "^8.5.10",
19
- "typescript": "^5.0.0",
20
- "@livekit/agents": "^0.4.6"
31
+ "tsup": "^8.3.5",
32
+ "typescript": "^5.0.0"
21
33
  },
22
34
  "dependencies": {
23
35
  "openai": "^4.70.2",
@@ -25,11 +37,11 @@
25
37
  "ws": "^8.16.0"
26
38
  },
27
39
  "peerDependencies": {
28
- "@livekit/rtc-node": "^0.11.1",
29
- "@livekit/agents": "^0.4.6"
40
+ "@livekit/rtc-node": "^0.12.1",
41
+ "@livekit/agents": "^0.5.1x"
30
42
  },
31
43
  "scripts": {
32
- "build": "tsc -b tsconfig.json",
44
+ "build": "tsup --onSuccess \"tsc --declaration --emitDeclarationOnly\"",
33
45
  "clean": "rm -rf dist",
34
46
  "clean:build": "pnpm clean && pnpm build",
35
47
  "lint": "eslint -f unix \"src/**/*.{ts,js}\"",
@@ -0,0 +1,10 @@
1
+ // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { llm } from '@livekit/agents-plugins-test';
5
+ import { describe } from 'vitest';
6
+ import { LLM } from './llm.js';
7
+
8
+ describe('OpenAI', async () => {
9
+ await llm(new LLM());
10
+ });
package/src/llm.ts CHANGED
@@ -498,6 +498,11 @@ export class LLMStream extends llm.LLMStream {
498
498
  continue; // oai may add other tools in the future
499
499
  }
500
500
 
501
+ let callChunk: llm.ChatChunk | undefined;
502
+ if (this.#toolCallId && tool.id && tool.id !== this.#toolCallId) {
503
+ callChunk = this.#tryBuildFunction(id, choice);
504
+ }
505
+
501
506
  if (tool.function.name) {
502
507
  this.#toolCallId = tool.id;
503
508
  this.#fncName = tool.function.name;
@@ -506,8 +511,8 @@ export class LLMStream extends llm.LLMStream {
506
511
  this.#fncRawArguments += tool.function.arguments;
507
512
  }
508
513
 
509
- if (this.#toolCallId && tool.id && tool.id !== this.#toolCallId) {
510
- return this.#tryBuildFunction(id, choice);
514
+ if (callChunk) {
515
+ return callChunk;
511
516
  }
512
517
  }
513
518
  }
@@ -0,0 +1,11 @@
1
+ // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { VAD } from '@livekit/agents-plugin-silero';
5
+ import { stt } from '@livekit/agents-plugins-test';
6
+ import { describe } from 'vitest';
7
+ import { STT } from './stt.js';
8
+
9
+ describe('OpenAI', async () => {
10
+ await stt(new STT(), await VAD.load(), { streaming: false });
11
+ });
@@ -0,0 +1,11 @@
1
+ // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { tts } from '@livekit/agents-plugins-test';
5
+ import { describe } from 'vitest';
6
+ import { STT } from './stt.js';
7
+ import { TTS } from './tts.js';
8
+
9
+ describe('OpenAI', async () => {
10
+ await tts(new TTS(), new STT(), { streaming: false });
11
+ });
package/src/tts.ts CHANGED
@@ -73,7 +73,8 @@ export class TTS extends tts.TTS {
73
73
  }
74
74
 
75
75
  export class ChunkedStream extends tts.ChunkedStream {
76
- constructor(stream: Promise<Response>) {
76
+ // set Promise<T> to any because OpenAI returns an annoying Response type
77
+ constructor(stream: Promise<any>) {
77
78
  super();
78
79
  this.#run(stream);
79
80
  }