v63: кликабельные слоги — проигрывание сегментов аудио

This commit is contained in:
“Naeel”
2026-05-22 18:31:56 +04:00
parent 53de41a90e
commit bd042be61c
+48 -1
View File
@@ -53,9 +53,38 @@ let mediaRecorder, audioChunks = [], userAudioBlob = null, ttsText = '';
let isRecording = false, isAnalyzing = false, micAnalyser = null, micAnimId = null; let isRecording = false, isAnalyzing = false, micAnalyser = null, micAnimId = null;
let recordStartTime = 0, recordDuration = 0; let recordStartTime = 0, recordDuration = 0;
// ---------- Версия ---------- // ---------- Версия ----------
const VERSION = 'v62'; const VERSION = 'v63';
document.getElementById('ver').textContent = VERSION; document.getElementById('ver').textContent = VERSION;
// ---------- AudioContext для проигрывания слогов ----------
let _audioCtx = null;
function getAudioCtx() {
if (!_audioCtx) _audioCtx = new (window.AudioContext || window.webkitAudioContext)();
if (_audioCtx.state === 'suspended') _audioCtx.resume();
return _audioCtx;
}
let _currentBlob = null; // blob для проигрывания слогов
let _currentSylBuf = null; // декодированный AudioBuffer
async function playSyllable(sylIdx, total) {
if (!_currentBlob) return;
const ctx = getAudioCtx();
try {
if (!_currentSylBuf) {
const ab = await _currentBlob.arrayBuffer();
_currentSylBuf = await ctx.decodeAudioData(ab);
}
const dur = _currentSylBuf.duration;
const start = (dur / total) * sylIdx;
const len = dur / total;
const src = ctx.createBufferSource();
src.buffer = _currentSylBuf;
src.connect(ctx.destination);
src.start(0, start, len);
} catch(e) { console.log('playSyllable ERR', e); }
}
// ---------- Перевод на русский (Groq) ---------- // ---------- Перевод на русский (Groq) ----------
async function translateToRussian(text) { async function translateToRussian(text) {
if (!GROQ_API_KEY) return; if (!GROQ_API_KEY) return;
@@ -266,6 +295,24 @@ async function doCompare(blob, originalText, duration) {
'<span> Артикуляция: ' + phon.voiceClarity + '%</span>' + '<span> Артикуляция: ' + phon.voiceClarity + '%</span>' +
'</div>'; '</div>';
// Слоги — кликабельные для прослушивания фрагментов
_currentBlob = blob;
_currentSylBuf = null;
const sy = syllabifyIT(originalText);
if (sy && sy.includes('-')) {
const syls = sy.split('-');
const sylHTML = '<div style="margin-top:8px;font-size:1.2em;letter-spacing:2px">' +
syls.map((s, i) =>
'<span class="syl-chip" data-syl="' + i + '" data-total="' + syls.length + '"' +
' style="cursor:pointer;padding:2px 4px;border-radius:4px;transition:0.15s"' +
' onmouseover="this.style.background=\'#e0e0ff\'"' +
' onmouseout="this.style.background=\'\'"' +
' onclick="playSyllable(' + i + ',' + syls.length + ')">' + s + '</span>'
).join('<span style="color:#ccc">·</span>') +
'</div>';
document.getElementById('diff').innerHTML += sylHTML;
}
setStatus('Готово.'); setStatus('Готово.');
isAnalyzing = false; isAnalyzing = false;
return whisperResult.text || ''; return whisperResult.text || '';