Spaces:
Running
Running
File size: 19,141 Bytes
f1602bc 315da52 32aac78 236e39c f1602bc c428e52 32aac78 f1602bc ebd65f3 131c11c f1602bc 32aac78 315da52 32aac78 c428e52 32aac78 63226fc 32aac78 236e39c 32aac78 236e39c 63226fc 5eb71d1 32aac78 236e39c ebd65f3 236e39c b240e2e 32aac78 131c11c 32aac78 131c11c 236e39c 5eb71d1 32aac78 5eb71d1 236e39c 32aac78 ebd65f3 63226fc 32aac78 5eb71d1 b15f84b 5eb71d1 63226fc 5eb71d1 63226fc 5eb71d1 32aac78 131c11c 63226fc 131c11c 63226fc 32aac78 5eb71d1 63226fc 5eb71d1 63226fc 5eb71d1 131c11c 5eb71d1 131c11c 32aac78 131c11c 5eb71d1 131c11c b15f84b 32aac78 5eb71d1 32aac78 5eb71d1 32aac78 63226fc 5eb71d1 63226fc 32aac78 5eb71d1 32aac78 5eb71d1 32aac78 63226fc 5eb71d1 63226fc 5eb71d1 63226fc 5eb71d1 236e39c 5eb71d1 236e39c 63226fc 5eb71d1 63226fc 5eb71d1 63226fc 5eb71d1 63226fc 5eb71d1 131c11c 5eb71d1 315da52 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 |
// 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', ...) |