salomonsky's picture
Upload 9 files
2f5df92 verified
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');
});