Spaces:
Running
Running
| // 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 = '<i class="fas fa-check mr-2"></i>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 = '<i class="fas fa-check mr-2"></i>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 = `<p class="text-red-600 font-semibold">Error al procesar: ${error.message}</p>`; | |
| 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 = '<i class="fas fa-check mr-2"></i>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', ...) |