Tune web voice VAD for short utterances

This commit is contained in:
Mohamed Boudra
2026-02-06 15:58:02 +07:00
parent 34ba33402a
commit 7d388b456f
2 changed files with 41 additions and 4 deletions

View File

@@ -8,6 +8,10 @@ import { activateKeepAwakeAsync, deactivateKeepAwake } from "expo-keep-awake";
const VOICE_CONVERSATION_ID_STORAGE_KEY = "@paseo:voice-conversation-id";
const KEEP_AWAKE_TAG = "paseo:voice";
const VOICE_VAD_VOLUME_THRESHOLD = 0.18;
const VOICE_VAD_SILENCE_DURATION_MS = 1400;
const VOICE_VAD_SPEECH_CONFIRMATION_MS = 120;
const VOICE_VAD_DETECTION_GRACE_PERIOD_MS = 700;
interface VoiceContextValue {
isVoiceMode: boolean;
@@ -123,10 +127,10 @@ export function VoiceProvider({ children }: VoiceProviderProps) {
console.error("[Voice] Cannot handle error - setMessages not available from SessionState");
}
},
volumeThreshold: 0.3,
silenceDuration: 2000,
speechConfirmationDuration: 300,
detectionGracePeriod: 200,
volumeThreshold: VOICE_VAD_VOLUME_THRESHOLD,
silenceDuration: VOICE_VAD_SILENCE_DURATION_MS,
speechConfirmationDuration: VOICE_VAD_SPEECH_CONFIRMATION_MS,
detectionGracePeriod: VOICE_VAD_DETECTION_GRACE_PERIOD_MS,
});
useEffect(() => {

View File

@@ -88,4 +88,37 @@ describe("SpeechSegmenter", () => {
expect(lastCall.isLast).toBe(true);
expect(lastCall.audioData.length).toBeGreaterThan(0);
});
it("keeps detection alive across a brief pause and confirms short utterances", () => {
const onSpeechStart = vi.fn();
const detectingChanges: boolean[] = [];
const segmenter = new SpeechSegmenter(
{
enableContinuousStreaming: false,
volumeThreshold: 0.18,
silenceDurationMs: 1400,
speechConfirmationMs: 120,
detectionGracePeriodMs: 700,
minChunkDurationMs: 100,
pcmSampleRate: 1000,
},
{
onSpeechStart,
onDetectingChange: (v) => detectingChanges.push(v),
}
);
const t0 = 20_000;
segmenter.pushVolumeLevel(0.4, t0);
segmenter.pushPcmChunk(mkPcmBytes(20));
segmenter.pushVolumeLevel(0.0, t0 + 80);
segmenter.pushPcmChunk(mkPcmBytes(20));
segmenter.pushVolumeLevel(0.4, t0 + 140);
segmenter.pushPcmChunk(mkPcmBytes(20));
expect(detectingChanges).toContain(true);
expect(onSpeechStart).toHaveBeenCalledTimes(1);
});
});