active_call/offline/
config.rs1use anyhow::Result;
2use std::path::PathBuf;
3
4#[derive(Clone, Debug)]
5pub struct OfflineConfig {
6 pub models_dir: PathBuf,
7 pub threads: usize,
8}
9
10impl Default for OfflineConfig {
11 fn default() -> Self {
12 Self {
13 models_dir: Self::default_models_dir(),
14 threads: num_cpus::get().min(4),
15 }
16 }
17}
18
19impl OfflineConfig {
20 pub fn new(models_dir: PathBuf, threads: usize) -> Self {
21 Self {
22 models_dir,
23 threads,
24 }
25 }
26
27 pub fn default_models_dir() -> PathBuf {
28 std::env::var("OFFLINE_MODELS_DIR")
29 .ok()
30 .map(PathBuf::from)
31 .unwrap_or_else(|| PathBuf::from("./models"))
32 }
33
34 pub fn sensevoice_dir(&self) -> PathBuf {
35 self.models_dir.join("sensevoice")
36 }
37
38 pub fn sensevoice_model_path(&self) -> PathBuf {
39 self.sensevoice_dir().join("model.int8.onnx")
40 }
41
42 pub fn sensevoice_tokens_path(&self) -> PathBuf {
43 self.sensevoice_dir().join("tokens.txt")
44 }
45
46 pub fn supertonic_dir(&self) -> PathBuf {
47 self.models_dir.join("supertonic")
48 }
49
50 pub fn supertonic_onnx_dir(&self) -> PathBuf {
51 self.supertonic_dir().join("onnx")
52 }
53
54 pub fn supertonic_config_path(&self) -> PathBuf {
55 self.supertonic_onnx_dir().join("tts.json")
56 }
57
58 pub fn supertonic_voice_styles_dir(&self) -> PathBuf {
59 self.supertonic_dir().join("voice_styles")
60 }
61
62 pub fn validate(&self) -> Result<()> {
63 if !self.models_dir.exists() {
64 anyhow::bail!(
65 "Models directory does not exist: {}. Please run with --download-models flag.",
66 self.models_dir.display()
67 );
68 }
69 Ok(())
70 }
71
72 pub fn sensevoice_available(&self) -> bool {
73 self.sensevoice_model_path().exists() && self.sensevoice_tokens_path().exists()
74 }
75
76 pub fn supertonic_available(&self) -> bool {
77 let onnx_dir = self.supertonic_onnx_dir();
78 onnx_dir.join("duration_predictor.onnx").exists()
79 && onnx_dir.join("text_encoder.onnx").exists()
80 && onnx_dir.join("vector_estimator.onnx").exists()
81 && onnx_dir.join("vocoder.onnx").exists()
82 && self.supertonic_config_path().exists()
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_default_config() {
92 let config = OfflineConfig::default();
93 assert!(config.threads > 0);
94 assert!(config.threads <= 4);
95 }
96
97 #[test]
98 fn test_paths() {
99 let config = OfflineConfig::new(PathBuf::from("/test/models"), 2);
100 assert_eq!(
101 config.sensevoice_model_path(),
102 PathBuf::from("/test/models/sensevoice/model.int8.onnx")
103 );
104 assert_eq!(
105 config.supertonic_onnx_dir(),
106 PathBuf::from("/test/models/supertonic/onnx")
107 );
108 }
109}