🎤 feat: Sistema de conversa por voz - auto-TTS quando mensagem vem do microfone, envio automático, melhor visibilidade do ícone

This commit is contained in:
2026-05-26 19:55:52 +00:00
parent 6c35f7ed1b
commit 0047614bf7
2 changed files with 34 additions and 10 deletions
+24 -3
View File
@@ -288,6 +288,7 @@ const initApp = () => {
// Variáveis de Reconhecimento de Voz
let recognition = null;
let isListening = false;
let lastInputWasVoice = false; // Rastrear se a última mensagem veio do microfone
// ==========================================================================
// THEME TOGGLE — Claro/Escuro
@@ -488,13 +489,14 @@ const initApp = () => {
});
// ==========================================================================
// VOZ — WEB SPEECH API (ditado)
// VOZ — WEB SPEECH API (ditado + conversa por voz)
// ==========================================================================
const initVoiceRecognition = () => {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
if (!SpeechRecognition) {
btnVoice.style.display = 'none';
console.warn('SpeechRecognition não suportado neste navegador.');
return;
}
@@ -509,6 +511,16 @@ const initApp = () => {
userInput.value = transcript;
userInput.dispatchEvent(new Event('input'));
setVoiceState(false);
// Marca que o input veio do microfone para auto-responder por voz
lastInputWasVoice = true;
// Envia automaticamente a mensagem ditada
if (transcript.trim()) {
setTimeout(() => {
chatForm.dispatchEvent(new Event('submit', { cancelable: true }));
}, 300);
}
};
recognition.onerror = (event) => {
@@ -525,10 +537,10 @@ const initApp = () => {
isListening = listening;
if (listening) {
btnVoice.classList.add('listening');
btnVoice.setAttribute('title', 'Clique para parar');
btnVoice.setAttribute('title', 'Clique para parar de ouvir');
} else {
btnVoice.classList.remove('listening');
btnVoice.setAttribute('title', 'Ditar mensagem');
btnVoice.setAttribute('title', 'Conversar por voz');
}
};
@@ -1685,6 +1697,15 @@ const initApp = () => {
scrollToBottom();
// AUTO-TTS: Se a mensagem veio do microfone, ler a resposta em voz alta automaticamente
if (lastInputWasVoice && assistantContent && !isMediaResponse) {
console.log('[VOZ] Mensagem veio do microfone — respondendo por voz automaticamente.');
setTimeout(() => {
speakText(assistantContent, speakBtn);
}, 400);
}
lastInputWasVoice = false;
// Salvar resposta no estado e localStorage
const assistantMsg = { role: 'assistant', content: assistantContent };
chat.messages.push(assistantMsg);
+10 -7
View File
@@ -1223,10 +1223,11 @@ code {
.btn-voice {
background: none !important;
border: none !important;
color: var(--text-muted) !important;
color: var(--text-secondary, #a3a3a3) !important;
border-radius: 50% !important;
width: 32px !important;
height: 32px !important;
width: 36px !important;
height: 36px !important;
min-width: 36px !important;
display: flex;
justify-content: center;
align-items: center;
@@ -1237,17 +1238,19 @@ code {
}
.btn-voice svg {
width: 18px;
height: 18px;
width: 20px;
height: 20px;
}
.btn-voice:hover {
color: var(--text-primary) !important;
transform: scale(1.05);
color: var(--brand-green, #10a37f) !important;
background-color: rgba(16, 163, 127, 0.1) !important;
transform: scale(1.1);
}
.btn-voice.listening {
color: #ef4444 !important;
background-color: rgba(239, 68, 68, 0.12) !important;
animation: pulse-voice 1.5s ease-in-out infinite;
}