From cca93107f5afa628e78c28b5f548f750eaad1617 Mon Sep 17 00:00:00 2001 From: chexit Date: Sat, 14 Nov 2026 15:30:51 +0300 Subject: [PATCH] Speak a confirmation when toggling PC audio --- server/quick-actions.mjs | 1 + server/turns.mjs | 7 +++++-- test/voice.test.mjs | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/server/quick-actions.mjs b/server/quick-actions.mjs index deedc51..663809c 100644 --- a/server/quick-actions.mjs +++ b/server/quick-actions.mjs @@ -23,6 +23,7 @@ export function quickAction(transcript) { name: 'pc_audio', args: { action: enabled ? 'start' : 'stop' }, done: enabled ? 'Звук с компьютера включён.' : 'Звук с компьютера выключен.', + speakOnSuccess: true, failure: 'Не удалось переключить звук с компьютера. Проверь агент на Windows.', success: result => result?.ok === true && result.enabled === enabled, }; diff --git a/server/turns.mjs b/server/turns.mjs index 46ace3a..be23c84 100644 --- a/server/turns.mjs +++ b/server/turns.mjs @@ -51,10 +51,13 @@ export function handleTurn(client, store) { send({ type: 'transcript', text }); try { const action = quickAction(text); + let quickReply; if (action) { const result = await device.execute(action.name, action.args).catch(() => null); if (terminal) return; - if (action.success(result)) return complete(text, action.done); + const succeeded = action.success(result); + if (succeeded && !action.speakOnSuccess) return complete(text, action.done); + quickReply = succeeded ? action.done : action.failure; } tts = await openTts(settings, signal, audio => { if (terminal || client.readyState !== WebSocket.OPEN) return; @@ -62,7 +65,7 @@ export function handleTurn(client, store) { client.send(audio, { binary: true }); }); if (terminal) return; - const answer = action?.failure ?? await streamAnswer(settings, store.getHistory(), text, signal, part => tts.text(part), device.execute); + const answer = quickReply ?? await streamAnswer(settings, store.getHistory(), text, signal, part => tts.text(part), device.execute); if (action) tts.text(answer); tts.finish(); await tts.done; diff --git a/test/voice.test.mjs b/test/voice.test.mjs index 7147de6..c3ddd2c 100644 --- a/test/voice.test.mjs +++ b/test/voice.test.mjs @@ -90,5 +90,19 @@ test('voice turns stream dialogue and skip synthesis for confirmed quick actions assert.deepEqual(await turn(undefined, true), { seen: ['ready', 'done'], audio: [], calls: [] }); assert.deepEqual(recorded, ['выключи музыку.', 'Музыка на паузе.']); assert.equal(syntheses, 1); + + for (const [command, action, enabled, answer] of [ + ['включи', 'start', true, 'Звук с компьютера включён.'], + ['выключи', 'stop', false, 'Звук с компьютера выключен.'], + ]) { + transcript = `Алиса, ${command} звук с компьютера.`; + ttsText = ''; + assert.deepEqual(await turn({ ok: true, enabled }, true), { + seen: ['ready', 'transcript', 'device_tool', 'done'], + audio: [1, 2, 3, 4], + calls: [['pc_audio', { action }]], + }); + assert.equal(ttsText, answer); + } await Promise.all([new Promise(r => local.close(r)), new Promise(r => stt.close(r)), new Promise(r => tts.close(r))]); });