From 88bb78fb23094b417c8eacd81619759a551814a4 Mon Sep 17 00:00:00 2001 From: retoor Date: Sun, 29 Jun 2025 20:56:44 +0200 Subject: [PATCH] Update. --- src/snek/static/stt.js | 52 ++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/snek/static/stt.js b/src/snek/static/stt.js index da462f8..4ee6363 100644 --- a/src/snek/static/stt.js +++ b/src/snek/static/stt.js @@ -1,22 +1,19 @@ class STTButton extends HTMLElement { - /** monitor target attribute so it can change on-the-fly */ static get observedAttributes() { return ['target']; } simulateTypingWithEvents(element, text, delay = 100) { let resolver = null; - let promise = new Promise((resolve) => { - resolver = resolve; - }); + const promise = new Promise((resolve) => resolver = resolve); let index = 0; - function triggerEvent(type, key) { + const triggerEvent = (type, key) => { const event = new KeyboardEvent(type, { key: key, bubbles: true, cancelable: true, }); element.dispatchEvent(event); - } + }; const interval = setInterval(() => { if (index < text.length) { @@ -32,7 +29,6 @@ class STTButton extends HTMLElement { triggerEvent('keypress', char); triggerEvent('keyup', char); - index++; } else { clearInterval(interval); @@ -58,8 +54,8 @@ class STTButton extends HTMLElement { button { all:unset; cursor:pointer; } button:hover { background:#e8e8e8; } :host([listening]) button { - background:#d32f2f; color:#fff; - animation:pulse 1.2s ease-in-out infinite; } + background:#d32f2f; color:#fff; + animation:pulse 1.2s ease-in-out infinite; } @keyframes pulse { 0%,100% { transform:scale(1); box-shadow:0 0 0 0 rgba(211,47,47,.6);} 50% { transform:scale(1.12);box-shadow:0 0 0 12px rgba(211,47,47,0);} @@ -80,12 +76,14 @@ class STTButton extends HTMLElement { let interim = ''; let committed = ''; + let previousInterim = ''; this.recog.onresult = (e) => { interim = ''; for (let i = e.resultIndex; i < e.results.length; i++) { const res = e.results[i]; - const txt = res[0].transcript.trim(); + const alt = res[0]; + const txt = alt.transcript.trim(); if (res.isFinal) { const sentence = txt.charAt(0).toUpperCase() + txt.slice(1); @@ -94,26 +92,46 @@ class STTButton extends HTMLElement { committed += punctuated + ' '; if (this.targetEl) { this.targetEl.focus(); - punctuated = punctuated.replace(/\./g, ".\n"); - punctuated = punctuated.replace(/\?/g, "?\n"); - punctuated = punctuated.replace(/\!/g, "!\n"); + punctuated = punctuated.replace(/\./g, ".\n") + .replace(/\?/g, "?\n") + .replace(/\!/g, "!\n"); - this.simulateTypingWithEvents(this.targetEl, punctuated, 1).then(() => { + this.targetEl.value = ''; // punctuated; + this.simulateTypingWithEvents(this.targetEl, punctuated, 1).then(() => { const chatInput = document.querySelector('chat-input'); chatInput.finalizeMessage(); }); } + + previousInterim = ''; } else { - interim += txt + ' '; + if (alt.confidence >= 0.85) { + interim += txt + ' '; + } } } + + if (interim && this.targetEl) { + const el = this.targetEl; + el.focus(); + + if (el.isContentEditable) { + el.innerText = el.innerText.replace(new RegExp(previousInterim + '$'), interim); + } else { + el.value = interim + //el.value = el.value.replace(new RegExp(previousInterim + '$'), interim); + } + /* + this.simulateTypingWithEvents(el, interim, 0).then(() => { + previousInterim = interim; + });*/ + } }; this.recog.onend = () => { - // Auto-restart recognition unless we explicitly stopped if (this.listening) { try { - this.recog.start(); // attempt restart + this.recog.start(); } catch (e) { console.warn('Failed to restart speech recognition:', e); }