diff --git a/build.sh b/build.sh index cbd5180..d4c1ce2 100755 --- a/build.sh +++ b/build.sh @@ -9,7 +9,7 @@ css = open(os.path.join(BASE, 'css/style.css')).read() html = html.replace('', f'') -for jsf in ['storage.js', 'syllables.js', 'transcribe.js', 'audio.js', 'compare.js', 'main.js']: +for jsf in ['storage.js', 'syllables.js', 'transcribe.js', 'pronounce.js', 'audio.js', 'compare.js', 'main.js']: js = open(os.path.join(BASE, 'js', jsf)).read() html = html.replace(f'', f'') diff --git a/dist/index.html b/dist/index.html index b44494d..032dc04 100644 --- a/dist/index.html +++ b/dist/index.html @@ -48,6 +48,7 @@ button:disabled { background:#ccc; cursor:not-allowed; }
+ @@ -432,6 +433,107 @@ async function translateToRussian(text) { } catch(e) { /* тихо */ } } + + + diff --git a/js/compare.js b/js/compare.js index f746385..8d2a124 100644 --- a/js/compare.js +++ b/js/compare.js @@ -65,7 +65,7 @@ async function doCompare(blob, originalText, duration) { } clearInterval(timerId); - let recHTML = '', diffHTML = ''; + let recHTML = '', diffHTML = '', pronounceHTML = ''; if (whisperResult.text) { const _transcribed = whisperResult.text; @@ -77,13 +77,21 @@ async function doCompare(blob, originalText, duration) { '📋 Текст: зелёный ≥80%, жёлтый ≥50%, красный <50%' + '' + renderDiff(words); + + // Запускаем pronunciation assessment (параллельно, не блокируем) + assessPronunciation(originalText, whisperResult).then(assess => { + if (assess) { + const el = document.getElementById('pronounce'); + if (el) el.innerHTML = renderPronunciation(assess); + } + }); } else { recHTML = '⚠️ Не распознано'; diffHTML = ''; } document.getElementById('score').innerHTML = recHTML; - + document.getElementById('pronounce').innerHTML = pronounceHTML; document.getElementById('diff').innerHTML = diffHTML; // Слоги — в отдельный div, не в diff (diff перезаписывается) diff --git a/js/main.js b/js/main.js index cfd4817..1db07b1 100644 --- a/js/main.js +++ b/js/main.js @@ -1,6 +1,6 @@ // ---------- Глобальные переменные и инициализация ---------- const GROQ_API_KEY = ''; -const VERSION = 'v106'; +const VERSION = 'v107'; let mediaRecorder, audioChunks = [], userAudioBlob = null, ttsText = ''; let isRecording = false, isAnalyzing = false, micAnalyser = null, micAnimId = null; diff --git a/js/pronounce.js b/js/pronounce.js new file mode 100644 index 0000000..11c9345 --- /dev/null +++ b/js/pronounce.js @@ -0,0 +1,98 @@ +// ---------- Pronunciation Assessment ---------- + +async function assessPronunciation(expectedText, whisperResult) { + try { + const r = await fetch('/pronounce/assess', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + expected: expectedText, + whisper: whisperResult, + lang: 'it' + }) + }); + if (!r.ok) { console.log('[PRONOUNCE] HTTP', r.status); return null; } + const data = await r.json(); + console.log('[PRONOUNCE] score=' + data.overall_score + ' ' + data.quality); + return data; + } catch(e) { + console.log('[PRONOUNCE] ERR', e); + return null; + } +} + +function renderPronunciation(assess) { + if (!assess) return ''; + + const s = assess.overall_score; + const emoji = s >= 90 ? '🟢' : s >= 70 ? '🟡' : s >= 50 ? '🟠' : '🔴'; + + let html = '