native_whisperx/config/
vad.rs1use std::path::PathBuf;
4
5use serde::{Deserialize, Serialize};
6
7use super::defaults::{
8 default_vad_enabled, default_vad_frame_seconds, default_vad_hop_seconds,
9 default_vad_max_chunk_seconds, default_vad_merge_gap_seconds, default_vad_min_speech_seconds,
10 default_vad_padding_seconds, default_vad_rms_threshold,
11};
12use super::ConfigSelection;
13
14#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub struct VadConfig {
17 #[serde(default = "default_vad_enabled")]
18 pub enabled: bool,
19 #[serde(default)]
20 pub method: VadMethod,
21 #[serde(default, skip_serializing_if = "ConfigSelection::is_explicit")]
22 pub selection: ConfigSelection,
23 #[serde(default)]
24 pub onset: Option<f32>,
25 #[serde(default)]
26 pub offset: Option<f32>,
27 #[serde(default)]
28 pub chunk_size: Option<f64>,
29 #[serde(default = "default_vad_rms_threshold")]
30 pub rms_threshold: f32,
31 #[serde(default = "default_vad_frame_seconds")]
32 pub frame_seconds: f64,
33 #[serde(default = "default_vad_hop_seconds")]
34 pub hop_seconds: f64,
35 #[serde(default = "default_vad_min_speech_seconds")]
36 pub min_speech_seconds: f64,
37 #[serde(default = "default_vad_padding_seconds")]
38 pub padding_seconds: f64,
39 #[serde(default = "default_vad_merge_gap_seconds")]
40 pub merge_gap_seconds: f64,
41 #[serde(default = "default_vad_max_chunk_seconds")]
42 pub max_chunk_seconds: f64,
43 #[serde(default)]
44 pub model_bundle: Option<PathBuf>,
45 #[serde(default)]
46 pub model_file: Option<String>,
47 #[serde(default)]
48 pub input_name: Option<String>,
49 #[serde(default)]
50 pub output_name: Option<String>,
51}
52
53impl Default for VadConfig {
54 fn default() -> Self {
55 Self {
56 enabled: true,
57 method: VadMethod::Energy,
58 selection: ConfigSelection::Explicit,
59 onset: None,
60 offset: None,
61 chunk_size: None,
62 rms_threshold: 0.01,
63 frame_seconds: 0.03,
64 hop_seconds: 0.01,
65 min_speech_seconds: 0.08,
66 padding_seconds: 0.02,
67 merge_gap_seconds: 0.05,
68 max_chunk_seconds: 30.0,
69 model_bundle: None,
70 model_file: None,
71 input_name: None,
72 output_name: None,
73 }
74 }
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
78#[serde(rename_all = "lowercase")]
79pub enum VadMethod {
80 #[default]
81 Energy,
82 Pyannote,
83 Silero,
84}
85
86impl VadMethod {
87 pub fn as_whisperx_arg(self) -> &'static str {
88 match self {
89 Self::Energy => "energy",
90 Self::Pyannote => "pyannote",
91 Self::Silero => "silero",
92 }
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use crate::ConfigSelection;
100
101 #[test]
102 fn vad_config_serializes_automatic_selection_separately_from_explicit_method() {
103 let automatic = VadConfig {
104 selection: ConfigSelection::Automatic,
105 method: VadMethod::Pyannote,
106 ..VadConfig::default()
107 };
108
109 let json = serde_json::to_value(&automatic).expect("serialize VAD config");
110
111 assert_eq!(json["selection"], "automatic");
112 assert_eq!(json["method"], "pyannote");
113
114 let explicit = VadConfig {
115 method: VadMethod::Pyannote,
116 ..VadConfig::default()
117 };
118 let json = serde_json::to_value(&explicit).expect("serialize explicit VAD config");
119
120 assert!(json.get("selection").is_none());
121 assert_eq!(json["method"], "pyannote");
122
123 let decoded: VadConfig = serde_json::from_value(serde_json::json!({
124 "method": "silero"
125 }))
126 .expect("deserialize existing VAD config shape");
127 assert_eq!(decoded.selection, ConfigSelection::Explicit);
128 assert_eq!(decoded.method, VadMethod::Silero);
129
130 let decoded: VadConfig = serde_json::from_value(serde_json::json!({
131 "selection": "automatic",
132 "method": "energy"
133 }))
134 .expect("deserialize automatic VAD config");
135 assert_eq!(decoded.selection, ConfigSelection::Automatic);
136 assert_eq!(decoded.method, VadMethod::Energy);
137 }
138}