Spaces:
Runtime error
Runtime error
let recognition = null; | |
let isProcessingSpeech = false; | |
let isPlayingAudio = false; | |
const STOP_WORDS = ['alto', 'detente', 'permiteme', 'callate', 'silencio']; | |
// Elementos del DOM | |
const chatBox = document.getElementById('chatBox'); | |
const textInput = document.getElementById('textInput'); | |
const sendTextButton = document.getElementById('sendText'); | |
const modoSelect = document.getElementById('modoSelect'); | |
const modeloSelect = document.getElementById('modeloSelect'); | |
const vozSelect = document.getElementById('vozSelect'); | |
const configForm = document.getElementById('configForm'); | |
const statusLabel = document.getElementById('statusLabel'); | |
// Manejar guardado de configuraci贸n | |
if (configForm) { | |
configForm.addEventListener('submit', async (e) => { | |
e.preventDefault(); | |
const config = { | |
GOOGLE_API_KEY: document.getElementById('googleApiKey').value, | |
HUGGINGFACE_TOKEN: document.getElementById('huggingfaceToken').value, | |
OPENAI_API_KEY: document.getElementById('openaiApiKey').value | |
}; | |
try { | |
const response = await fetch('/guardar_config', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify(config) | |
}); | |
const data = await response.json(); | |
if (data.success) { | |
alert('Configuraci贸n guardada exitosamente'); | |
} else { | |
alert('Error al guardar la configuraci贸n: ' + data.error); | |
} | |
} catch (error) { | |
alert('Error al guardar la configuraci贸n: ' + error); | |
} | |
}); | |
} | |
// Manejar cambio de modelo AI | |
if (modeloSelect) { | |
modeloSelect.addEventListener('change', async function() { | |
const response = await fetch('/cambiar_modelo', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify({ modelo: this.value }) | |
}); | |
const data = await response.json(); | |
if (!data.success) { | |
alert('Error al cambiar el modelo: ' + data.error); | |
} | |
}); | |
} | |
// Manejar cambio de modelo de voz | |
if (vozSelect) { | |
vozSelect.addEventListener('change', async function() { | |
const response = await fetch('/cambiar_voz', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify({ voz: this.value }) | |
}); | |
const data = await response.json(); | |
if (!data.success) { | |
alert('Error al cambiar el modelo de voz: ' + data.error); | |
} | |
}); | |
} | |
// Manejar cambio de modo | |
modoSelect.addEventListener('change', async function() { | |
const response = await fetch('/cambiar_modo', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify({ modo: this.value }) | |
}); | |
const data = await response.json(); | |
if (data.success) { | |
addMessage(data.mensaje, 'bot'); | |
if (data.audio) { | |
await playAudio(data.audio); | |
} | |
updateStatus('Esperando activaci贸n...'); | |
} | |
}); | |
// Funci贸n para verificar si el texto contiene palabras de parada | |
function containsStopWord(text) { | |
const lowerText = text.toLowerCase(); | |
return STOP_WORDS.some(word => lowerText.includes(word)); | |
} | |
// Funci贸n para reproducir audio | |
async function playAudio(base64Audio) { | |
try { | |
console.log('Preparando reproducci贸n de audio...'); | |
isPlayingAudio = true; | |
// Detener completamente el reconocimiento | |
if (recognition) { | |
recognition.stop(); | |
recognition.abort(); | |
await new Promise(resolve => setTimeout(resolve, 500)); | |
} | |
updateStatus('Reproduciendo respuesta...'); | |
const audio = new Audio('data:audio/mp3;base64,' + base64Audio); | |
// Permitir interrupciones durante la reproducci贸n | |
recognition.start(); | |
audio.onended = () => { | |
console.log('Audio reproducido completamente'); | |
isPlayingAudio = false; | |
updateStatus('Escuchando...'); | |
}; | |
audio.play(); | |
} catch (error) { | |
console.error('Error reproduciendo audio:', error); | |
isPlayingAudio = false; | |
updateStatus('Error al reproducir audio. Escuchando...'); | |
if (!isProcessingSpeech) { | |
recognition.start(); | |
} | |
} | |
} | |
// Funci贸n para agregar mensaje al chat | |
function addMessage(text, sender) { | |
if (!text || !sender) { | |
console.error('Error: texto o remitente faltante', { text, sender }); | |
return; | |
} | |
const chatBox = document.getElementById('chatBox'); | |
if (!chatBox) { | |
console.error('Error cr铆tico: No se encontr贸 el elemento chatBox'); | |
return; | |
} | |
try { | |
console.log('Agregando mensaje al chat:', { text, sender }); | |
const messageDiv = document.createElement('div'); | |
messageDiv.className = `message ${sender}-message`; | |
const iconSpan = document.createElement('span'); | |
iconSpan.className = 'message-icon'; | |
iconSpan.textContent = sender === 'user' ? '馃懁' : '馃'; | |
const textSpan = document.createElement('span'); | |
textSpan.className = 'message-text'; | |
textSpan.textContent = text; | |
messageDiv.appendChild(iconSpan); | |
messageDiv.appendChild(textSpan); | |
chatBox.appendChild(messageDiv); | |
// Hacer scroll al 煤ltimo mensaje | |
chatBox.scrollTop = chatBox.scrollHeight; | |
console.log('Mensaje agregado exitosamente'); | |
} catch (error) { | |
console.error('Error al agregar mensaje:', error); | |
} | |
} | |
// Agregar m煤ltiples mensajes | |
function addMessages(messages) { | |
messages.forEach(msg => { | |
addMessage(msg.text, msg.sender); | |
}); | |
} | |
// Funci贸n para actualizar el estado | |
function updateStatus(text) { | |
const statusLabel = document.getElementById('statusLabel'); | |
if (statusLabel) { | |
statusLabel.textContent = text; | |
statusLabel.style.display = 'block'; // Asegurar que sea visible | |
console.log('Estado actualizado:', text); | |
} else { | |
console.error('No se encontr贸 el elemento statusLabel'); | |
} | |
} | |
// Funci贸n para procesar la respuesta del servidor | |
async function processServerResponse(data, userText) { | |
try { | |
console.log('Procesando respuesta del servidor:', data); | |
// Mostrar el mensaje del usuario | |
addMessage(userText, 'user'); | |
if (data.success && data.texto) { | |
// Mostrar la respuesta del bot | |
console.log('Mostrando respuesta del bot:', data.texto); | |
addMessage(data.texto, 'bot'); | |
// Reproducir el audio si existe y no se dijo una palabra de parada | |
if (data.audio && !containsStopWord(userText)) { | |
await playAudio(data.audio); | |
} | |
} else { | |
const errorMessage = data.error || 'Error desconocido'; | |
console.error('Error en la respuesta:', errorMessage); | |
addMessage('Lo siento, hubo un error: ' + errorMessage, 'bot'); | |
} | |
} catch (error) { | |
console.error('Error procesando respuesta:', error); | |
addMessage('Lo siento, ocurri贸 un error inesperado.', 'bot'); | |
} | |
} | |
// Inicializar reconocimiento de voz | |
function initializeSpeechRecognition() { | |
if ('webkitSpeechRecognition' in window) { | |
recognition = new webkitSpeechRecognition(); | |
recognition.continuous = true; // Cambiar a true para permitir interrupciones | |
recognition.interimResults = true; | |
recognition.lang = 'es-ES'; | |
recognition.onstart = function() { | |
console.log('Reconocimiento de voz iniciado'); | |
updateStatus('Escuchando...'); | |
}; | |
recognition.onend = function() { | |
console.log('Reconocimiento de voz terminado'); | |
if (!isProcessingSpeech) { | |
console.log('Reiniciando reconocimiento...'); | |
updateStatus('Escuchando...'); | |
setTimeout(() => recognition.start(), 500); | |
} | |
}; | |
recognition.onerror = function(event) { | |
console.error('Error en reconocimiento de voz:', event.error); | |
if (!isProcessingSpeech && event.error !== 'no-speech') { | |
setTimeout(() => recognition.start(), 1000); | |
} | |
}; | |
recognition.onresult = async function(event) { | |
let finalTranscript = ''; | |
let interimTranscript = ''; | |
for (let i = event.resultIndex; i < event.results.length; ++i) { | |
const transcript = event.results[i][0].transcript; | |
if (event.results[i].isFinal) { | |
finalTranscript = transcript; | |
console.log('Texto final:', finalTranscript); | |
// Verificar si es una palabra de parada | |
if (containsStopWord(finalTranscript)) { | |
console.log('Palabra de parada detectada, deteniendo audio...'); | |
const audio = document.querySelector('audio'); | |
if (audio) { | |
audio.pause(); | |
audio.currentTime = 0; | |
} | |
isPlayingAudio = false; | |
updateStatus('Audio detenido. Escuchando...'); | |
continue; | |
} | |
if (!isProcessingSpeech) { | |
isProcessingSpeech = true; | |
updateStatus('Procesando...'); | |
try { | |
console.log('Enviando texto al servidor:', finalTranscript); | |
const response = await fetch('/procesar_voz', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify({ texto: finalTranscript }) | |
}); | |
const data = await response.json(); | |
console.log('Respuesta recibida:', data); | |
await processServerResponse(data, finalTranscript); | |
} catch (error) { | |
console.error('Error al procesar voz:', error); | |
updateStatus('Error de conexi贸n. Escuchando...'); | |
addMessage('Lo siento, hubo un error de conexi贸n.', 'bot'); | |
} | |
isProcessingSpeech = false; | |
} | |
} else { | |
interimTranscript = transcript; | |
updateStatus(`Escuchando: ${interimTranscript}`); | |
} | |
} | |
}; | |
// Iniciar reconocimiento | |
recognition.start(); | |
updateStatus('Escuchando...'); | |
} else { | |
console.error('El reconocimiento de voz no est谩 soportado en este navegador'); | |
alert('Tu navegador no soporta el reconocimiento de voz. Por favor, usa Chrome.'); | |
updateStatus('Reconocimiento de voz no soportado'); | |
} | |
} | |
// Manejar env铆o de texto | |
sendTextButton.addEventListener('click', async () => { | |
const text = textInput.value.trim(); | |
if (text) { | |
updateStatus('Procesando...'); | |
addMessage(text, 'user'); | |
try { | |
const response = await fetch('/procesar_voz', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify({ texto: text }) | |
}); | |
const data = await response.json(); | |
await processServerResponse(data, text); | |
textInput.value = ''; | |
updateStatus('Esperando activaci贸n...'); | |
} catch (error) { | |
console.error('Error:', error); | |
updateStatus('Error de conexi贸n'); | |
} | |
} | |
}); | |
// Inicializar cuando se carga la p谩gina | |
document.addEventListener('DOMContentLoaded', () => { | |
console.log('P谩gina cargada, verificando elementos...'); | |
// Verificar que existan los elementos necesarios | |
const chatBox = document.getElementById('chatBox'); | |
const statusLabel = document.getElementById('statusLabel'); | |
if (!chatBox) { | |
console.error('Error cr铆tico: No se encontr贸 el elemento chatBox'); | |
return; | |
} | |
if (!statusLabel) { | |
console.error('Error cr铆tico: No se encontr贸 el elemento statusLabel'); | |
return; | |
} | |
// Asegurar que el statusLabel sea visible | |
statusLabel.style.display = 'block'; | |
console.log('Elementos encontrados, inicializando reconocimiento de voz...'); | |
initializeSpeechRecognition(); | |
// Agregar mensaje de bienvenida | |
addMessage('隆Hola! Soy tu asistente virtual. 驴En qu茅 puedo ayudarte?', 'bot'); | |
}); | |