// js/recordingModule.js // Modificamos la firma para aceptar el nuevo callback export function initRecorder({ btnStart, btnStop, transcriptEl, getProvider, clearFieldsCallback }) { let mediaRecorder, audioChunks = [], transcriptText = ''; // Listener para el botón Iniciar (MODIFICADO para usar el callback) btnStart.addEventListener('click', async () => { console.log('[Recorder] Botón Iniciar pulsado'); // --- INICIO: Limpieza usando Callback --- if (typeof clearFieldsCallback === 'function') { console.log('[Recorder] Llamando a clearFieldsCallback...'); try { clearFieldsCallback(); // <-- LLAMADA AL CALLBACK } catch (error) { console.error('[Recorder] Error al ejecutar clearFieldsCallback:', error); } } else { console.warn('[Recorder] clearFieldsCallback no fue proporcionado o no es una función.'); // Opcionalmente, limpiar al menos la transcripción aquí como fallback if (transcriptEl) transcriptEl.value = ''; // Fallback si no hay callback } // --- FIN: Limpieza usando Callback --- // Ya no se necesitan las líneas de evento y log desactivado // console.log('[Recorder] Evento newRecordingStarted DESACTIVADO TEMPORALMENTE'); // Eliminado const aiProviderUrl = getProvider(); if (!aiProviderUrl) { alert('Proveedor de Transcripción no configurado o URL inválida. Revisa la Configuración IA.'); return; } try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); console.log('[Recorder] Acceso a micrófono concedido'); mediaRecorder = new MediaRecorder(stream); mediaRecorder.onstop = onStop; console.log('[Recorder] MediaRecorder creado:', mediaRecorder); audioChunks = []; mediaRecorder.ondataavailable = e => audioChunks.push(e.data); mediaRecorder.start(); btnStart.disabled = true; btnStop.disabled = false; const status = document.getElementById('recorder-status'); if (status) { status.innerHTML = 'Consulta en progreso...'; } } catch (err) { console.error('[Recorder] Error al acceder al micrófono:', err); alert(`No se pudo acceder al micrófono: ${err.message}`); btnStart.disabled = false; btnStop.disabled = true; } }); // Listener para el botón Detener (CON estado intermedio) btnStop.addEventListener('click', () => { console.log('[Recorder] Botón Detener pulsado'); if (mediaRecorder && mediaRecorder.state === 'recording') { mediaRecorder.stop(); btnStop.disabled = true; const status = document.getElementById('recorder-status'); if (status) { status.innerHTML = 'Procesando audio...'; } } else { console.warn('[Recorder] MediaRecorder no estaba grabando al intentar detener.'); btnStart.disabled = false; btnStop.disabled = true; } }); // --- INICIO: Función onStop (Sin cambios en su lógica interna) --- async function onStop() { console.log('[Recorder] Grabación detenida (onStop), procesando audio...'); if (audioChunks.length === 0) { console.warn('[Recorder] No hay audio chunks para procesar.'); alert('No se grabó audio.'); const status = document.getElementById('recorder-status'); if (status) status.innerHTML = 'No hay consulta en progreso'; btnStart.disabled = false; btnStop.disabled = true; return; } const cfg = JSON.parse(localStorage.getItem('iaConfig')); if (!cfg || !cfg.transcription || !cfg.transcription.provider || !cfg.transcription.apiKeys || !cfg.transcription.models) { alert('Configuración de Transcripción incompleta.'); const status = document.getElementById('recorder-status'); if(status) status.innerHTML = 'Error Configuración.'; btnStart.disabled = false; btnStop.disabled = true; return; } const transProvider = cfg.transcription.provider; const apiKey = cfg.transcription.apiKeys[transProvider]; const transModel = cfg.transcription.models[transProvider]; const providerBaseUrl = getProvider(); // Llama a la función pasada desde main.js if (!apiKey) { alert(`API Key para ${transProvider} no encontrada.`); const status = document.getElementById('recorder-status'); if(status) status.innerHTML = `Falta API Key (${transProvider}).`; btnStart.disabled = false; btnStop.disabled = true; return; } if (!providerBaseUrl) { alert(`URL base para ${transProvider} no encontrada.`); const status = document.getElementById('recorder-status'); if(status) status.innerHTML = `Error URL Proveedor.`; btnStart.disabled = false; btnStop.disabled = true; return; } let blobType = audioChunks[0]?.type || 'audio/webm'; console.log(`[Recorder] Usando tipo MIME para Blob: ${blobType}`); const blob = new Blob(audioChunks, { type: blobType }); console.log('[Recorder] Blob de audio creado:', blob); audioChunks = []; let transcript = ''; try { if (transProvider === 'deepgram') { console.log(`[Recorder] Iniciando transcripción con Deepgram (Modelo: ${transModel})`); const deepgramUrl = `${providerBaseUrl}/v1/listen?language=es&model=${transModel}&smart_format=true`; console.log('[Recorder] Deepgram URL:', deepgramUrl); const res = await fetch(deepgramUrl, { method: 'POST', headers: { 'Authorization': 'Token ' + apiKey, 'Content-Type': blob.type }, body: blob }); if (!res.ok) { const errorText = await res.text().catch(() => `Status ${res.status}`); throw new Error(`Error Deepgram (${res.status}): ${errorText}`); } const data = await res.json(); console.log('[Deepgram] Respuesta completa:', data); transcript = data.results?.channels?.[0]?.alternatives?.[0]?.transcript || ''; console.log('[Deepgram] Transcript extraído:', transcript); } else if (transProvider === 'openai') { console.log(`[Recorder] Iniciando transcripción con OpenAI (Modelo: ${transModel})`); const fd = new FormData(); fd.append('model', transModel); // --- INICIO: CÓDIGO MODIFICADO PARA FILENAME --- // Obtener la parte después de '/' (ej: 'webm;codecs=opus' o 'mp4') o usar 'webm' como fallback const mimeSubType = (blobType.split('/')[1] || 'webm'); // Quitar cualquier cosa después de un punto y coma (ej: ';codecs=opus') const extension = mimeSubType.split(';')[0]; // Construir el nombre de archivo solo con la extensión limpia const filename = `consulta.${extension}`; // --- FIN: CÓDIGO MODIFICADO PARA FILENAME --- fd.append('file', blob, filename); // Ahora filename será algo como 'consulta.webm' console.log(`[Recorder] Enviando a OpenAI: model=${transModel}, filename=${filename}, size=${blob.size}`); // Log mostrará el filename corregido const respOA = await fetch(`${providerBaseUrl}/v1/audio/transcriptions`, { method: 'POST', headers: { 'Authorization': 'Bearer ' + apiKey }, body: fd }); if (!respOA.ok) { const errTxt = await respOA.text(); throw new Error(`Error OpenAI transcripción (${respOA.status}): ${errTxt}`); } const dataOA = await respOA.json(); console.log('[OpenAI Whisper] Respuesta completa:', dataOA); transcript = dataOA.text || ''; console.log('[OpenAI Whisper] Transcript extraído:', transcript); } else { throw new Error(`Proveedor de transcripción no soportado: ${transProvider}`); } // Actualizar UI y disparar evento (ESTA LÍNEA SIGUE ACTIVA) if (transcriptEl) transcriptEl.value = transcript; // Asegurarse que transcriptEl existe document.dispatchEvent(new CustomEvent('transcriptionReady', { detail: transcript })); console.log("[Recorder] Evento 'transcriptionReady' DESPACHADO con detalle:", { detail: transcript }); } catch (e) { console.error('[Recorder] Error durante la llamada API de transcripción:', e); alert('Error en la transcripción: ' + e.message); const status = document.getElementById('recorder-status'); if (status) status.innerHTML = `Error en transcripción.`; } finally { console.log('[Recorder] Finalizando onStop (finally).'); btnStart.disabled = false; btnStop.disabled = true; const statusElement = document.getElementById('recorder-status'); if (statusElement && !statusElement.innerHTML.includes('Error')) { statusElement.innerHTML = 'Transcripción lista.'; // Actualizar estado después de un tiempo si sigue en "lista" setTimeout(() => { const currentStatusElement = document.getElementById('recorder-status'); if(currentStatusElement && currentStatusElement.innerHTML.includes('lista')) { currentStatusElement.innerHTML = 'No hay consulta en progreso'; } }, 4000); } else if (statusElement && statusElement.innerHTML.includes('Error')) { // Si hubo error, dejar el mensaje de error por un tiempo y luego resetear setTimeout(() => { const currentStatusElement = document.getElementById('recorder-status'); if(currentStatusElement && currentStatusElement.innerHTML.includes('Error')) { currentStatusElement.innerHTML = 'No hay consulta en progreso'; } }, 5000); // Un poco más de tiempo para leer el error } else if (statusElement) { // Si no hubo error pero tampoco está 'lista' (caso raro, ej. no audio chunks), resetear statusElement.innerHTML = 'No hay consulta en progreso'; } } } // --- FIN: Función onStop --- } // Fin export function initRecorder