Stabilize Athena Talk audio delivery
This commit is contained in:
+15
-11
@@ -107,6 +107,7 @@ class AthenaTalkBridge {
|
||||
prefixBytes = 0;
|
||||
silenceTimer;
|
||||
active;
|
||||
transcribing = false;
|
||||
generation = 0;
|
||||
constructor(req, cfg) {
|
||||
this.req = req;
|
||||
@@ -122,6 +123,8 @@ class AthenaTalkBridge {
|
||||
sendAudio(chunk) {
|
||||
if (!this.isConnected() || chunk.length === 0)
|
||||
return;
|
||||
if (this.transcribing || this.active)
|
||||
return;
|
||||
const voiced = pcmRms(chunk) >= this.cfg.vadThreshold;
|
||||
const maxPrefix = Math.round(24000 * 2 * this.cfg.prefixPaddingMs / 1000);
|
||||
if (!this.speaking) {
|
||||
@@ -132,12 +135,6 @@ class AthenaTalkBridge {
|
||||
}
|
||||
if (!voiced)
|
||||
return;
|
||||
if (this.active) {
|
||||
this.active.abort();
|
||||
this.active = undefined;
|
||||
this.generation += 1;
|
||||
this.req.onClearAudio?.("barge-in");
|
||||
}
|
||||
this.speaking = true;
|
||||
this.speech = this.prefix;
|
||||
this.prefix = [];
|
||||
@@ -187,17 +184,22 @@ class AthenaTalkBridge {
|
||||
this.speech = [];
|
||||
if (pcm.length < 24000 * 2 * 0.25)
|
||||
return;
|
||||
this.transcribing = true;
|
||||
try {
|
||||
const text = await this.transcribe(pcm);
|
||||
if (!text || !this.isConnected())
|
||||
return;
|
||||
this.req.onTranscript?.("user", text, true);
|
||||
this.transcribing = false;
|
||||
await this.answer(text);
|
||||
}
|
||||
catch (error) {
|
||||
if (error.name !== "AbortError")
|
||||
this.req.onError?.(error);
|
||||
}
|
||||
finally {
|
||||
this.transcribing = false;
|
||||
}
|
||||
}
|
||||
async transcribe(pcm) {
|
||||
const form = new FormData();
|
||||
@@ -217,7 +219,8 @@ class AthenaTalkBridge {
|
||||
async answer(prompt) {
|
||||
if (!this.req.runAgentConsult)
|
||||
throw new Error("OpenClaw agent-consult is unavailable");
|
||||
this.active?.abort();
|
||||
if (this.active)
|
||||
return;
|
||||
const controller = new AbortController();
|
||||
this.active = controller;
|
||||
const generation = ++this.generation;
|
||||
@@ -229,17 +232,18 @@ class AthenaTalkBridge {
|
||||
const text = String(result?.text || "").trim();
|
||||
if (!text)
|
||||
return;
|
||||
this.req.onEvent?.({ direction: "server", type: "response.created", responseId });
|
||||
this.req.onTranscript?.("assistant", text, true);
|
||||
const pcm = await this.synthesize(text, controller.signal);
|
||||
if (generation !== this.generation || !this.isConnected())
|
||||
return;
|
||||
const frameBytes = 24000 * 2 / 50;
|
||||
const frameBytes = 24000 * 2 / 10;
|
||||
for (let offset = 0; offset < pcm.length; offset += frameBytes) {
|
||||
if (controller.signal.aborted || generation !== this.generation || !this.isConnected()) {
|
||||
return;
|
||||
}
|
||||
this.req.onAudio?.(pcm.subarray(offset, Math.min(offset + frameBytes, pcm.length)));
|
||||
await new Promise((resolve) => setTimeout(resolve, 20));
|
||||
await new Promise((resolve) => setTimeout(resolve, 80));
|
||||
}
|
||||
this.req.onResponseDone?.({ status: "completed", responseId });
|
||||
this.req.onEvent?.({ direction: "server", type: "response.done", responseId });
|
||||
@@ -289,8 +293,8 @@ export default definePluginEntry({
|
||||
transports: ["gateway-relay"],
|
||||
inputAudioFormats: [AUDIO_FORMAT],
|
||||
outputAudioFormats: [AUDIO_FORMAT],
|
||||
supportsBargeIn: true,
|
||||
handlesInputAudioBargeIn: true,
|
||||
supportsBargeIn: false,
|
||||
handlesInputAudioBargeIn: false,
|
||||
supportsToolCalls: true,
|
||||
supportsSessionResumption: false,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user