diff --git a/public/app.js b/public/app.js index c141528..68e45a0 100644 --- a/public/app.js +++ b/public/app.js @@ -64,6 +64,7 @@ document.addEventListener('DOMContentLoaded', () => { const userInput = document.getElementById('userInput'); const btnSend = document.getElementById('btnSend'); + const btnVoice = document.getElementById('btnVoice'); const chatForm = document.getElementById('chatForm'); const messagesContainer = document.getElementById('messagesContainer'); const welcomeContainer = document.getElementById('welcomeContainer'); @@ -90,6 +91,10 @@ document.addEventListener('DOMContentLoaded', () => { let searchQuery = ''; let activeTag = 'all'; + // Variáveis de Reconhecimento de Voz + let recognition = null; + let isListening = false; + // ========================================================================== // CONTROLES DE INTERFACE & SIDEBAR // ========================================================================== @@ -156,6 +161,83 @@ document.addEventListener('DOMContentLoaded', () => { renderHistory(); }); + // ========================================================================== + // VOZ — WEB SPEECH API (ditado) + // ========================================================================== + + const initVoiceRecognition = () => { + const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; + if (!SpeechRecognition) { + btnVoice.style.display = 'none'; + return; + } + + recognition = new SpeechRecognition(); + recognition.lang = 'pt-BR'; + recognition.continuous = false; + recognition.interimResults = false; + recognition.maxAlternatives = 1; + + recognition.onresult = (event) => { + const transcript = event.results[0][0].transcript; + userInput.value = transcript; + userInput.dispatchEvent(new Event('input')); + setVoiceState(false); + }; + + recognition.onerror = (event) => { + console.warn('Voice error:', event.error); + setVoiceState(false); + }; + + recognition.onend = () => { + setVoiceState(false); + }; + }; + + const setVoiceState = (listening) => { + isListening = listening; + if (listening) { + btnVoice.classList.add('listening'); + btnVoice.setAttribute('title', 'Clique para parar'); + } else { + btnVoice.classList.remove('listening'); + btnVoice.setAttribute('title', 'Ditar mensagem'); + } + }; + + btnVoice.addEventListener('click', () => { + if (!recognition) return; + if (isListening) { + recognition.stop(); + } else { + recognition.start(); + setVoiceState(true); + } + }); + + // ========================================================================== + // ATALHOS DE TECLADO + // ========================================================================== + + document.addEventListener('keydown', (e) => { + // Ctrl+N → novo chat + if ((e.ctrlKey || e.metaKey) && e.key === 'n') { + e.preventDefault(); + createNewChat(); + } + // Ctrl+F ou Ctrl+K → focar busca + if ((e.ctrlKey || e.metaKey) && (e.key === 'f' || e.key === 'k')) { + e.preventDefault(); + toggleSidebar(true); + setTimeout(() => searchInput.focus(), 50); + } + // Escape → fechar sidebar + if (e.key === 'Escape') { + toggleSidebar(false); + } + }); + // ========================================================================== // HISTÓRICO DE CHATS (LOCALSTORAGE) — VERSÃO COMPLETA COM PINNED, TAGS, BUSCA // ========================================================================== @@ -682,4 +764,7 @@ document.addEventListener('DOMContentLoaded', () => { } else { createNewChat(); } + + // Inicializar reconhecimento de voz + initVoiceRecognition(); }); diff --git a/public/index.html b/public/index.html index c902b9c..b09b8f6 100644 --- a/public/index.html +++ b/public/index.html @@ -155,6 +155,13 @@
+