// js/main.js // --- INICIO: Importaciones --- import { renderIaConfigForm, transcriptionProviders, getIaConfig } from './iaConfigModule.js'; import { initRecorder } from './recordingModule.js'; import { analyzeMedical } from './analysisModule.js'; import { copyText } from './clipboardModule.js'; import { analyzeLabResults, displayLabResults } from './labAnalysisModule.js'; // --- FIN: Importaciones --- console.log("[Main] Script main.js cargado. Esperando DOMContentLoaded..."); window.addEventListener('DOMContentLoaded', () => { console.log("[Main] Evento DOMContentLoaded detectado."); // --- Variables y Estado --- let lastLabResultText = ''; // --- Selección de Elementos DOM (con validación básica) --- console.log("[Main] Seleccionando elementos..."); const btnConfig = document.getElementById('btnConfig'); if (!btnConfig) console.error("!!! #btnConfig NO ENCONTRADO!"); const modal = document.getElementById('configModal'); if (!modal) console.error("!!! #configModal NO ENCONTRADO!"); const transcriptEl = document.getElementById('transcript'); if (!transcriptEl) console.error("!!! #transcript NO ENCONTRADO!"); const outputEnfermedadEl = document.getElementById('output-enfermedad'); if (!outputEnfermedadEl) console.error("!!! #output-enfermedad NO ENCONTRADO!"); const outputExploracionEl = document.getElementById('output-exploracion'); if (!outputExploracionEl) console.error("!!! #output-exploracion NO ENCONTRADO!"); const btnStart = document.getElementById('btnStart'); if (!btnStart) console.error("!!! #btnStart NO ENCONTRADO!"); const btnStop = document.getElementById('btnStop'); if (!btnStop) console.error("!!! #btnStop NO ENCONTRADO!"); const allTabButtons = document.querySelectorAll('.tab-button'); if (allTabButtons.length === 0) console.error("!!! No .tab-button encontrados!"); const allTabContents = document.querySelectorAll('.tab-content'); if (allTabContents.length === 0) console.error("!!! No .tab-content encontrados!"); const labInputText = document.getElementById('lab-input-text'); if (!labInputText) console.error("!!! #lab-input-text NO ENCONTRADO!"); const btnAnalyzeLabs = document.getElementById('btnAnalyzeLabs'); if (!btnAnalyzeLabs) console.error("!!! #btnAnalyzeLabs NO ENCONTRADO!"); const labLoadingIndicator = document.getElementById('lab-loading-indicator'); if (!labLoadingIndicator) console.error("!!! #lab-loading-indicator NO ENCONTRADO!"); const filterAlteredLabsCheckbox = document.getElementById('filterAlteredLabs'); if (!filterAlteredLabsCheckbox) console.error("!!! #filterAlteredLabs NO ENCONTRADO!"); const labResultsOutput = document.getElementById('lab-results-output'); if (!labResultsOutput) console.error("!!! #lab-results-output NO ENCONTRADO!"); const btnCopyTranscript = document.getElementById('btnCopyTranscript'); if (!btnCopyTranscript) console.error("!!! #btnCopyTranscript NO ENCONTRADO!"); const btnCopyAnalysis = document.getElementById('btnCopyAnalysis'); if (!btnCopyAnalysis) console.error("!!! #btnCopyAnalysis NO ENCONTRADO!"); const btnCopyLabResults = document.getElementById('btnCopyLabResults'); if (!btnCopyLabResults) console.error("!!! #btnCopyLabResults NO ENCONTRADO!"); console.log("[Main] Selección elementos finalizada."); // --- Función updateModelLabels (DENTRO de DOMContentLoaded) --- function updateModelLabels() { console.log("[Main] Ejecutando updateModelLabels..."); // (Código interno de la función sin cambios) try{ const cfg=getIaConfig(); const tP=cfg?.transcription?.provider; const tM=cfg?.transcription?.models?.[tP]||'N/A'; const lP=cfg?.llm?.provider; const lM=cfg?.llm?.model||'N/A'; const tL=document.getElementById('trans-model-label'); if(tL)tL.textContent=tM?`(${tM})`:''; const aL=document.getElementById('analysis-model-label'); if(aL)aL.textContent=lM?`(${lM})`:''; const labL=document.getElementById('lab-model-label'); if(labL)labL.textContent=lM?`(${lM})`:''; } catch(e){console.error("Error en updateModelLabels:",e)} } // --- Función para Limpiar Campos de UI --- function clearUIFields() { console.log('[Main] Ejecutando clearUIFields...'); if (transcriptEl) transcriptEl.value = 'Aquí aparecerá la transcripción...'; // Valor inicial o '' if (outputEnfermedadEl) outputEnfermedadEl.textContent = ''; if (outputExploracionEl) outputExploracionEl.textContent = ''; // También limpiamos los campos de la pestaña de Laboratorio por consistencia if (labInputText) labInputText.value = ''; if (labResultsOutput) labResultsOutput.innerHTML = ''; lastLabResultText = ''; // Reiniciar variable de estado console.log('[Main] Campos de UI limpiados.'); } // --- Configuración Inicial y Listeners --- try { updateModelLabels(); // Llamada inicial document.addEventListener('iaConfigChanged', updateModelLabels); renderIaConfigForm('iaConfigContainer'); if(btnConfig) { btnConfig.addEventListener('click', () => { renderIaConfigForm('iaConfigContainer'); if (modal) modal.classList.add('active'); }); } if(modal) { modal.addEventListener('mousedown', e => { if (e.target === modal) modal.classList.remove('active'); }); } } catch(e) { console.error("Error en setup inicial (config/labels):", e); } // --- Listener ANÁLISIS MÉDICO --- try { document.addEventListener('transcriptionReady', async (e) => { console.log("[Main] Evento 'transcriptionReady' recibido."); const transcriptText = e.detail; if (!transcriptText) return; // Mostrar 'Analizando...' solo si los elementos existen if(outputEnfermedadEl) outputEnfermedadEl.textContent='Analizando...'; if(outputExploracionEl) outputExploracionEl.textContent=''; // Limpiar el segundo campo try { const result = await analyzeMedical(transcriptText); console.log("[Main] Análisis médico completado."); const sections = result.split(/\n\s*\n/); // Actualizar elementos solo si existen if(outputEnfermedadEl) outputEnfermedadEl.textContent = sections[0]?.trim() || '(No generado)'; if(outputExploracionEl) outputExploracionEl.textContent = sections.slice(1).join('\n\n').trim() || '(No generado)'; } catch (err) { console.error("Error en analyzeMedical:", err); if(outputEnfermedadEl) outputEnfermedadEl.textContent = `Error análisis: ${err.message}`; if(outputExploracionEl) outputExploracionEl.textContent = ''; // Limpiar si hubo error alert(`Error análisis médico: ${err.message}`); } }); console.log("[Main] Listener 'transcriptionReady' añadido."); } catch(e) { console.error("Error añadiendo listener 'transcriptionReady':", e); } // --- Inicializar Grabadora --- try { // La función getTranscriptionProviderUrl está definida dentro de este try-catch function getTranscriptionProviderUrl() { console.log("[Main] Ejecutando getTranscriptionProviderUrl..."); const cfg = getIaConfig(); const providerValue = cfg?.transcription?.provider; if (providerValue) { const prov = transcriptionProviders.find(p => p.value === providerValue); if (prov?.url) { console.log(`[Main] URL encontrada para ${providerValue}: ${prov.url}`); return prov.url; } else { console.warn(`[Main] URL no encontrada para el proveedor '${providerValue}'.`); } } else { console.warn('[Main] No se encontró providerValue en cfg.transcription.provider.'); } console.error('[Main] Fallo al obtener URL del proveedor. Retornando vacío.'); return ''; } if (btnStart && btnStop && transcriptEl && typeof initRecorder === 'function') { // Pasamos la función clearUIFields como callback initRecorder({ btnStart, btnStop, transcriptEl, getProvider: getTranscriptionProviderUrl, clearFieldsCallback: clearUIFields }); } else { console.error("Faltan elementos/función para initRecorder"); } } catch(e) { console.error("Error inicializando Recorder:", e); } // --- Botones Copiar (Análisis Médico) --- (MODIFICADO CON FEEDBACK) try { // Botón Copiar Transcripción if (btnCopyTranscript && transcriptEl) { btnCopyTranscript.addEventListener('click', async () => { const textToCopy = transcriptEl.value; if (textToCopy && textToCopy !== 'Aquí aparecerá la transcripción...') { try { await copyText(textToCopy); // --- INICIO: Lógica de Feedback Visual --- const buttonElement = btnCopyTranscript; const originalHtml = buttonElement.innerHTML; buttonElement.innerHTML = 'Copiado!'; buttonElement.disabled = true; setTimeout(() => { // Solo restaurar si el botón sigue existiendo y está deshabilitado if (document.body.contains(buttonElement) && buttonElement.disabled) { buttonElement.innerHTML = originalHtml; buttonElement.disabled = false; } }, 2000); // --- FIN: Lógica de Feedback Visual --- } catch (err) { console.error('Error copia transcripción:', err); alert('Error al copiar transcripción.'); // Asegurarse de rehabilitar el botón si falla la copia if (document.body.contains(btnCopyTranscript)) { btnCopyTranscript.disabled = false; } } } else { alert('No hay transcripción válida para copiar.'); } }); } else { console.error("Faltan elementos para botón Copiar Transcripción."); } // Botón Copiar Análisis Médico (Enfermedad + Exploración) if (btnCopyAnalysis && outputEnfermedadEl && outputExploracionEl) { btnCopyAnalysis.addEventListener('click', async () => { const textToCopy = `${outputEnfermedadEl.textContent || ''}\n\n${outputExploracionEl.textContent || ''}`.trim(); // Validar que no esté vacío y no contenga mensajes de error o "no generado" if (textToCopy && !textToCopy.toLowerCase().includes('error') && !textToCopy.toLowerCase().includes('(no generado)')) { try { await copyText(textToCopy); // --- INICIO: Lógica de Feedback Visual --- const buttonElement = btnCopyAnalysis; const originalHtml = buttonElement.innerHTML; buttonElement.innerHTML = 'Copiado!'; buttonElement.disabled = true; setTimeout(() => { // Solo restaurar si el botón sigue existiendo y está deshabilitado if (document.body.contains(buttonElement) && buttonElement.disabled) { buttonElement.innerHTML = originalHtml; buttonElement.disabled = false; } }, 2000); // --- FIN: Lógica de Feedback Visual --- } catch (err) { console.error('Error copia análisis:', err); alert('Error al copiar análisis.'); // Asegurarse de rehabilitar el botón si falla la copia if (document.body.contains(btnCopyAnalysis)) { btnCopyAnalysis.disabled = false; } } } else { alert('No hay análisis válido para copiar.'); } }); } else { console.error("Faltan elementos para botón Copiar Análisis."); } } catch(e) { console.error("Error añadiendo listeners botones Copiar (Médico):", e); } // --- Cambio de Pestañas --- try { function switchTab(clickedTab) { const targetContentId = clickedTab.dataset.contentId; const targetContentElement = document.getElementById(targetContentId); if(targetContentElement && !targetContentElement.classList.contains('active')){ // Desactivar todos los botones y contenidos allTabButtons.forEach(button => { const activeClasses = button.dataset.activeClasses.split(' ').filter(c => c); const inactiveClasses = button.dataset.inactiveClasses.split(' ').filter(c => c); button.classList.remove(...activeClasses); button.classList.add(...inactiveClasses); }); allTabContents.forEach(content => { content.classList.remove('active'); }); // Activar el botón y contenido clickeado const activeClassesToAdd = clickedTab.dataset.activeClasses.split(' ').filter(c => c); const inactiveClassesToRemove = clickedTab.dataset.inactiveClasses.split(' ').filter(c => c); clickedTab.classList.remove(...inactiveClassesToRemove); clickedTab.classList.add(...activeClassesToAdd); targetContentElement.classList.add('active'); console.log(`Pestaña activada: ${targetContentId}`); } } if(allTabButtons.length > 0){ allTabButtons.forEach(button => { button.addEventListener('click', (e) => { switchTab(e.currentTarget); }); }); // Activar la primera pestaña por defecto si ninguna está activa const initiallyActive = document.querySelector('.tab-button.bg-indigo-600'); // Busca la clase activa inicial del HTML if (initiallyActive && !document.querySelector('.tab-content.active')) { switchTab(initiallyActive); } else if (!document.querySelector('.tab-content.active') && allTabButtons.length > 0) { switchTab(allTabButtons[0]); // Activa la primera si no hay ninguna activa por defecto } } else { console.error("No se pueden añadir listeners a los botones de pestaña."); } } catch(e) { console.error("Error en setup Cambio de Pestañas:", e); } // --- ELIMINADO: Bloque del listener 'newRecordingStarted' --- // --- Lógica Pestaña Laboratorio --- try { // Listener Analizar Laboratorio if (btnAnalyzeLabs && labInputText && labLoadingIndicator && filterAlteredLabsCheckbox && labResultsOutput) { btnAnalyzeLabs.addEventListener('click', async () => { console.log("[Main] Click en btnAnalyzeLabs."); const inputText = labInputText.value; if (!inputText.trim()) { alert("Por favor, pega los resultados del laboratorio en el área de texto."); return; } labLoadingIndicator.style.display = 'flex'; btnAnalyzeLabs.disabled = true; filterAlteredLabsCheckbox.disabled = true; labResultsOutput.innerHTML = ''; // Limpiar resultados anteriores lastLabResultText = ''; try { const resultText = await analyzeLabResults(inputText); console.log("RAW AI RESPONSE:", resultText); lastLabResultText = resultText; // Guardar el resultado crudo const filterIsActive = filterAlteredLabsCheckbox.checked; displayLabResults(resultText, labResultsOutput, filterIsActive); // Mostrar resultados // Llamada a updateModelLabels console.log("[Main] Intentando llamar a updateModelLabels desde listener btnAnalyzeLabs..."); updateModelLabels(); console.log("[Main] Llamada a updateModelLabels desde listener btnAnalyzeLabs completada."); } catch (error) { console.error("Error DENTRO listener btnAnalyzeLabs:", error); if(labResultsOutput) labResultsOutput.innerHTML = `
Error al procesar: ${error.message}
`; alert(`Error al analizar resultados: ${error.message}`); } finally { labLoadingIndicator.style.display = 'none'; btnAnalyzeLabs.disabled = false; filterAlteredLabsCheckbox.disabled = false; } }); // Listener Checkbox Filtro filterAlteredLabsCheckbox.addEventListener('change', () => { if (!lastLabResultText || !labResultsOutput) return; const filterIsActive = filterAlteredLabsCheckbox.checked; displayLabResults(lastLabResultText, labResultsOutput, filterIsActive); }); } else { console.error("Faltan elementos esenciales para la Pestaña de Análisis de Exámenes."); } // Listener Copiar Laboratorio (con feedback) if (btnCopyLabResults && labResultsOutput) { btnCopyLabResults.addEventListener('click', async () => { const currentOutputText = labResultsOutput.textContent?.trim(); if(!currentOutputText || currentOutputText.startsWith('Error')) { alert('No hay resultados válidos para copiar.'); return; } try { await copyText(currentOutputText); // --- INICIO: Lógica de Feedback Visual --- const buttonElement = btnCopyLabResults; const originalHtml = buttonElement.innerHTML; buttonElement.innerHTML = 'Copiado!'; buttonElement.disabled = true; setTimeout(() => { // Solo restaurar si el botón sigue existiendo y está deshabilitado if (document.body.contains(buttonElement) && buttonElement.disabled) { buttonElement.innerHTML = originalHtml; buttonElement.disabled = false; } }, 2000); // --- FIN: Lógica de Feedback Visual --- } catch(e){ console.error("Error al copiar resultados de laboratorio:", e); alert("Error al intentar copiar los resultados."); // Asegurarse de rehabilitar el botón si falla la copia if (document.body.contains(btnCopyLabResults)) { btnCopyLabResults.disabled = false; } } }); } else { console.error("Faltan elementos para el botón Copiar Resultados de Laboratorio."); } } catch(e) { console.error("Error general en el setup de la Pestaña de Análisis de Exámenes:", e); } console.log("[Main] Configuración de listeners y UI inicial finalizada."); }); // Fin de window.addEventListener('DOMContentLoaded', ...)