v8.0.0: Fix speech recognition repeating text, enable AWS Transcribe Medical
- Add deduplication logic to prevent Chrome Speech API from repeating sentences during long recording sessions (all 4 recording modules) - Enable AWS Transcribe Medical with PRIMARYCARE specialty in .env - Bump version to 8.0.0
This commit is contained in:
parent
3da61c455e
commit
70d2f34770
5 changed files with 49 additions and 8 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "pediatric-ai-scribe",
|
||||
"version": "7.0.0",
|
||||
"version": "8.0.0",
|
||||
"description": "AI-powered pediatric clinical documentation platform",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -542,9 +542,32 @@ function createSpeechRecognition() {
|
|||
rec.continuous = true;
|
||||
rec.interimResults = true;
|
||||
rec.lang = 'en-US';
|
||||
rec.maxAlternatives = 1;
|
||||
return rec;
|
||||
}
|
||||
|
||||
// Deduplicate speech recognition finals — Chrome can repeat text across restarts
|
||||
function deduplicateFinal(newText, existingText) {
|
||||
if (!newText || !existingText) return newText;
|
||||
var trimmed = newText.trim();
|
||||
if (!trimmed) return '';
|
||||
// Check if the new text is already at the end of existing text
|
||||
if (existingText.trimEnd().endsWith(trimmed)) return '';
|
||||
// Check for partial overlap (last sentence repeated)
|
||||
var words = trimmed.split(/\s+/);
|
||||
if (words.length >= 3) {
|
||||
var tail = existingText.trimEnd().split(/\s+/).slice(-words.length).join(' ');
|
||||
if (tail === trimmed) return '';
|
||||
// Check if first half of new text overlaps with end of existing
|
||||
var half = Math.ceil(words.length / 2);
|
||||
var firstHalf = words.slice(0, half).join(' ');
|
||||
if (existingText.trimEnd().endsWith(firstHalf)) {
|
||||
return words.slice(half).join(' ') + ' ';
|
||||
}
|
||||
}
|
||||
return newText;
|
||||
}
|
||||
|
||||
// PWA Service Worker
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/sw.js').catch(function() {});
|
||||
|
|
|
|||
|
|
@ -28,8 +28,13 @@
|
|||
recognition.onresult = function(e) {
|
||||
var interim = '';
|
||||
for (var i = e.resultIndex; i < e.results.length; i++) {
|
||||
if (e.results[i].isFinal) sessionFinals += e.results[i][0].transcript + ' ';
|
||||
else interim = e.results[i][0].transcript;
|
||||
if (e.results[i].isFinal) {
|
||||
var chunk = e.results[i][0].transcript + ' ';
|
||||
var deduped = deduplicateFinal(chunk, finalText + sessionFinals);
|
||||
sessionFinals += deduped;
|
||||
} else {
|
||||
interim = e.results[i][0].transcript;
|
||||
}
|
||||
}
|
||||
var combined = finalText + sessionFinals;
|
||||
transcript.innerHTML = escHtml(combined) + (interim ? '<span style="color:#9ca3af;">' + escHtml(interim) + '</span>' : '');
|
||||
|
|
@ -39,7 +44,10 @@
|
|||
sessionFinals = '';
|
||||
if (isRecording && !isPaused) try { recognition.start(); } catch(e) {}
|
||||
};
|
||||
recognition.onerror = function() {};
|
||||
recognition.onerror = function(e) {
|
||||
if (e.error === 'no-speech' || e.error === 'aborted') return;
|
||||
console.warn('[SpeechRecognition] error:', e.error);
|
||||
};
|
||||
}
|
||||
|
||||
recordBtn.addEventListener('click', function() {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,13 @@
|
|||
recognition.onresult = function(e) {
|
||||
var interim = '';
|
||||
for (var i = e.resultIndex; i < e.results.length; i++) {
|
||||
if (e.results[i].isFinal) sessionFinals += e.results[i][0].transcript + ' ';
|
||||
else interim = e.results[i][0].transcript;
|
||||
if (e.results[i].isFinal) {
|
||||
var chunk = e.results[i][0].transcript + ' ';
|
||||
var deduped = deduplicateFinal(chunk, finalText + sessionFinals);
|
||||
sessionFinals += deduped;
|
||||
} else {
|
||||
interim = e.results[i][0].transcript;
|
||||
}
|
||||
}
|
||||
var combined = finalText + sessionFinals;
|
||||
transcript.innerHTML = escHtml(combined) + (interim ? '<span style="color:#9ca3af;">' + escHtml(interim) + '</span>' : '');
|
||||
|
|
|
|||
|
|
@ -28,8 +28,13 @@
|
|||
recognition.onresult = function(e) {
|
||||
var interim = '';
|
||||
for (var i = e.resultIndex; i < e.results.length; i++) {
|
||||
if (e.results[i].isFinal) sessionFinals += e.results[i][0].transcript + ' ';
|
||||
else interim = e.results[i][0].transcript;
|
||||
if (e.results[i].isFinal) {
|
||||
var chunk = e.results[i][0].transcript + ' ';
|
||||
var deduped = deduplicateFinal(chunk, finalText + sessionFinals);
|
||||
sessionFinals += deduped;
|
||||
} else {
|
||||
interim = e.results[i][0].transcript;
|
||||
}
|
||||
}
|
||||
var combined = finalText + sessionFinals;
|
||||
transcript.innerHTML = escHtml(combined) + (interim ? '<span style="color:#9ca3af;">' + escHtml(interim) + '</span>' : '');
|
||||
|
|
|
|||
Loading…
Reference in a new issue