diff --git a/dist/index.html b/dist/index.html index 94e2b20..1effacd 100644 --- a/dist/index.html +++ b/dist/index.html @@ -257,7 +257,7 @@ async function transcribe(blob) { const tStart = performance.now(); const form = new FormData(); - form.append('file', blob, blob.type === 'audio/wav' ? 'audio.wav' : 'audio.webm'); + form.append('file', blob, 'audio.webm'); form.append('model', 'whisper-large-v3'); form.append('language', 'it'); @@ -274,7 +274,6 @@ async function transcribe(blob) { return data.error ? { text: '', error: data.error } : { text: data.text || '', error: null }; } catch(e) { console.log('[HTTP] ERR', e); - alert('Ошибка транскрипции: ' + (e.message || e)); return { text: '', error: 'network' }; } } @@ -365,15 +364,11 @@ async function startRecording() { const opts = mimeType ? { mimeType } : {}; mediaRecorder = new MediaRecorder(stream, opts); mediaRecorder.ondataavailable = e => { if (e.data.size > 0) audioChunks.push(e.data); }; - mediaRecorder.onstop = async () => { + mediaRecorder.onstop = () => { stopMicMeter(); recordDuration = (Date.now() - recordStartTime) / 1000; - let blob = new Blob(audioChunks, { type: mimeType || 'audio/webm' }); + userAudioBlob = new Blob(audioChunks, { type: mimeType || 'audio/webm' }); stream.getTracks().forEach(t => t.stop()); - // Обрезаем тишину - const trimmed = await trimSilence(blob); - if (trimmed && trimmed.size > 0) blob = trimmed; - userAudioBlob = blob; enable('btnCompare', true); enable('btnStereo', true); enable('btnPlayUser', true); @@ -558,7 +553,7 @@ function pitchFrame(data, start, len, sr) { return bestR > 0.30 ? sr / bestLag : 0; } -// ---------- Обрезка тишины (щелчок в начале, тишина в конце) ---------- +// ---------- Обрезка тишины — возвращает {buffer, startSample, endSample} ---------- async function trimSilence(blob) { try { const ctx = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(1, 1, 44100); @@ -568,7 +563,6 @@ async function trimSilence(blob) { const sr = buf.sampleRate; const len = data.length; - // RMS по окнам 10мс const win = Math.floor(sr * 0.01); const rms = []; let maxRms = 0; @@ -579,17 +573,14 @@ async function trimSilence(blob) { rms.push(v); if (v > maxRms) maxRms = v; } - if (maxRms < 0.001) return blob; // тишина + if (maxRms < 0.001) return null; - const threshold = maxRms * 0.02; // 2% от пика + const threshold = maxRms * 0.02; - // Начало — первый кадр выше порога let startIdx = 0; for (let i = 0; i < rms.length; i++) { if (rms[i] > threshold) { startIdx = Math.max(0, i - 2); break; } } - - // Конец — последний кадр выше порога let endIdx = rms.length - 1; for (let i = rms.length - 1; i >= 0; i--) { if (rms[i] > threshold) { endIdx = Math.min(rms.length - 1, i + 2); break; } @@ -597,33 +588,11 @@ async function trimSilence(blob) { const startSample = startIdx * win; const endSample = Math.min((endIdx + 1) * win, len); - if (endSample - startSample < sr * 0.08) return blob; // слишком коротко + if (endSample - startSample < sr * 0.08) return null; - // WAV: 44-byte header + PCM16 - const trimmed = data.slice(startSample, endSample); - const numSamples = trimmed.length; - const wav = new ArrayBuffer(44 + numSamples * 2); - const view = new DataView(wav); - const writeStr = (off, s) => { for (let i = 0; i < s.length; i++) view.setUint8(off + i, s.charCodeAt(i)); }; - writeStr(0, 'RIFF'); - view.setUint32(4, 36 + numSamples * 2, true); - writeStr(8, 'WAVE'); - writeStr(12, 'fmt '); - view.setUint32(16, 16, true); - view.setUint16(20, 1, true); - view.setUint16(22, 1, true); - view.setUint32(24, sr, true); - view.setUint32(28, sr * 2, true); - view.setUint16(32, 2, true); - view.setUint16(34, 16, true); - writeStr(36, 'data'); - view.setUint32(40, numSamples * 2, true); - for (let i = 0; i < numSamples; i++) { - const s = Math.max(-1, Math.min(1, trimmed[i])); - view.setInt16(44 + i * 2, s < 0 ? s * 0x8000 : s * 0x7FFF, true); - } - return new Blob([wav], { type: 'audio/wav' }); - } catch(e) { return blob; } + const trimmedBuf = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(1, endSample - startSample, sr); + return { buffer: trimmedBuf, data: data.slice(startSample, endSample), sr, startSample, endSample }; + } catch(e) { return null; } } @@ -766,7 +735,7 @@ async function doCompare(blob, originalText, duration) {