max words

This commit is contained in:
2026-03-01 16:35:48 +01:00
parent 37e098ecdf
commit 146b4be549

View File

@@ -323,7 +323,7 @@
font-size: 14px; font-size: 14px;
} }
.transcript-box.interim { color: var(--text-dim); } .transcript-box[contenteditable="true"] { outline: none; cursor: text; border-color: var(--accent); }
/* ── Actions ── */ /* ── Actions ── */
.actions { .actions {
@@ -830,6 +830,7 @@ function loadQuestion() {
function resetPracticeUI() { function resetPracticeUI() {
state.transcript = ''; state.transcript = '';
transcriptBox.contentEditable = 'false';
updateTranscriptBox('', false); updateTranscriptBox('', false);
feedbackBox.classList.remove('visible'); feedbackBox.classList.remove('visible');
feedbackContent.innerHTML = ''; feedbackContent.innerHTML = '';
@@ -866,8 +867,8 @@ speakBtn.addEventListener('click', () => {
// ── Speech recognition ──────────────────────────────────────────────────────── // ── Speech recognition ────────────────────────────────────────────────────────
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const MAX_RECORD_SECONDS = 10; const MAX_RECORD_SECONDS = 20;
const MAX_RECORD_WORDS = 30; const MAX_RECORD_WORDS = 60;
function initRecognition() { function initRecognition() {
if (!SpeechRecognition) return null; if (!SpeechRecognition) return null;
@@ -875,7 +876,7 @@ function initRecognition() {
const r = new SpeechRecognition(); const r = new SpeechRecognition();
r.lang = 'de-DE'; r.lang = 'de-DE';
r.continuous = true; r.continuous = true;
r.interimResults = true; r.interimResults = false;
r.maxAlternatives = 1; r.maxAlternatives = 1;
let finalText = ''; let finalText = '';
@@ -888,32 +889,22 @@ function initRecognition() {
}; };
r.onresult = (e) => { r.onresult = (e) => {
let interim = '';
for (let i = e.resultIndex; i < e.results.length; i++) { for (let i = e.resultIndex; i < e.results.length; i++) {
const t = e.results[i][0].transcript;
if (e.results[i].isFinal) { if (e.results[i].isFinal) {
finalText += (finalText ? ' ' : '') + t; finalText += (finalText ? ' ' : '') + e.results[i][0].transcript;
} else {
interim = t;
} }
} }
if (finalText.trim().split(/\s+/).length >= MAX_RECORD_WORDS) { if (finalText.trim().split(/\s+/).length >= MAX_RECORD_WORDS) {
stopRecording(); stopRecording();
return; return;
} }
const display = finalText + (interim ? ' ' + interim : ''); updateTranscriptBox(finalText, false);
updateTranscriptBox(display, !!interim);
state.transcript = finalText; state.transcript = finalText;
checkBtn.disabled = !finalText.trim(); checkBtn.disabled = !finalText.trim();
}; };
r.onend = () => { r.onend = () => {
if (state.isRecording) { if (state.isRecording) stopRecording();
// create a fresh instance to avoid duplicate results on restart
const fresh = initRecognition();
recognition = fresh;
try { fresh.start(); } catch (_) {}
}
}; };
r.onerror = (e) => { r.onerror = (e) => {
@@ -933,6 +924,7 @@ function startRecording() {
return; return;
} }
stopAudio(); stopAudio();
transcriptBox.contentEditable = 'false';
recognition = initRecognition(); recognition = initRecognition();
state.isRecording = true; state.isRecording = true;
try { recognition.start(); } catch (_) {} try { recognition.start(); } catch (_) {}
@@ -950,6 +942,10 @@ function stopRecording() {
} }
recordBtn.classList.remove('recording'); recordBtn.classList.remove('recording');
recordHint.textContent = 'Tippen zum Aufnehmen'; recordHint.textContent = 'Tippen zum Aufnehmen';
if (state.transcript) {
transcriptBox.contentEditable = 'true';
transcriptBox.focus();
}
} }
recordBtn.addEventListener('click', () => { recordBtn.addEventListener('click', () => {
@@ -972,10 +968,16 @@ function updateTranscriptBox(text, isInterim) {
} }
} }
transcriptBox.addEventListener('input', () => {
state.transcript = transcriptBox.textContent.trim();
checkBtn.disabled = !state.transcript;
});
// ── Clear ───────────────────────────────────────────────────────────────────── // ── Clear ─────────────────────────────────────────────────────────────────────
clearBtn.addEventListener('click', () => { clearBtn.addEventListener('click', () => {
stopRecording(); stopRecording();
state.transcript = ''; state.transcript = '';
transcriptBox.contentEditable = 'false';
updateTranscriptBox('', false); updateTranscriptBox('', false);
checkBtn.disabled = true; checkBtn.disabled = true;
feedbackBox.classList.remove('visible'); feedbackBox.classList.remove('visible');