This commit is contained in:
valenti
2026-10-17 22:01:31 +01:00
parent bfed42c3b3
commit 79f927d968
53 changed files with 2158 additions and 78 deletions
+19 -1
View File
@@ -44,6 +44,20 @@ pub struct VadSettings {
pub speech_pad_ms: u32,
/// Speech required to fire the barge-in onset (`VAD_BARGE_IN_MIN_SPEECH_MS`).
pub barge_in_min_speech_ms: u32,
/// Drop an utterance shorter than this before transcription
/// (`VAD_MIN_UTTERANCE_MS`, default 300). `0` disables the check. Filters
/// the short VAD false-triggers (breaths, clicks, echo).
pub min_utterance_ms: u32,
/// Drop an utterance whose average speech probability is below this before
/// transcription (`VAD_MIN_AVG_PROB`, default 0.25). `0.0` disables the
/// check. Filters the soft/noisy segments that the STT would otherwise
/// turn into hallucinated text. The average is taken over the **voiced
/// windows only** (probability ≥ `neg_threshold`), so the trailing
/// hangover silence (`min_silence_ms`) does not dilute short utterances
/// like "uno" / "due". A genuine utterance still fluctuates around the
/// speech threshold on its onset/release, so keep this well below
/// `threshold` (default 0.5).
pub min_avg_prob: f32,
/// Feed the STT engine with VAD-segmented utterances instead of letting it
/// run its own RMS segmentation (`VAD_SEGMENT_STT`).
pub segment_stt: bool,
@@ -62,9 +76,11 @@ impl Default for VadSettings {
threshold: 0.5,
neg_threshold: 0.35,
min_speech_ms: 250,
min_silence_ms: 300,
min_silence_ms: 700,
speech_pad_ms: 30,
barge_in_min_speech_ms: 150,
min_utterance_ms: 300,
min_avg_prob: 0.25,
segment_stt: true,
barge_in: true,
debug: false,
@@ -91,6 +107,8 @@ impl VadSettings {
s.min_silence_ms = env_u32("VAD_MIN_SILENCE_MS", s.min_silence_ms);
s.speech_pad_ms = env_u32("VAD_SPEECH_PAD_MS", s.speech_pad_ms);
s.barge_in_min_speech_ms = env_u32("VAD_BARGE_IN_MIN_SPEECH_MS", s.barge_in_min_speech_ms);
s.min_utterance_ms = env_u32("VAD_MIN_UTTERANCE_MS", s.min_utterance_ms);
s.min_avg_prob = env_f32("VAD_MIN_AVG_PROB", s.min_avg_prob);
// Hysteresis must stay below the speech threshold, and the fast
// barge-in onset can never be slower than the utterance onset.
+11 -3
View File
@@ -219,8 +219,10 @@ pub struct VadDetector {
speech_run_ms: u32,
/// Consecutive silence milliseconds while in speech.
silence_run_ms: u32,
/// Running probability average over the current utterance.
/// Running sum of speech probabilities over the voiced windows of the
/// current utterance.
prob_sum: f32,
/// Number of voiced windows contributing to `prob_sum`.
speech_windows: u64,
/// Windows analysed since the detector was created (for logging).
window_count: u64,
@@ -365,8 +367,14 @@ impl VadDetector {
}
self.utterance.extend_from_slice(window);
self.prob_sum += prob;
self.speech_windows += 1;
// Average only over the voiced windows. The trailing hangover (the
// `min_silence_ms` of silence that closes the segment) must not dilute
// the score: for a short word like "uno" it is most of the segment and
// would drag the mean below any sane gate.
if prob >= self.settings.neg_threshold {
self.prob_sum += prob;
self.speech_windows += 1;
}
if prob < self.settings.neg_threshold {
self.silence_run_ms = self.silence_run_ms.saturating_add(WINDOW_MS);