@luckydraw/cumulus 0.30.24 → 0.30.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gateway/static/widget.js +41 -16
- package/package.json +1 -1
|
@@ -4374,6 +4374,7 @@
|
|
|
4374
4374
|
audioQueue: [], // queue of Float32Array PCM chunks
|
|
4375
4375
|
audioPlaying: false, // currently playing audio
|
|
4376
4376
|
audioDone: false, // server signaled all audio sent
|
|
4377
|
+
micRestartTimer: null, // pending mic restart, cancellable when PCM resumes
|
|
4377
4378
|
// Voice loading state for Safari compatibility
|
|
4378
4379
|
voicesLoaded: false,
|
|
4379
4380
|
speakQueue: [],
|
|
@@ -4501,9 +4502,7 @@
|
|
|
4501
4502
|
} else {
|
|
4502
4503
|
// No speech detected — restart listening
|
|
4503
4504
|
setPhase('idle');
|
|
4504
|
-
|
|
4505
|
-
if (state.active) startRecognition();
|
|
4506
|
-
}, 300);
|
|
4505
|
+
scheduleMicRestart(300);
|
|
4507
4506
|
}
|
|
4508
4507
|
};
|
|
4509
4508
|
|
|
@@ -4513,15 +4512,11 @@
|
|
|
4513
4512
|
// Normal — just restart
|
|
4514
4513
|
if (state.active) {
|
|
4515
4514
|
setPhase('idle');
|
|
4516
|
-
|
|
4517
|
-
if (state.active) startRecognition();
|
|
4518
|
-
}, 500);
|
|
4515
|
+
scheduleMicRestart(500);
|
|
4519
4516
|
}
|
|
4520
4517
|
} else {
|
|
4521
4518
|
label.textContent = 'Mic error: ' + event.error;
|
|
4522
|
-
|
|
4523
|
-
if (state.active) startRecognition();
|
|
4524
|
-
}, 1000);
|
|
4519
|
+
scheduleMicRestart(1000);
|
|
4525
4520
|
}
|
|
4526
4521
|
};
|
|
4527
4522
|
|
|
@@ -4700,12 +4695,18 @@
|
|
|
4700
4695
|
state.speaking = false;
|
|
4701
4696
|
if (state.active) {
|
|
4702
4697
|
setPhase('idle');
|
|
4703
|
-
|
|
4704
|
-
if (state.active) startRecognition();
|
|
4705
|
-
}, 300);
|
|
4698
|
+
scheduleMicRestart(300);
|
|
4706
4699
|
}
|
|
4707
4700
|
}
|
|
4708
4701
|
|
|
4702
|
+
function scheduleMicRestart(delay) {
|
|
4703
|
+
if (state.micRestartTimer) clearTimeout(state.micRestartTimer);
|
|
4704
|
+
state.micRestartTimer = setTimeout(function () {
|
|
4705
|
+
state.micRestartTimer = null;
|
|
4706
|
+
if (state.active && state.phase !== 'speaking') startRecognition();
|
|
4707
|
+
}, delay);
|
|
4708
|
+
}
|
|
4709
|
+
|
|
4709
4710
|
// ── Server-side TTS (Web Audio API playback) ──
|
|
4710
4711
|
function ensureAudioCtx() {
|
|
4711
4712
|
if (!state.audioCtx) {
|
|
@@ -4721,7 +4722,29 @@
|
|
|
4721
4722
|
}
|
|
4722
4723
|
|
|
4723
4724
|
function queuePCMAudio(arrayBuffer) {
|
|
4724
|
-
if (!state.active
|
|
4725
|
+
if (!state.active) return;
|
|
4726
|
+
|
|
4727
|
+
// Server is sending audio — it always wins over the mic. If the widget
|
|
4728
|
+
// transitioned to listening (or back to idle) prematurely, recover by
|
|
4729
|
+
// killing recognition and resuming the speaking phase. Without this,
|
|
4730
|
+
// any subsequent PCM is silently dropped and the mic gets stuck in an
|
|
4731
|
+
// idle/listen flicker loop.
|
|
4732
|
+
if (state.phase !== 'speaking') {
|
|
4733
|
+
console.log('[Voice] PCM arrived in phase=' + state.phase + ', recovering to speaking');
|
|
4734
|
+
if (state.recognition) {
|
|
4735
|
+
try { state.recognition.abort(); } catch (e) {}
|
|
4736
|
+
}
|
|
4737
|
+
clearWatchdog();
|
|
4738
|
+
// Cancel any pending mic-restart timer so it can't override us
|
|
4739
|
+
if (state.micRestartTimer) {
|
|
4740
|
+
clearTimeout(state.micRestartTimer);
|
|
4741
|
+
state.micRestartTimer = null;
|
|
4742
|
+
}
|
|
4743
|
+
// Reset audioDone — server is still sending, so a previously-seen
|
|
4744
|
+
// voice_audio_done signal must have been spurious (or stale from a
|
|
4745
|
+
// prior turn). Wait for the next legitimate one.
|
|
4746
|
+
state.audioDone = false;
|
|
4747
|
+
}
|
|
4725
4748
|
|
|
4726
4749
|
// Strip 4-byte "VPCM" header
|
|
4727
4750
|
var pcmData = new Int16Array(arrayBuffer, 4);
|
|
@@ -4785,9 +4808,7 @@
|
|
|
4785
4808
|
state.audioDone = false;
|
|
4786
4809
|
if (state.active) {
|
|
4787
4810
|
setPhase('idle');
|
|
4788
|
-
|
|
4789
|
-
if (state.active) startRecognition();
|
|
4790
|
-
}, 300);
|
|
4811
|
+
scheduleMicRestart(300);
|
|
4791
4812
|
}
|
|
4792
4813
|
}
|
|
4793
4814
|
|
|
@@ -4849,6 +4870,10 @@
|
|
|
4849
4870
|
clearTimeout(state.voiceLoadTimer);
|
|
4850
4871
|
state.voiceLoadTimer = null;
|
|
4851
4872
|
}
|
|
4873
|
+
if (state.micRestartTimer) {
|
|
4874
|
+
clearTimeout(state.micRestartTimer);
|
|
4875
|
+
state.micRestartTimer = null;
|
|
4876
|
+
}
|
|
4852
4877
|
state.speakQueue.length = 0;
|
|
4853
4878
|
state.voicesLoaded = false;
|
|
4854
4879
|
state.waitingForServerTTS = false;
|