🎤 Voz + ⌨️ Atalhos: Ctrl+N/F/K, Escape, microfone com Web Speech API
This commit is contained in:
@@ -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();
|
||||
});
|
||||
|
||||
@@ -155,6 +155,13 @@
|
||||
<form id="chatForm">
|
||||
<div class="input-box">
|
||||
<textarea id="userInput" placeholder="Mensagem Camila AI..." rows="1" autocomplete="off"></textarea>
|
||||
<button type="button" id="btnVoice" class="btn-voice" aria-label="Usar microfone" title="Ditar mensagem">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke-width="2" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19 10v2a7 7 0 0 1-14 0v-2"/>
|
||||
<line stroke-linecap="round" stroke-linejoin="round" x1="12" x2="12" y1="19" y2="22"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="submit" id="btnSend" disabled aria-label="Enviar mensagem">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M11.47 2.47a.75.75 0 0 1 1.06 0l7.5 7.5a.75.75 0 1 1-1.06 1.06l-6.22-6.22V21a.75.75 0 0 1-1.5 0V4.81L5.03 11.03a.75.75 0 0 1-1.06-1.06l7.5-7.5Z" clip-rule="evenodd" />
|
||||
|
||||
@@ -1192,6 +1192,43 @@ code {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
/* Botão de voz (microfone) */
|
||||
.btn-voice {
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
color: var(--text-muted) !important;
|
||||
border-radius: 50% !important;
|
||||
width: 32px !important;
|
||||
height: 32px !important;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: color var(--transition-fast), background-color var(--transition-fast), transform var(--transition-fast);
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.btn-voice svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.btn-voice:hover {
|
||||
color: var(--text-primary) !important;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.btn-voice.listening {
|
||||
color: #ef4444 !important;
|
||||
animation: pulse-voice 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-voice {
|
||||
0%, 100% { transform: scale(1); opacity: 1; }
|
||||
50% { transform: scale(1.15); opacity: 0.8; }
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
|
||||
Reference in New Issue
Block a user