@livekit/agents 0.4.6 → 0.5.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 (214) hide show
  1. package/README.md +17 -0
  2. package/dist/audio.cjs +77 -0
  3. package/dist/audio.cjs.map +1 -0
  4. package/dist/audio.js +48 -37
  5. package/dist/audio.js.map +1 -1
  6. package/dist/cli.cjs +131 -0
  7. package/dist/cli.cjs.map +1 -0
  8. package/dist/cli.js +96 -122
  9. package/dist/cli.js.map +1 -1
  10. package/dist/generator.cjs +36 -0
  11. package/dist/generator.cjs.map +1 -0
  12. package/dist/generator.js +8 -22
  13. package/dist/generator.js.map +1 -1
  14. package/dist/http_server.cjs +72 -0
  15. package/dist/http_server.cjs.map +1 -0
  16. package/dist/http_server.d.ts +1 -1
  17. package/dist/http_server.js +44 -47
  18. package/dist/http_server.js.map +1 -1
  19. package/dist/index.cjs +78 -0
  20. package/dist/index.cjs.map +1 -0
  21. package/dist/index.js +26 -28
  22. package/dist/index.js.map +1 -1
  23. package/dist/ipc/job_executor.cjs +33 -0
  24. package/dist/ipc/job_executor.cjs.map +1 -0
  25. package/dist/ipc/job_executor.js +7 -4
  26. package/dist/ipc/job_executor.js.map +1 -1
  27. package/dist/ipc/job_main.cjs +147 -0
  28. package/dist/ipc/job_main.cjs.map +1 -0
  29. package/dist/ipc/job_main.d.ts +1 -1
  30. package/dist/ipc/job_main.js +103 -103
  31. package/dist/ipc/job_main.js.map +1 -1
  32. package/dist/ipc/message.cjs +17 -0
  33. package/dist/ipc/message.cjs.map +1 -0
  34. package/dist/ipc/message.js +0 -1
  35. package/dist/ipc/message.js.map +1 -1
  36. package/dist/ipc/proc_job_executor.cjs +174 -0
  37. package/dist/ipc/proc_job_executor.cjs.map +1 -0
  38. package/dist/ipc/proc_job_executor.js +130 -126
  39. package/dist/ipc/proc_job_executor.js.map +1 -1
  40. package/dist/ipc/proc_pool.cjs +126 -0
  41. package/dist/ipc/proc_pool.cjs.map +1 -0
  42. package/dist/ipc/proc_pool.js +93 -96
  43. package/dist/ipc/proc_pool.js.map +1 -1
  44. package/dist/job.cjs +230 -0
  45. package/dist/job.cjs.map +1 -0
  46. package/dist/job.d.ts +6 -1
  47. package/dist/job.d.ts.map +1 -1
  48. package/dist/job.js +195 -198
  49. package/dist/job.js.map +1 -1
  50. package/dist/llm/chat_context.cjs +131 -0
  51. package/dist/llm/chat_context.cjs.map +1 -0
  52. package/dist/llm/chat_context.js +98 -86
  53. package/dist/llm/chat_context.js.map +1 -1
  54. package/dist/llm/function_context.cjs +103 -0
  55. package/dist/llm/function_context.cjs.map +1 -0
  56. package/dist/llm/function_context.js +72 -81
  57. package/dist/llm/function_context.js.map +1 -1
  58. package/dist/llm/function_context.test.cjs +218 -0
  59. package/dist/llm/function_context.test.cjs.map +1 -0
  60. package/dist/llm/function_context.test.js +209 -210
  61. package/dist/llm/function_context.test.js.map +1 -1
  62. package/dist/llm/index.cjs +43 -0
  63. package/dist/llm/index.cjs.map +1 -0
  64. package/dist/llm/index.js +22 -6
  65. package/dist/llm/index.js.map +1 -1
  66. package/dist/llm/llm.cjs +76 -0
  67. package/dist/llm/llm.cjs.map +1 -0
  68. package/dist/llm/llm.js +48 -42
  69. package/dist/llm/llm.js.map +1 -1
  70. package/dist/log.cjs +57 -0
  71. package/dist/log.cjs.map +1 -0
  72. package/dist/log.js +27 -26
  73. package/dist/log.js.map +1 -1
  74. package/dist/multimodal/agent_playout.cjs +228 -0
  75. package/dist/multimodal/agent_playout.cjs.map +1 -0
  76. package/dist/multimodal/agent_playout.d.ts +1 -1
  77. package/dist/multimodal/agent_playout.js +193 -180
  78. package/dist/multimodal/agent_playout.js.map +1 -1
  79. package/dist/multimodal/index.cjs +25 -0
  80. package/dist/multimodal/index.cjs.map +1 -0
  81. package/dist/multimodal/index.js +2 -5
  82. package/dist/multimodal/index.js.map +1 -1
  83. package/dist/multimodal/multimodal_agent.cjs +404 -0
  84. package/dist/multimodal/multimodal_agent.cjs.map +1 -0
  85. package/dist/multimodal/multimodal_agent.d.ts +1 -1
  86. package/dist/multimodal/multimodal_agent.js +351 -330
  87. package/dist/multimodal/multimodal_agent.js.map +1 -1
  88. package/dist/pipeline/agent_output.cjs +172 -0
  89. package/dist/pipeline/agent_output.cjs.map +1 -0
  90. package/dist/pipeline/agent_output.js +136 -138
  91. package/dist/pipeline/agent_output.js.map +1 -1
  92. package/dist/pipeline/agent_playout.cjs +169 -0
  93. package/dist/pipeline/agent_playout.cjs.map +1 -0
  94. package/dist/pipeline/agent_playout.js +126 -136
  95. package/dist/pipeline/agent_playout.js.map +1 -1
  96. package/dist/pipeline/human_input.cjs +158 -0
  97. package/dist/pipeline/human_input.cjs.map +1 -0
  98. package/dist/pipeline/human_input.js +124 -125
  99. package/dist/pipeline/human_input.js.map +1 -1
  100. package/dist/pipeline/index.cjs +31 -0
  101. package/dist/pipeline/index.cjs.map +1 -0
  102. package/dist/pipeline/index.js +8 -4
  103. package/dist/pipeline/index.js.map +1 -1
  104. package/dist/pipeline/pipeline_agent.cjs +642 -0
  105. package/dist/pipeline/pipeline_agent.cjs.map +1 -0
  106. package/dist/pipeline/pipeline_agent.js +595 -651
  107. package/dist/pipeline/pipeline_agent.js.map +1 -1
  108. package/dist/pipeline/speech_handle.cjs +128 -0
  109. package/dist/pipeline/speech_handle.cjs.map +1 -0
  110. package/dist/pipeline/speech_handle.js +102 -100
  111. package/dist/pipeline/speech_handle.js.map +1 -1
  112. package/dist/plugin.cjs +46 -0
  113. package/dist/plugin.cjs.map +1 -0
  114. package/dist/plugin.js +20 -20
  115. package/dist/plugin.js.map +1 -1
  116. package/dist/stt/index.cjs +38 -0
  117. package/dist/stt/index.cjs.map +1 -0
  118. package/dist/stt/index.js +13 -5
  119. package/dist/stt/index.js.map +1 -1
  120. package/dist/stt/stream_adapter.cjs +87 -0
  121. package/dist/stt/stream_adapter.cjs.map +1 -0
  122. package/dist/stt/stream_adapter.js +58 -55
  123. package/dist/stt/stream_adapter.js.map +1 -1
  124. package/dist/stt/stt.cjs +98 -0
  125. package/dist/stt/stt.cjs.map +1 -0
  126. package/dist/stt/stt.js +63 -98
  127. package/dist/stt/stt.js.map +1 -1
  128. package/dist/tokenize/basic/basic.cjs +98 -0
  129. package/dist/tokenize/basic/basic.cjs.map +1 -0
  130. package/dist/tokenize/basic/basic.d.ts +1 -1
  131. package/dist/tokenize/basic/basic.d.ts.map +1 -1
  132. package/dist/tokenize/basic/basic.js +56 -45
  133. package/dist/tokenize/basic/basic.js.map +1 -1
  134. package/dist/tokenize/basic/hyphenator.cjs +425 -0
  135. package/dist/tokenize/basic/hyphenator.cjs.map +1 -0
  136. package/dist/tokenize/basic/hyphenator.js +66 -82
  137. package/dist/tokenize/basic/hyphenator.js.map +1 -1
  138. package/dist/tokenize/basic/index.cjs +35 -0
  139. package/dist/tokenize/basic/index.cjs.map +1 -0
  140. package/dist/tokenize/basic/index.js +7 -4
  141. package/dist/tokenize/basic/index.js.map +1 -1
  142. package/dist/tokenize/basic/paragraph.cjs +57 -0
  143. package/dist/tokenize/basic/paragraph.cjs.map +1 -0
  144. package/dist/tokenize/basic/paragraph.js +30 -35
  145. package/dist/tokenize/basic/paragraph.js.map +1 -1
  146. package/dist/tokenize/basic/sentence.cjs +89 -0
  147. package/dist/tokenize/basic/sentence.cjs.map +1 -0
  148. package/dist/tokenize/basic/sentence.d.ts.map +1 -1
  149. package/dist/tokenize/basic/sentence.js +62 -57
  150. package/dist/tokenize/basic/sentence.js.map +1 -1
  151. package/dist/tokenize/basic/word.cjs +44 -0
  152. package/dist/tokenize/basic/word.cjs.map +1 -0
  153. package/dist/tokenize/basic/word.js +17 -20
  154. package/dist/tokenize/basic/word.js.map +1 -1
  155. package/dist/tokenize/index.cjs +55 -0
  156. package/dist/tokenize/index.cjs.map +1 -0
  157. package/dist/tokenize/index.js +18 -7
  158. package/dist/tokenize/index.js.map +1 -1
  159. package/dist/tokenize/token_stream.cjs +164 -0
  160. package/dist/tokenize/token_stream.cjs.map +1 -0
  161. package/dist/tokenize/token_stream.js +133 -139
  162. package/dist/tokenize/token_stream.js.map +1 -1
  163. package/dist/tokenize/tokenizer.cjs +184 -0
  164. package/dist/tokenize/tokenizer.cjs.map +1 -0
  165. package/dist/tokenize/tokenizer.js +138 -99
  166. package/dist/tokenize/tokenizer.js.map +1 -1
  167. package/dist/tokenize/tokenizer.test.cjs +220 -0
  168. package/dist/tokenize/tokenizer.test.cjs.map +1 -0
  169. package/dist/tokenize/tokenizer.test.d.ts +2 -0
  170. package/dist/tokenize/tokenizer.test.d.ts.map +1 -0
  171. package/dist/tokenize/tokenizer.test.js +219 -0
  172. package/dist/tokenize/tokenizer.test.js.map +1 -0
  173. package/dist/transcription.cjs +131 -0
  174. package/dist/transcription.cjs.map +1 -0
  175. package/dist/transcription.js +99 -96
  176. package/dist/transcription.js.map +1 -1
  177. package/dist/tts/index.cjs +38 -0
  178. package/dist/tts/index.cjs.map +1 -0
  179. package/dist/tts/index.js +13 -5
  180. package/dist/tts/index.js.map +1 -1
  181. package/dist/tts/stream_adapter.cjs +78 -0
  182. package/dist/tts/stream_adapter.cjs.map +1 -0
  183. package/dist/tts/stream_adapter.js +50 -47
  184. package/dist/tts/stream_adapter.js.map +1 -1
  185. package/dist/tts/tts.cjs +127 -0
  186. package/dist/tts/tts.cjs.map +1 -0
  187. package/dist/tts/tts.js +90 -120
  188. package/dist/tts/tts.js.map +1 -1
  189. package/dist/utils.cjs +284 -0
  190. package/dist/utils.cjs.map +1 -0
  191. package/dist/utils.js +242 -247
  192. package/dist/utils.js.map +1 -1
  193. package/dist/vad.cjs +92 -0
  194. package/dist/vad.cjs.map +1 -0
  195. package/dist/vad.js +57 -52
  196. package/dist/vad.js.map +1 -1
  197. package/dist/version.cjs +29 -0
  198. package/dist/version.cjs.map +1 -0
  199. package/dist/version.js +4 -4
  200. package/dist/version.js.map +1 -1
  201. package/dist/worker.cjs +577 -0
  202. package/dist/worker.cjs.map +1 -0
  203. package/dist/worker.d.ts +1 -1
  204. package/dist/worker.d.ts.map +1 -1
  205. package/dist/worker.js +512 -484
  206. package/dist/worker.js.map +1 -1
  207. package/package.json +18 -8
  208. package/src/ipc/job_main.ts +66 -64
  209. package/src/job.ts +3 -2
  210. package/src/pipeline/pipeline_agent.ts +23 -23
  211. package/src/tokenize/basic/basic.ts +1 -1
  212. package/src/tokenize/basic/sentence.ts +14 -8
  213. package/src/tokenize/tokenizer.test.ts +255 -0
  214. package/src/worker.ts +1 -0
@@ -0,0 +1,228 @@
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 agent_playout_exports = {};
20
+ __export(agent_playout_exports, {
21
+ AgentPlayout: () => AgentPlayout,
22
+ PlayoutHandle: () => PlayoutHandle,
23
+ proto: () => proto
24
+ });
25
+ module.exports = __toCommonJS(agent_playout_exports);
26
+ var import_node_events = require("node:events");
27
+ var import_audio = require("../audio.cjs");
28
+ var import_utils = require("../utils.cjs");
29
+ const proto = {};
30
+ class PlayoutHandle extends import_node_events.EventEmitter {
31
+ #audioSource;
32
+ #sampleRate;
33
+ #itemId;
34
+ #contentIndex;
35
+ /** @internal */
36
+ transcriptionFwd;
37
+ /** @internal */
38
+ doneFut;
39
+ /** @internal */
40
+ intFut;
41
+ /** @internal */
42
+ #interrupted;
43
+ /** @internal */
44
+ pushedDuration;
45
+ /** @internal */
46
+ totalPlayedTime;
47
+ // Set when playout is done
48
+ constructor(audioSource, sampleRate, itemId, contentIndex, transcriptionFwd) {
49
+ super();
50
+ this.#audioSource = audioSource;
51
+ this.#sampleRate = sampleRate;
52
+ this.#itemId = itemId;
53
+ this.#contentIndex = contentIndex;
54
+ this.transcriptionFwd = transcriptionFwd;
55
+ this.doneFut = new import_utils.Future();
56
+ this.intFut = new import_utils.Future();
57
+ this.#interrupted = false;
58
+ this.pushedDuration = 0;
59
+ this.totalPlayedTime = void 0;
60
+ }
61
+ get itemId() {
62
+ return this.#itemId;
63
+ }
64
+ get audioSamples() {
65
+ if (this.totalPlayedTime !== void 0) {
66
+ return Math.floor(this.totalPlayedTime * this.#sampleRate);
67
+ }
68
+ return Math.floor(
69
+ (this.pushedDuration - this.#audioSource.queuedDuration) * (this.#sampleRate / 1e3)
70
+ );
71
+ }
72
+ get textChars() {
73
+ return this.transcriptionFwd.currentCharacterIndex;
74
+ }
75
+ get contentIndex() {
76
+ return this.#contentIndex;
77
+ }
78
+ get interrupted() {
79
+ return this.#interrupted;
80
+ }
81
+ get done() {
82
+ return this.doneFut.done || this.#interrupted;
83
+ }
84
+ interrupt() {
85
+ if (this.doneFut.done) return;
86
+ this.intFut.resolve();
87
+ this.#interrupted = true;
88
+ }
89
+ }
90
+ class AgentPlayout extends import_node_events.EventEmitter {
91
+ #audioSource;
92
+ #playoutTask;
93
+ #sampleRate;
94
+ #numChannels;
95
+ #inFrameSize;
96
+ #outFrameSize;
97
+ constructor(audioSource, sampleRate, numChannels, inFrameSize, outFrameSize) {
98
+ super();
99
+ this.#audioSource = audioSource;
100
+ this.#playoutTask = null;
101
+ this.#sampleRate = sampleRate;
102
+ this.#numChannels = numChannels;
103
+ this.#inFrameSize = inFrameSize;
104
+ this.#outFrameSize = outFrameSize;
105
+ }
106
+ play(itemId, contentIndex, transcriptionFwd, textStream, audioStream) {
107
+ const handle = new PlayoutHandle(
108
+ this.#audioSource,
109
+ this.#sampleRate,
110
+ itemId,
111
+ contentIndex,
112
+ transcriptionFwd
113
+ );
114
+ this.#playoutTask = this.#makePlayoutTask(this.#playoutTask, handle, textStream, audioStream);
115
+ return handle;
116
+ }
117
+ #makePlayoutTask(oldTask, handle, textStream, audioStream) {
118
+ return new import_utils.CancellablePromise((resolve, reject, onCancel) => {
119
+ let cancelled = false;
120
+ onCancel(() => {
121
+ cancelled = true;
122
+ });
123
+ (async () => {
124
+ try {
125
+ if (oldTask) {
126
+ await (0, import_utils.gracefullyCancel)(oldTask);
127
+ }
128
+ let firstFrame = true;
129
+ const readText = () => new import_utils.CancellablePromise((resolveText, rejectText, onCancelText) => {
130
+ let cancelledText = false;
131
+ onCancelText(() => {
132
+ cancelledText = true;
133
+ });
134
+ (async () => {
135
+ try {
136
+ for await (const text of textStream) {
137
+ if (cancelledText || cancelled) {
138
+ break;
139
+ }
140
+ handle.transcriptionFwd.pushText(text);
141
+ }
142
+ resolveText();
143
+ } catch (error) {
144
+ rejectText(error);
145
+ }
146
+ })();
147
+ });
148
+ const capture = () => new import_utils.CancellablePromise((resolveCapture, rejectCapture, onCancelCapture) => {
149
+ let cancelledCapture = false;
150
+ onCancelCapture(() => {
151
+ cancelledCapture = true;
152
+ });
153
+ (async () => {
154
+ try {
155
+ const samplesPerChannel = this.#outFrameSize;
156
+ const bstream = new import_audio.AudioByteStream(
157
+ this.#sampleRate,
158
+ this.#numChannels,
159
+ samplesPerChannel
160
+ );
161
+ for await (const frame of audioStream) {
162
+ if (cancelledCapture || cancelled) {
163
+ break;
164
+ }
165
+ if (firstFrame) {
166
+ handle.transcriptionFwd.start();
167
+ this.emit("playout_started");
168
+ firstFrame = false;
169
+ }
170
+ handle.transcriptionFwd.pushAudio(frame);
171
+ for (const f of bstream.write(frame.data.buffer)) {
172
+ handle.pushedDuration += f.samplesPerChannel / f.sampleRate * 1e3;
173
+ await this.#audioSource.captureFrame(f);
174
+ }
175
+ }
176
+ if (!cancelledCapture && !cancelled) {
177
+ for (const f of bstream.flush()) {
178
+ handle.pushedDuration += f.samplesPerChannel / f.sampleRate * 1e3;
179
+ await this.#audioSource.captureFrame(f);
180
+ }
181
+ handle.transcriptionFwd.markAudioComplete();
182
+ await this.#audioSource.waitForPlayout();
183
+ }
184
+ resolveCapture();
185
+ } catch (error) {
186
+ rejectCapture(error);
187
+ }
188
+ })();
189
+ });
190
+ const readTextTask = readText();
191
+ const captureTask = capture();
192
+ try {
193
+ await Promise.race([captureTask, handle.intFut.await]);
194
+ } finally {
195
+ if (!captureTask.isCancelled) {
196
+ await (0, import_utils.gracefullyCancel)(captureTask);
197
+ }
198
+ handle.totalPlayedTime = handle.pushedDuration - this.#audioSource.queuedDuration;
199
+ if (handle.interrupted || captureTask.error) {
200
+ this.#audioSource.clearQueue();
201
+ }
202
+ if (!readTextTask.isCancelled) {
203
+ await (0, import_utils.gracefullyCancel)(readTextTask);
204
+ }
205
+ if (!firstFrame) {
206
+ if (!handle.interrupted) {
207
+ handle.transcriptionFwd.markTextComplete();
208
+ }
209
+ this.emit("playout_stopped", handle.interrupted);
210
+ }
211
+ handle.doneFut.resolve();
212
+ await handle.transcriptionFwd.close(handle.interrupted);
213
+ }
214
+ resolve();
215
+ } catch (error) {
216
+ reject(error);
217
+ }
218
+ })();
219
+ });
220
+ }
221
+ }
222
+ // Annotate the CommonJS export names for ESM import in node:
223
+ 0 && (module.exports = {
224
+ AgentPlayout,
225
+ PlayoutHandle,
226
+ proto
227
+ });
228
+ //# sourceMappingURL=agent_playout.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/multimodal/agent_playout.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { type AudioSource } from '@livekit/rtc-node';\nimport { EventEmitter } from 'node:events';\nimport { AudioByteStream } from '../audio.js';\nimport type { TranscriptionForwarder } from '../transcription.js';\nimport { type AsyncIterableQueue, CancellablePromise, Future, gracefullyCancel } from '../utils.js';\n\nexport const proto = {};\n\nexport class PlayoutHandle extends EventEmitter {\n #audioSource: AudioSource;\n #sampleRate: number;\n #itemId: string;\n #contentIndex: number;\n /** @internal */\n transcriptionFwd: TranscriptionForwarder;\n /** @internal */\n doneFut: Future;\n /** @internal */\n intFut: Future;\n /** @internal */\n #interrupted: boolean;\n /** @internal */\n pushedDuration: number;\n /** @internal */\n totalPlayedTime: number | undefined; // Set when playout is done\n\n constructor(\n audioSource: AudioSource,\n sampleRate: number,\n itemId: string,\n contentIndex: number,\n transcriptionFwd: TranscriptionForwarder,\n ) {\n super();\n this.#audioSource = audioSource;\n this.#sampleRate = sampleRate;\n this.#itemId = itemId;\n this.#contentIndex = contentIndex;\n this.transcriptionFwd = transcriptionFwd;\n this.doneFut = new Future();\n this.intFut = new Future();\n this.#interrupted = false;\n this.pushedDuration = 0;\n this.totalPlayedTime = undefined;\n }\n\n get itemId(): string {\n return this.#itemId;\n }\n\n get audioSamples(): number {\n if (this.totalPlayedTime !== undefined) {\n return Math.floor(this.totalPlayedTime * this.#sampleRate);\n }\n\n return Math.floor(\n (this.pushedDuration - this.#audioSource.queuedDuration) * (this.#sampleRate / 1000),\n );\n }\n\n get textChars(): number {\n return this.transcriptionFwd.currentCharacterIndex;\n }\n\n get contentIndex(): number {\n return this.#contentIndex;\n }\n\n get interrupted(): boolean {\n return this.#interrupted;\n }\n\n get done(): boolean {\n return this.doneFut.done || this.#interrupted;\n }\n\n interrupt() {\n if (this.doneFut.done) return;\n this.intFut.resolve();\n this.#interrupted = true;\n }\n}\n\nexport class AgentPlayout extends EventEmitter {\n #audioSource: AudioSource;\n #playoutTask: CancellablePromise<void> | null;\n #sampleRate: number;\n #numChannels: number;\n #inFrameSize: number;\n #outFrameSize: number;\n constructor(\n audioSource: AudioSource,\n sampleRate: number,\n numChannels: number,\n inFrameSize: number,\n outFrameSize: number,\n ) {\n super();\n this.#audioSource = audioSource;\n this.#playoutTask = null;\n this.#sampleRate = sampleRate;\n this.#numChannels = numChannels;\n this.#inFrameSize = inFrameSize;\n this.#outFrameSize = outFrameSize;\n }\n\n play(\n itemId: string,\n contentIndex: number,\n transcriptionFwd: TranscriptionForwarder,\n textStream: AsyncIterableQueue<string>,\n audioStream: AsyncIterableQueue<AudioFrame>,\n ): PlayoutHandle {\n const handle = new PlayoutHandle(\n this.#audioSource,\n this.#sampleRate,\n itemId,\n contentIndex,\n transcriptionFwd,\n );\n this.#playoutTask = this.#makePlayoutTask(this.#playoutTask, handle, textStream, audioStream);\n return handle;\n }\n\n #makePlayoutTask(\n oldTask: CancellablePromise<void> | null,\n handle: PlayoutHandle,\n textStream: AsyncIterableQueue<string>,\n audioStream: AsyncIterableQueue<AudioFrame>,\n ): CancellablePromise<void> {\n return new CancellablePromise<void>((resolve, reject, onCancel) => {\n let cancelled = false;\n onCancel(() => {\n cancelled = true;\n });\n\n (async () => {\n try {\n if (oldTask) {\n await gracefullyCancel(oldTask);\n }\n\n let firstFrame = true;\n\n const readText = () =>\n new CancellablePromise<void>((resolveText, rejectText, onCancelText) => {\n let cancelledText = false;\n onCancelText(() => {\n cancelledText = true;\n });\n\n (async () => {\n try {\n for await (const text of textStream) {\n if (cancelledText || cancelled) {\n break;\n }\n handle.transcriptionFwd.pushText(text);\n }\n resolveText();\n } catch (error) {\n rejectText(error);\n }\n })();\n });\n\n const capture = () =>\n new CancellablePromise<void>((resolveCapture, rejectCapture, onCancelCapture) => {\n let cancelledCapture = false;\n onCancelCapture(() => {\n cancelledCapture = true;\n });\n\n (async () => {\n try {\n const samplesPerChannel = this.#outFrameSize;\n const bstream = new AudioByteStream(\n this.#sampleRate,\n this.#numChannels,\n samplesPerChannel,\n );\n\n for await (const frame of audioStream) {\n if (cancelledCapture || cancelled) {\n break;\n }\n if (firstFrame) {\n handle.transcriptionFwd.start();\n this.emit('playout_started');\n firstFrame = false;\n }\n\n handle.transcriptionFwd.pushAudio(frame);\n\n for (const f of bstream.write(frame.data.buffer)) {\n handle.pushedDuration += (f.samplesPerChannel / f.sampleRate) * 1000;\n await this.#audioSource.captureFrame(f);\n }\n }\n\n if (!cancelledCapture && !cancelled) {\n for (const f of bstream.flush()) {\n handle.pushedDuration += (f.samplesPerChannel / f.sampleRate) * 1000;\n await this.#audioSource.captureFrame(f);\n }\n\n handle.transcriptionFwd.markAudioComplete();\n\n await this.#audioSource.waitForPlayout();\n }\n\n resolveCapture();\n } catch (error) {\n rejectCapture(error);\n }\n })();\n });\n\n const readTextTask = readText();\n const captureTask = capture();\n\n try {\n await Promise.race([captureTask, handle.intFut.await]);\n } finally {\n if (!captureTask.isCancelled) {\n await gracefullyCancel(captureTask);\n }\n\n handle.totalPlayedTime = handle.pushedDuration - this.#audioSource.queuedDuration;\n\n if (handle.interrupted || captureTask.error) {\n this.#audioSource.clearQueue(); // make sure to remove any queued frames\n }\n\n if (!readTextTask.isCancelled) {\n await gracefullyCancel(readTextTask);\n }\n\n if (!firstFrame) {\n if (!handle.interrupted) {\n handle.transcriptionFwd.markTextComplete();\n }\n\n this.emit('playout_stopped', handle.interrupted);\n }\n\n handle.doneFut.resolve();\n await handle.transcriptionFwd.close(handle.interrupted);\n }\n\n resolve();\n } catch (error) {\n reject(error);\n }\n })();\n });\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,4 @@
1
- /// <reference types="node" />
1
+ /// <reference types="node" resolution-mode="require"/>
2
2
  import type { AudioFrame } from '@livekit/rtc-node';
3
3
  import { type AudioSource } from '@livekit/rtc-node';
4
4
  import { EventEmitter } from 'node:events';
@@ -1,189 +1,202 @@
1
- import { EventEmitter } from 'node:events';
2
- import { AudioByteStream } from '../audio.js';
3
- import { CancellablePromise, Future, gracefullyCancel } from '../utils.js';
4
- export const proto = {};
5
- export class PlayoutHandle extends EventEmitter {
6
- #audioSource;
7
- #sampleRate;
8
- #itemId;
9
- #contentIndex;
10
- /** @internal */
11
- transcriptionFwd;
12
- /** @internal */
13
- doneFut;
14
- /** @internal */
15
- intFut;
16
- /** @internal */
17
- #interrupted;
18
- /** @internal */
19
- pushedDuration;
20
- /** @internal */
21
- totalPlayedTime; // Set when playout is done
22
- constructor(audioSource, sampleRate, itemId, contentIndex, transcriptionFwd) {
23
- super();
24
- this.#audioSource = audioSource;
25
- this.#sampleRate = sampleRate;
26
- this.#itemId = itemId;
27
- this.#contentIndex = contentIndex;
28
- this.transcriptionFwd = transcriptionFwd;
29
- this.doneFut = new Future();
30
- this.intFut = new Future();
31
- this.#interrupted = false;
32
- this.pushedDuration = 0;
33
- this.totalPlayedTime = undefined;
34
- }
35
- get itemId() {
36
- return this.#itemId;
37
- }
38
- get audioSamples() {
39
- if (this.totalPlayedTime !== undefined) {
40
- return Math.floor(this.totalPlayedTime * this.#sampleRate);
41
- }
42
- return Math.floor((this.pushedDuration - this.#audioSource.queuedDuration) * (this.#sampleRate / 1000));
43
- }
44
- get textChars() {
45
- return this.transcriptionFwd.currentCharacterIndex;
46
- }
47
- get contentIndex() {
48
- return this.#contentIndex;
49
- }
50
- get interrupted() {
51
- return this.#interrupted;
52
- }
53
- get done() {
54
- return this.doneFut.done || this.#interrupted;
55
- }
56
- interrupt() {
57
- if (this.doneFut.done)
58
- return;
59
- this.intFut.resolve();
60
- this.#interrupted = true;
1
+ import { EventEmitter } from "node:events";
2
+ import { AudioByteStream } from "../audio.js";
3
+ import { CancellablePromise, Future, gracefullyCancel } from "../utils.js";
4
+ const proto = {};
5
+ class PlayoutHandle extends EventEmitter {
6
+ #audioSource;
7
+ #sampleRate;
8
+ #itemId;
9
+ #contentIndex;
10
+ /** @internal */
11
+ transcriptionFwd;
12
+ /** @internal */
13
+ doneFut;
14
+ /** @internal */
15
+ intFut;
16
+ /** @internal */
17
+ #interrupted;
18
+ /** @internal */
19
+ pushedDuration;
20
+ /** @internal */
21
+ totalPlayedTime;
22
+ // Set when playout is done
23
+ constructor(audioSource, sampleRate, itemId, contentIndex, transcriptionFwd) {
24
+ super();
25
+ this.#audioSource = audioSource;
26
+ this.#sampleRate = sampleRate;
27
+ this.#itemId = itemId;
28
+ this.#contentIndex = contentIndex;
29
+ this.transcriptionFwd = transcriptionFwd;
30
+ this.doneFut = new Future();
31
+ this.intFut = new Future();
32
+ this.#interrupted = false;
33
+ this.pushedDuration = 0;
34
+ this.totalPlayedTime = void 0;
35
+ }
36
+ get itemId() {
37
+ return this.#itemId;
38
+ }
39
+ get audioSamples() {
40
+ if (this.totalPlayedTime !== void 0) {
41
+ return Math.floor(this.totalPlayedTime * this.#sampleRate);
61
42
  }
43
+ return Math.floor(
44
+ (this.pushedDuration - this.#audioSource.queuedDuration) * (this.#sampleRate / 1e3)
45
+ );
46
+ }
47
+ get textChars() {
48
+ return this.transcriptionFwd.currentCharacterIndex;
49
+ }
50
+ get contentIndex() {
51
+ return this.#contentIndex;
52
+ }
53
+ get interrupted() {
54
+ return this.#interrupted;
55
+ }
56
+ get done() {
57
+ return this.doneFut.done || this.#interrupted;
58
+ }
59
+ interrupt() {
60
+ if (this.doneFut.done) return;
61
+ this.intFut.resolve();
62
+ this.#interrupted = true;
63
+ }
62
64
  }
63
- export class AgentPlayout extends EventEmitter {
64
- #audioSource;
65
- #playoutTask;
66
- #sampleRate;
67
- #numChannels;
68
- #inFrameSize;
69
- #outFrameSize;
70
- constructor(audioSource, sampleRate, numChannels, inFrameSize, outFrameSize) {
71
- super();
72
- this.#audioSource = audioSource;
73
- this.#playoutTask = null;
74
- this.#sampleRate = sampleRate;
75
- this.#numChannels = numChannels;
76
- this.#inFrameSize = inFrameSize;
77
- this.#outFrameSize = outFrameSize;
78
- }
79
- play(itemId, contentIndex, transcriptionFwd, textStream, audioStream) {
80
- const handle = new PlayoutHandle(this.#audioSource, this.#sampleRate, itemId, contentIndex, transcriptionFwd);
81
- this.#playoutTask = this.#makePlayoutTask(this.#playoutTask, handle, textStream, audioStream);
82
- return handle;
83
- }
84
- #makePlayoutTask(oldTask, handle, textStream, audioStream) {
85
- return new CancellablePromise((resolve, reject, onCancel) => {
86
- let cancelled = false;
87
- onCancel(() => {
88
- cancelled = true;
65
+ class AgentPlayout extends EventEmitter {
66
+ #audioSource;
67
+ #playoutTask;
68
+ #sampleRate;
69
+ #numChannels;
70
+ #inFrameSize;
71
+ #outFrameSize;
72
+ constructor(audioSource, sampleRate, numChannels, inFrameSize, outFrameSize) {
73
+ super();
74
+ this.#audioSource = audioSource;
75
+ this.#playoutTask = null;
76
+ this.#sampleRate = sampleRate;
77
+ this.#numChannels = numChannels;
78
+ this.#inFrameSize = inFrameSize;
79
+ this.#outFrameSize = outFrameSize;
80
+ }
81
+ play(itemId, contentIndex, transcriptionFwd, textStream, audioStream) {
82
+ const handle = new PlayoutHandle(
83
+ this.#audioSource,
84
+ this.#sampleRate,
85
+ itemId,
86
+ contentIndex,
87
+ transcriptionFwd
88
+ );
89
+ this.#playoutTask = this.#makePlayoutTask(this.#playoutTask, handle, textStream, audioStream);
90
+ return handle;
91
+ }
92
+ #makePlayoutTask(oldTask, handle, textStream, audioStream) {
93
+ return new CancellablePromise((resolve, reject, onCancel) => {
94
+ let cancelled = false;
95
+ onCancel(() => {
96
+ cancelled = true;
97
+ });
98
+ (async () => {
99
+ try {
100
+ if (oldTask) {
101
+ await gracefullyCancel(oldTask);
102
+ }
103
+ let firstFrame = true;
104
+ const readText = () => new CancellablePromise((resolveText, rejectText, onCancelText) => {
105
+ let cancelledText = false;
106
+ onCancelText(() => {
107
+ cancelledText = true;
108
+ });
109
+ (async () => {
110
+ try {
111
+ for await (const text of textStream) {
112
+ if (cancelledText || cancelled) {
113
+ break;
114
+ }
115
+ handle.transcriptionFwd.pushText(text);
116
+ }
117
+ resolveText();
118
+ } catch (error) {
119
+ rejectText(error);
120
+ }
121
+ })();
122
+ });
123
+ const capture = () => new CancellablePromise((resolveCapture, rejectCapture, onCancelCapture) => {
124
+ let cancelledCapture = false;
125
+ onCancelCapture(() => {
126
+ cancelledCapture = true;
89
127
  });
90
128
  (async () => {
91
- try {
92
- if (oldTask) {
93
- await gracefullyCancel(oldTask);
94
- }
95
- let firstFrame = true;
96
- const readText = () => new CancellablePromise((resolveText, rejectText, onCancelText) => {
97
- let cancelledText = false;
98
- onCancelText(() => {
99
- cancelledText = true;
100
- });
101
- (async () => {
102
- try {
103
- for await (const text of textStream) {
104
- if (cancelledText || cancelled) {
105
- break;
106
- }
107
- handle.transcriptionFwd.pushText(text);
108
- }
109
- resolveText();
110
- }
111
- catch (error) {
112
- rejectText(error);
113
- }
114
- })();
115
- });
116
- const capture = () => new CancellablePromise((resolveCapture, rejectCapture, onCancelCapture) => {
117
- let cancelledCapture = false;
118
- onCancelCapture(() => {
119
- cancelledCapture = true;
120
- });
121
- (async () => {
122
- try {
123
- const samplesPerChannel = this.#outFrameSize;
124
- const bstream = new AudioByteStream(this.#sampleRate, this.#numChannels, samplesPerChannel);
125
- for await (const frame of audioStream) {
126
- if (cancelledCapture || cancelled) {
127
- break;
128
- }
129
- if (firstFrame) {
130
- handle.transcriptionFwd.start();
131
- this.emit('playout_started');
132
- firstFrame = false;
133
- }
134
- handle.transcriptionFwd.pushAudio(frame);
135
- for (const f of bstream.write(frame.data.buffer)) {
136
- handle.pushedDuration += (f.samplesPerChannel / f.sampleRate) * 1000;
137
- await this.#audioSource.captureFrame(f);
138
- }
139
- }
140
- if (!cancelledCapture && !cancelled) {
141
- for (const f of bstream.flush()) {
142
- handle.pushedDuration += (f.samplesPerChannel / f.sampleRate) * 1000;
143
- await this.#audioSource.captureFrame(f);
144
- }
145
- handle.transcriptionFwd.markAudioComplete();
146
- await this.#audioSource.waitForPlayout();
147
- }
148
- resolveCapture();
149
- }
150
- catch (error) {
151
- rejectCapture(error);
152
- }
153
- })();
154
- });
155
- const readTextTask = readText();
156
- const captureTask = capture();
157
- try {
158
- await Promise.race([captureTask, handle.intFut.await]);
159
- }
160
- finally {
161
- if (!captureTask.isCancelled) {
162
- await gracefullyCancel(captureTask);
163
- }
164
- handle.totalPlayedTime = handle.pushedDuration - this.#audioSource.queuedDuration;
165
- if (handle.interrupted || captureTask.error) {
166
- this.#audioSource.clearQueue(); // make sure to remove any queued frames
167
- }
168
- if (!readTextTask.isCancelled) {
169
- await gracefullyCancel(readTextTask);
170
- }
171
- if (!firstFrame) {
172
- if (!handle.interrupted) {
173
- handle.transcriptionFwd.markTextComplete();
174
- }
175
- this.emit('playout_stopped', handle.interrupted);
176
- }
177
- handle.doneFut.resolve();
178
- await handle.transcriptionFwd.close(handle.interrupted);
179
- }
180
- resolve();
129
+ try {
130
+ const samplesPerChannel = this.#outFrameSize;
131
+ const bstream = new AudioByteStream(
132
+ this.#sampleRate,
133
+ this.#numChannels,
134
+ samplesPerChannel
135
+ );
136
+ for await (const frame of audioStream) {
137
+ if (cancelledCapture || cancelled) {
138
+ break;
139
+ }
140
+ if (firstFrame) {
141
+ handle.transcriptionFwd.start();
142
+ this.emit("playout_started");
143
+ firstFrame = false;
144
+ }
145
+ handle.transcriptionFwd.pushAudio(frame);
146
+ for (const f of bstream.write(frame.data.buffer)) {
147
+ handle.pushedDuration += f.samplesPerChannel / f.sampleRate * 1e3;
148
+ await this.#audioSource.captureFrame(f);
149
+ }
181
150
  }
182
- catch (error) {
183
- reject(error);
151
+ if (!cancelledCapture && !cancelled) {
152
+ for (const f of bstream.flush()) {
153
+ handle.pushedDuration += f.samplesPerChannel / f.sampleRate * 1e3;
154
+ await this.#audioSource.captureFrame(f);
155
+ }
156
+ handle.transcriptionFwd.markAudioComplete();
157
+ await this.#audioSource.waitForPlayout();
184
158
  }
159
+ resolveCapture();
160
+ } catch (error) {
161
+ rejectCapture(error);
162
+ }
185
163
  })();
186
- });
187
- }
164
+ });
165
+ const readTextTask = readText();
166
+ const captureTask = capture();
167
+ try {
168
+ await Promise.race([captureTask, handle.intFut.await]);
169
+ } finally {
170
+ if (!captureTask.isCancelled) {
171
+ await gracefullyCancel(captureTask);
172
+ }
173
+ handle.totalPlayedTime = handle.pushedDuration - this.#audioSource.queuedDuration;
174
+ if (handle.interrupted || captureTask.error) {
175
+ this.#audioSource.clearQueue();
176
+ }
177
+ if (!readTextTask.isCancelled) {
178
+ await gracefullyCancel(readTextTask);
179
+ }
180
+ if (!firstFrame) {
181
+ if (!handle.interrupted) {
182
+ handle.transcriptionFwd.markTextComplete();
183
+ }
184
+ this.emit("playout_stopped", handle.interrupted);
185
+ }
186
+ handle.doneFut.resolve();
187
+ await handle.transcriptionFwd.close(handle.interrupted);
188
+ }
189
+ resolve();
190
+ } catch (error) {
191
+ reject(error);
192
+ }
193
+ })();
194
+ });
195
+ }
188
196
  }
197
+ export {
198
+ AgentPlayout,
199
+ PlayoutHandle,
200
+ proto
201
+ };
189
202
  //# sourceMappingURL=agent_playout.js.map