Spaces:
Running
Running
File size: 10,415 Bytes
f1602bc d82b630 541ec2c 12b3a3c f1602bc 541ec2c f1602bc d82b630 541ec2c d82b630 12b3a3c 6d399bf f1602bc 12b3a3c f1602bc 6d399bf d82b630 f1602bc 6d399bf f1602bc 12b3a3c d82b630 6d399bf d82b630 6d399bf d82b630 f1602bc 541ec2c f1602bc d82b630 6d399bf 12b3a3c 6d399bf f1602bc 6d399bf 12b3a3c 6d399bf 541ec2c 6d399bf 12b3a3c 6d399bf 12b3a3c 6d399bf 12b3a3c 6d399bf f54bdc2 6d399bf 12b3a3c 6d399bf 12b3a3c f54bdc2 12b3a3c 6d399bf 12b3a3c d82b630 12b3a3c 541ec2c 12b3a3c 541ec2c d82b630 6d399bf 12b3a3c 6d399bf 541ec2c 6d399bf 12b3a3c 6d399bf |
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 |
// 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 = '<i class="fas fa-circle text-red-500 animate-pulse mr-2"></i>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 = '<i class="fas fa-spinner fa-spin mr-2"></i>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 = '<i class="fas fa-circle text-gray-400 mr-2"></i>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 = '<i class="fas fa-exclamation-circle text-red-500 mr-2"></i>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 = `<i class="fas fa-exclamation-circle text-red-500 mr-2"></i>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 = `<i class="fas fa-exclamation-circle text-red-500 mr-2"></i>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 = `<i class="fas fa-times-circle text-red-500 mr-2"></i>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 = '<i class="fas fa-check-circle text-green-500 mr-2"></i>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 = '<i class="fas fa-circle text-gray-400 mr-2"></i>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 = '<i class="fas fa-circle text-gray-400 mr-2"></i>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 = '<i class="fas fa-circle text-gray-400 mr-2"></i>No hay consulta en progreso';
}
}
}
// --- FIN: Funci贸n onStop ---
} // Fin export function initRecorder |