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