@livekit/agents 0.4.6 → 0.5.0
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/README.md +17 -0
- package/dist/audio.cjs +77 -0
- package/dist/audio.cjs.map +1 -0
- package/dist/audio.js +48 -37
- package/dist/audio.js.map +1 -1
- package/dist/cli.cjs +131 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +96 -122
- package/dist/cli.js.map +1 -1
- package/dist/generator.cjs +36 -0
- package/dist/generator.cjs.map +1 -0
- package/dist/generator.js +8 -22
- package/dist/generator.js.map +1 -1
- package/dist/http_server.cjs +72 -0
- package/dist/http_server.cjs.map +1 -0
- package/dist/http_server.d.ts +1 -1
- package/dist/http_server.js +44 -47
- package/dist/http_server.js.map +1 -1
- package/dist/index.cjs +78 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +26 -28
- package/dist/index.js.map +1 -1
- package/dist/ipc/job_executor.cjs +33 -0
- package/dist/ipc/job_executor.cjs.map +1 -0
- package/dist/ipc/job_executor.js +7 -4
- package/dist/ipc/job_executor.js.map +1 -1
- package/dist/ipc/job_main.cjs +147 -0
- package/dist/ipc/job_main.cjs.map +1 -0
- package/dist/ipc/job_main.d.ts +1 -1
- package/dist/ipc/job_main.js +103 -103
- package/dist/ipc/job_main.js.map +1 -1
- package/dist/ipc/message.cjs +17 -0
- package/dist/ipc/message.cjs.map +1 -0
- package/dist/ipc/message.js +0 -1
- package/dist/ipc/message.js.map +1 -1
- package/dist/ipc/proc_job_executor.cjs +174 -0
- package/dist/ipc/proc_job_executor.cjs.map +1 -0
- package/dist/ipc/proc_job_executor.js +130 -126
- package/dist/ipc/proc_job_executor.js.map +1 -1
- package/dist/ipc/proc_pool.cjs +126 -0
- package/dist/ipc/proc_pool.cjs.map +1 -0
- package/dist/ipc/proc_pool.js +93 -96
- package/dist/ipc/proc_pool.js.map +1 -1
- package/dist/job.cjs +230 -0
- package/dist/job.cjs.map +1 -0
- package/dist/job.js +195 -198
- package/dist/job.js.map +1 -1
- package/dist/llm/chat_context.cjs +131 -0
- package/dist/llm/chat_context.cjs.map +1 -0
- package/dist/llm/chat_context.js +98 -86
- package/dist/llm/chat_context.js.map +1 -1
- package/dist/llm/function_context.cjs +103 -0
- package/dist/llm/function_context.cjs.map +1 -0
- package/dist/llm/function_context.js +72 -81
- package/dist/llm/function_context.js.map +1 -1
- package/dist/llm/function_context.test.cjs +218 -0
- package/dist/llm/function_context.test.cjs.map +1 -0
- package/dist/llm/function_context.test.js +209 -210
- package/dist/llm/function_context.test.js.map +1 -1
- package/dist/llm/index.cjs +43 -0
- package/dist/llm/index.cjs.map +1 -0
- package/dist/llm/index.js +22 -6
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/llm.cjs +76 -0
- package/dist/llm/llm.cjs.map +1 -0
- package/dist/llm/llm.js +48 -42
- package/dist/llm/llm.js.map +1 -1
- package/dist/log.cjs +57 -0
- package/dist/log.cjs.map +1 -0
- package/dist/log.js +27 -26
- package/dist/log.js.map +1 -1
- package/dist/multimodal/agent_playout.cjs +228 -0
- package/dist/multimodal/agent_playout.cjs.map +1 -0
- package/dist/multimodal/agent_playout.d.ts +1 -1
- package/dist/multimodal/agent_playout.js +193 -180
- package/dist/multimodal/agent_playout.js.map +1 -1
- package/dist/multimodal/index.cjs +25 -0
- package/dist/multimodal/index.cjs.map +1 -0
- package/dist/multimodal/index.js +2 -5
- package/dist/multimodal/index.js.map +1 -1
- package/dist/multimodal/multimodal_agent.cjs +404 -0
- package/dist/multimodal/multimodal_agent.cjs.map +1 -0
- package/dist/multimodal/multimodal_agent.d.ts +1 -1
- package/dist/multimodal/multimodal_agent.js +351 -330
- package/dist/multimodal/multimodal_agent.js.map +1 -1
- package/dist/pipeline/agent_output.cjs +172 -0
- package/dist/pipeline/agent_output.cjs.map +1 -0
- package/dist/pipeline/agent_output.js +136 -138
- package/dist/pipeline/agent_output.js.map +1 -1
- package/dist/pipeline/agent_playout.cjs +169 -0
- package/dist/pipeline/agent_playout.cjs.map +1 -0
- package/dist/pipeline/agent_playout.js +126 -136
- package/dist/pipeline/agent_playout.js.map +1 -1
- package/dist/pipeline/human_input.cjs +158 -0
- package/dist/pipeline/human_input.cjs.map +1 -0
- package/dist/pipeline/human_input.js +124 -125
- package/dist/pipeline/human_input.js.map +1 -1
- package/dist/pipeline/index.cjs +31 -0
- package/dist/pipeline/index.cjs.map +1 -0
- package/dist/pipeline/index.js +8 -4
- package/dist/pipeline/index.js.map +1 -1
- package/dist/pipeline/pipeline_agent.cjs +642 -0
- package/dist/pipeline/pipeline_agent.cjs.map +1 -0
- package/dist/pipeline/pipeline_agent.js +595 -651
- package/dist/pipeline/pipeline_agent.js.map +1 -1
- package/dist/pipeline/speech_handle.cjs +128 -0
- package/dist/pipeline/speech_handle.cjs.map +1 -0
- package/dist/pipeline/speech_handle.js +102 -100
- package/dist/pipeline/speech_handle.js.map +1 -1
- package/dist/plugin.cjs +46 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.js +20 -20
- package/dist/plugin.js.map +1 -1
- package/dist/stt/index.cjs +38 -0
- package/dist/stt/index.cjs.map +1 -0
- package/dist/stt/index.js +13 -5
- package/dist/stt/index.js.map +1 -1
- package/dist/stt/stream_adapter.cjs +87 -0
- package/dist/stt/stream_adapter.cjs.map +1 -0
- package/dist/stt/stream_adapter.js +58 -55
- package/dist/stt/stream_adapter.js.map +1 -1
- package/dist/stt/stt.cjs +98 -0
- package/dist/stt/stt.cjs.map +1 -0
- package/dist/stt/stt.js +63 -98
- package/dist/stt/stt.js.map +1 -1
- package/dist/tokenize/basic/basic.cjs +98 -0
- package/dist/tokenize/basic/basic.cjs.map +1 -0
- package/dist/tokenize/basic/basic.js +56 -45
- package/dist/tokenize/basic/basic.js.map +1 -1
- package/dist/tokenize/basic/hyphenator.cjs +425 -0
- package/dist/tokenize/basic/hyphenator.cjs.map +1 -0
- package/dist/tokenize/basic/hyphenator.js +66 -82
- package/dist/tokenize/basic/hyphenator.js.map +1 -1
- package/dist/tokenize/basic/index.cjs +35 -0
- package/dist/tokenize/basic/index.cjs.map +1 -0
- package/dist/tokenize/basic/index.js +7 -4
- package/dist/tokenize/basic/index.js.map +1 -1
- package/dist/tokenize/basic/paragraph.cjs +57 -0
- package/dist/tokenize/basic/paragraph.cjs.map +1 -0
- package/dist/tokenize/basic/paragraph.js +30 -35
- package/dist/tokenize/basic/paragraph.js.map +1 -1
- package/dist/tokenize/basic/sentence.cjs +83 -0
- package/dist/tokenize/basic/sentence.cjs.map +1 -0
- package/dist/tokenize/basic/sentence.js +56 -57
- package/dist/tokenize/basic/sentence.js.map +1 -1
- package/dist/tokenize/basic/word.cjs +44 -0
- package/dist/tokenize/basic/word.cjs.map +1 -0
- package/dist/tokenize/basic/word.js +17 -20
- package/dist/tokenize/basic/word.js.map +1 -1
- package/dist/tokenize/index.cjs +55 -0
- package/dist/tokenize/index.cjs.map +1 -0
- package/dist/tokenize/index.js +18 -7
- package/dist/tokenize/index.js.map +1 -1
- package/dist/tokenize/token_stream.cjs +164 -0
- package/dist/tokenize/token_stream.cjs.map +1 -0
- package/dist/tokenize/token_stream.js +133 -139
- package/dist/tokenize/token_stream.js.map +1 -1
- package/dist/tokenize/tokenizer.cjs +184 -0
- package/dist/tokenize/tokenizer.cjs.map +1 -0
- package/dist/tokenize/tokenizer.js +138 -99
- package/dist/tokenize/tokenizer.js.map +1 -1
- package/dist/transcription.cjs +131 -0
- package/dist/transcription.cjs.map +1 -0
- package/dist/transcription.js +99 -96
- package/dist/transcription.js.map +1 -1
- package/dist/tts/index.cjs +38 -0
- package/dist/tts/index.cjs.map +1 -0
- package/dist/tts/index.js +13 -5
- package/dist/tts/index.js.map +1 -1
- package/dist/tts/stream_adapter.cjs +78 -0
- package/dist/tts/stream_adapter.cjs.map +1 -0
- package/dist/tts/stream_adapter.js +50 -47
- package/dist/tts/stream_adapter.js.map +1 -1
- package/dist/tts/tts.cjs +127 -0
- package/dist/tts/tts.cjs.map +1 -0
- package/dist/tts/tts.js +90 -120
- package/dist/tts/tts.js.map +1 -1
- package/dist/utils.cjs +284 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.js +242 -247
- package/dist/utils.js.map +1 -1
- package/dist/vad.cjs +92 -0
- package/dist/vad.cjs.map +1 -0
- package/dist/vad.js +57 -52
- package/dist/vad.js.map +1 -1
- package/dist/version.cjs +29 -0
- package/dist/version.cjs.map +1 -0
- package/dist/version.js +4 -4
- package/dist/version.js.map +1 -1
- package/dist/worker.cjs +576 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +511 -484
- package/dist/worker.js.map +1 -1
- package/package.json +18 -8
- package/src/ipc/job_main.ts +66 -64
- package/src/pipeline/pipeline_agent.ts +23 -23
|
@@ -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,189 +1,202 @@
|
|
|
1
|
-
import { EventEmitter } from
|
|
2
|
-
import { AudioByteStream } from
|
|
3
|
-
import { CancellablePromise, Future, gracefullyCancel } from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
183
|
-
|
|
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
|