2023-06-11 19:17:50 +05:00
|
|
|
|
pub mod structs;
|
|
|
|
|
|
use structs::AudioType;
|
2025-12-11 23:43:50 +05:00
|
|
|
|
use structs::RecorderType;
|
|
|
|
|
|
use structs::SpeechToTextEngine;
|
|
|
|
|
|
use structs::WakeWordEngine;
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
|
use once_cell::sync::Lazy;
|
2023-06-11 19:17:50 +05:00
|
|
|
|
use std::env;
|
2025-12-11 23:43:50 +05:00
|
|
|
|
use std::fs;
|
2023-06-11 19:17:50 +05:00
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
|
use platform_dirs::AppDirs;
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
|
#[cfg(feature="jarvis_app")]
|
|
|
|
|
|
use rustpotter::{
|
|
|
|
|
|
AudioFmt, BandPassConfig, DetectorConfig, FiltersConfig, GainNormalizationConfig,
|
|
|
|
|
|
RustpotterConfig, ScoreMode,
|
|
|
|
|
|
};
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
2026-01-05 01:22:45 +05:00
|
|
|
|
use crate::IntentRecognitionEngine;
|
2026-02-11 07:21:50 +05:00
|
|
|
|
use crate::SlotExtractionEngine;
|
2026-01-06 23:32:58 +05:00
|
|
|
|
use crate::config::structs::NoiseSuppressionBackend;
|
|
|
|
|
|
use crate::config::structs::VadBackend;
|
2026-01-04 05:19:47 +05:00
|
|
|
|
use crate::{APP_CONFIG_DIR, APP_DIRS, APP_LOG_DIR};
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
|
#[allow(dead_code)]
|
2023-06-11 19:17:50 +05:00
|
|
|
|
pub fn init_dirs() -> Result<(), String> {
|
|
|
|
|
|
// infer app dirs
|
|
|
|
|
|
if APP_DIRS.get().is_some() {
|
|
|
|
|
|
return Ok(());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// cache_dir, config_dir, data_dir, state_dir
|
2025-12-11 23:43:50 +05:00
|
|
|
|
APP_DIRS
|
2026-01-04 05:19:47 +05:00
|
|
|
|
.set(AppDirs::new(Some(BUNDLE_IDENTIFIER), false).unwrap())
|
2025-12-11 23:43:50 +05:00
|
|
|
|
.unwrap();
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
|
|
|
|
|
// setup directories
|
|
|
|
|
|
let mut config_dir = PathBuf::from(&APP_DIRS.get().unwrap().config_dir);
|
|
|
|
|
|
let mut log_dir = PathBuf::from(&APP_DIRS.get().unwrap().config_dir);
|
|
|
|
|
|
|
|
|
|
|
|
// create dirs, if required
|
|
|
|
|
|
if !config_dir.exists() {
|
|
|
|
|
|
if fs::create_dir_all(&config_dir).is_err() {
|
|
|
|
|
|
config_dir = env::current_dir().expect("Cannot infer the config directory");
|
2025-12-11 23:43:50 +05:00
|
|
|
|
fs::create_dir_all(&config_dir)
|
|
|
|
|
|
.expect("Cannot create config directory, access denied?");
|
2023-06-11 19:17:50 +05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if !log_dir.exists() {
|
|
|
|
|
|
if fs::create_dir_all(&log_dir).is_err() {
|
|
|
|
|
|
log_dir = env::current_dir().expect("Cannot infer the log directory");
|
|
|
|
|
|
fs::create_dir_all(&log_dir).expect("Cannot create log directory, access denied?");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// store inferred paths
|
|
|
|
|
|
APP_CONFIG_DIR.set(config_dir).unwrap();
|
|
|
|
|
|
APP_LOG_DIR.set(log_dir).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2025-12-11 23:43:50 +05:00
|
|
|
|
Defaults.
|
|
|
|
|
|
*/
|
2023-06-11 19:17:50 +05:00
|
|
|
|
pub const DEFAULT_AUDIO_TYPE: AudioType = AudioType::Kira;
|
|
|
|
|
|
pub const DEFAULT_RECORDER_TYPE: RecorderType = RecorderType::PvRecorder;
|
2026-01-05 03:38:04 +05:00
|
|
|
|
pub const DEFAULT_WAKE_WORD_ENGINE: WakeWordEngine = WakeWordEngine::Vosk;
|
2026-01-05 01:22:45 +05:00
|
|
|
|
pub const DEFAULT_INTENT_RECOGNITION_ENGINE: IntentRecognitionEngine = IntentRecognitionEngine::IntentClassifier;
|
2023-06-11 19:17:50 +05:00
|
|
|
|
pub const DEFAULT_SPEECH_TO_TEXT_ENGINE: SpeechToTextEngine = SpeechToTextEngine::Vosk;
|
|
|
|
|
|
|
2026-01-07 23:29:46 +05:00
|
|
|
|
pub const DEFAULT_VOICE: &str = "jarvis-remaster";
|
|
|
|
|
|
pub const SOUND_PATH: &str = "resources/sound"; // extended from SOUND_DIR (resources/sound)
|
|
|
|
|
|
pub const VOICES_PATH: &str = "voices"; // extended from SOUND_PATH (resources/sound)
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
|
|
|
|
|
pub const BUNDLE_IDENTIFIER: &str = "com.priler.jarvis";
|
|
|
|
|
|
pub const DB_FILE_NAME: &str = "app.db";
|
|
|
|
|
|
pub const LOG_FILE_NAME: &str = "log.txt";
|
|
|
|
|
|
pub const APP_VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");
|
|
|
|
|
|
pub const AUTHOR_NAME: Option<&str> = option_env!("CARGO_PKG_AUTHORS");
|
|
|
|
|
|
pub const REPOSITORY_LINK: Option<&str> = option_env!("CARGO_PKG_REPOSITORY");
|
|
|
|
|
|
pub const TG_OFFICIAL_LINK: Option<&str> = Some("https://t.me/howdyho_official");
|
|
|
|
|
|
pub const FEEDBACK_LINK: Option<&str> = Some("https://t.me/jarvis_feedback_bot");
|
2026-01-07 05:04:04 +05:00
|
|
|
|
pub const SUPPORT_BOOSTY_LINK: Option<&str> = Some("https://boosty.to/howdyho");
|
2026-01-07 23:29:46 +05:00
|
|
|
|
pub const SUPPORT_PATREON_LINK: Option<&str> = Some("https://www.patreon.com/c/priler");
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
|
|
|
|
|
/*
|
2025-12-11 23:43:50 +05:00
|
|
|
|
Tray.
|
|
|
|
|
|
*/
|
2023-06-11 19:17:50 +05:00
|
|
|
|
pub const TRAY_ICON: &str = "32x32.png";
|
|
|
|
|
|
pub const TRAY_TOOLTIP: &str = "Jarvis Voice Assistant";
|
|
|
|
|
|
|
|
|
|
|
|
// RUSPOTTER
|
|
|
|
|
|
pub const RUSPOTTER_MIN_SCORE: f32 = 0.62;
|
2026-01-04 05:19:47 +05:00
|
|
|
|
|
2025-12-11 23:43:50 +05:00
|
|
|
|
#[cfg(feature="jarvis_app")]
|
2023-06-11 19:17:50 +05:00
|
|
|
|
pub const RUSTPOTTER_DEFAULT_CONFIG: Lazy<RustpotterConfig> = Lazy::new(|| {
|
|
|
|
|
|
RustpotterConfig {
|
2025-12-11 23:43:50 +05:00
|
|
|
|
fmt: AudioFmt::default(),
|
2023-06-11 19:17:50 +05:00
|
|
|
|
detector: DetectorConfig {
|
|
|
|
|
|
avg_threshold: 0.,
|
|
|
|
|
|
threshold: 0.5,
|
|
|
|
|
|
min_scores: 15,
|
2025-12-11 23:43:50 +05:00
|
|
|
|
score_ref: 0.22,
|
|
|
|
|
|
band_size: 5,
|
|
|
|
|
|
vad_mode: None,
|
|
|
|
|
|
score_mode: ScoreMode::Max,
|
|
|
|
|
|
eager: false,
|
|
|
|
|
|
// comparator_band_size: 5,
|
|
|
|
|
|
// comparator_ref: 0.22
|
2023-06-11 19:17:50 +05:00
|
|
|
|
},
|
|
|
|
|
|
filters: FiltersConfig {
|
|
|
|
|
|
gain_normalizer: GainNormalizationConfig {
|
2026-01-06 23:32:58 +05:00
|
|
|
|
// enabled: true,
|
|
|
|
|
|
// gain_ref: None,
|
|
|
|
|
|
// min_gain: 0.7,
|
|
|
|
|
|
// max_gain: 1.0,
|
|
|
|
|
|
enabled: false, // disable, now we have separate gain normalizer implementation
|
2023-06-11 19:17:50 +05:00
|
|
|
|
gain_ref: None,
|
|
|
|
|
|
min_gain: 0.7,
|
|
|
|
|
|
max_gain: 1.0,
|
|
|
|
|
|
},
|
|
|
|
|
|
band_pass: BandPassConfig {
|
|
|
|
|
|
enabled: true,
|
|
|
|
|
|
low_cutoff: 80.,
|
|
|
|
|
|
high_cutoff: 400.,
|
2025-12-11 23:43:50 +05:00
|
|
|
|
},
|
|
|
|
|
|
},
|
2023-06-11 19:17:50 +05:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// PICOVOICE
|
2026-01-05 03:38:04 +05:00
|
|
|
|
pub const COMMANDS_PATH: &str = "resources/commands/";
|
|
|
|
|
|
pub const KEYWORDS_PATH: &str = "resources/picovoice/keywords/";
|
2023-06-11 19:17:50 +05:00
|
|
|
|
pub const DEFAULT_KEYWORD: &str = "jarvis_windows.ppn";
|
|
|
|
|
|
pub const DEFAULT_SENSITIVITY: f32 = 1.0;
|
|
|
|
|
|
|
|
|
|
|
|
// VOSK
|
|
|
|
|
|
// pub const VOSK_MODEL_PATH: &str = const_concat!(PUBLIC_PATH, "/vosk/model_small");
|
2026-01-05 03:38:04 +05:00
|
|
|
|
pub const VOSK_MODELS_PATH: &str = "resources/vosk";
|
|
|
|
|
|
pub const VOSK_MODEL_PATH: &str = "resources/vosk/model_small";
|
2023-06-11 19:17:50 +05:00
|
|
|
|
pub const VOSK_FETCH_PHRASE: &str = "джарвис";
|
|
|
|
|
|
pub const VOSK_MIN_RATIO: f64 = 70.0;
|
|
|
|
|
|
|
2026-01-05 04:20:43 +05:00
|
|
|
|
// 0.7 lenient, expect false positives
|
|
|
|
|
|
// 0.8 balanced
|
|
|
|
|
|
// 0.9 strict
|
|
|
|
|
|
// etc
|
|
|
|
|
|
pub const VOSK_WAKE_CONFIDENCE: f32 = 0.9;
|
|
|
|
|
|
|
|
|
|
|
|
pub const VOSK_SPEECH_RECOGNIZER_MAX_ALTERNATIVES: u16 = 3;
|
|
|
|
|
|
pub const VOSK_SPEECH_RECOGNIZER_WORDS: bool = false;
|
|
|
|
|
|
pub const VOSK_SPEECH_PARTIAL_WORDS: bool = false;
|
|
|
|
|
|
|
2026-01-05 01:22:45 +05:00
|
|
|
|
// IRE (intents recognition)
|
2026-01-05 03:38:04 +05:00
|
|
|
|
pub const INTENT_CLASSIFIER_MIN_CONFIDENCE: f64 = 0.75;
|
2026-01-05 01:22:45 +05:00
|
|
|
|
|
2026-02-11 07:21:50 +05:00
|
|
|
|
// SLOTS EXTRACTION
|
|
|
|
|
|
pub const DEFAULT_SLOT_EXTRACTION_ENGINE: SlotExtractionEngine = SlotExtractionEngine::None;
|
|
|
|
|
|
|
2026-02-08 07:16:03 +05:00
|
|
|
|
// embedding classifier
|
2026-02-08 07:30:46 +05:00
|
|
|
|
pub const EMBEDDING_MIN_CONFIDENCE: f64 = 0.70;
|
2026-01-06 23:32:58 +05:00
|
|
|
|
|
|
|
|
|
|
// AUDIO PROCESSING DEFAULTS
|
|
|
|
|
|
pub const DEFAULT_NOISE_SUPPRESSION: NoiseSuppressionBackend = NoiseSuppressionBackend::None;
|
|
|
|
|
|
pub const DEFAULT_VAD: VadBackend = VadBackend::Energy;
|
|
|
|
|
|
pub const DEFAULT_GAIN_NORMALIZER: bool = false;
|
|
|
|
|
|
|
|
|
|
|
|
// VAD settings
|
2026-01-08 00:35:21 +05:00
|
|
|
|
pub const VAD_ENERGY_THRESHOLD: f32 = 100.0; // RMS threshold for energy-based VAD
|
|
|
|
|
|
pub const VAD_NNNOISELESS_THRESHOLD: f32 = 0.8; // probability threshold for nnnoiseless
|
2026-01-06 23:32:58 +05:00
|
|
|
|
pub const VAD_SILENCE_FRAMES: u32 = 15; // frames of silence before speech end (~480ms)
|
|
|
|
|
|
|
|
|
|
|
|
// gain normalizer settings
|
|
|
|
|
|
pub const GAIN_TARGET_RMS: f32 = 3000.0; // target RMS level
|
|
|
|
|
|
pub const GAIN_MIN: f32 = 0.5; // minimum gain multiplier
|
|
|
|
|
|
pub const GAIN_MAX: f32 = 3.0; // maximum gain multiplier
|
|
|
|
|
|
|
|
|
|
|
|
// nnnoiseless frame size (fixed by library)
|
|
|
|
|
|
pub const NNNOISELESS_FRAME_SIZE: usize = 480;
|
|
|
|
|
|
|
2026-01-17 05:46:38 +05:00
|
|
|
|
// LUA
|
|
|
|
|
|
pub const DEFAULT_LUA_SANDBOX: &str = "standard";
|
|
|
|
|
|
pub const DEFAULT_LUA_TIMEOUT: u64 = 10000; // ms
|
2026-01-06 23:32:58 +05:00
|
|
|
|
|
2023-06-11 19:17:50 +05:00
|
|
|
|
// ETC
|
2026-02-08 07:16:03 +05:00
|
|
|
|
pub const CMD_RATIO_THRESHOLD: f64 = 75f64;
|
2023-06-11 19:17:50 +05:00
|
|
|
|
pub const CMS_WAIT_DELAY: std::time::Duration = std::time::Duration::from_secs(15);
|
|
|
|
|
|
|
2026-01-13 02:21:59 +05:00
|
|
|
|
// pub const ASSISTANT_GREET_PHRASES: [&str; 3] = ["greet1", "greet2", "greet3"];
|
|
|
|
|
|
// pub const ASSISTANT_PHRASES_TBR: [&str; 17] = [
|
|
|
|
|
|
// "джарвис",
|
|
|
|
|
|
// "сэр",
|
|
|
|
|
|
// "слушаю сэр",
|
|
|
|
|
|
// "всегда к услугам",
|
|
|
|
|
|
// "произнеси",
|
|
|
|
|
|
// "ответь",
|
|
|
|
|
|
// "покажи",
|
|
|
|
|
|
// "скажи",
|
|
|
|
|
|
// "давай",
|
|
|
|
|
|
// "да сэр",
|
|
|
|
|
|
// "к вашим услугам сэр",
|
|
|
|
|
|
// "всегда к вашим услугам сэр",
|
|
|
|
|
|
// "запрос выполнен сэр",
|
|
|
|
|
|
// "выполнен сэр",
|
|
|
|
|
|
// "есть",
|
|
|
|
|
|
// "загружаю сэр",
|
|
|
|
|
|
// "очень тонкое замечание сэр",
|
|
|
|
|
|
// ];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-02-08 06:37:39 +05:00
|
|
|
|
pub fn get_wake_phrases(lang: &str) -> &'static [&'static str] {
|
2026-01-13 02:21:59 +05:00
|
|
|
|
match lang {
|
2026-02-08 06:37:39 +05:00
|
|
|
|
"ru" => &["джарвис", "джервис", "гарвис", "джарви", "гарви"],
|
|
|
|
|
|
"ua" => &["джарвіс", "джервіс"],
|
|
|
|
|
|
"en" => &["jarvis", "jervis"],
|
|
|
|
|
|
_ => &["jarvis"],
|
2026-01-13 02:21:59 +05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn get_phrases_to_remove(lang: &str) -> &'static [&'static str] {
|
|
|
|
|
|
match lang {
|
|
|
|
|
|
"ru" => &[
|
2026-02-08 06:37:39 +05:00
|
|
|
|
"джарвис", "джервис", "гарвис", "джарви", "гарви",
|
|
|
|
|
|
"сэр", "слушаю сэр", "всегда к услугам",
|
2026-01-13 02:21:59 +05:00
|
|
|
|
"произнеси", "ответь", "покажи", "скажи", "давай",
|
|
|
|
|
|
"да сэр", "к вашим услугам сэр", "загружаю сэр",
|
|
|
|
|
|
],
|
|
|
|
|
|
"ua" => &[
|
2026-02-08 06:37:39 +05:00
|
|
|
|
"джарвіс", "джервіс", "сер", "слухаю сер", "завжди до послуг",
|
2026-01-13 02:21:59 +05:00
|
|
|
|
"скажи", "покажи", "відповідай", "давай",
|
|
|
|
|
|
"так сер", "до ваших послуг сер",
|
|
|
|
|
|
],
|
|
|
|
|
|
"en" => &[
|
2026-02-08 06:37:39 +05:00
|
|
|
|
"jarvis", "jervis", "sir", "yes sir", "at your service",
|
2026-01-13 02:21:59 +05:00
|
|
|
|
"please", "say", "show", "tell", "hey",
|
|
|
|
|
|
],
|
|
|
|
|
|
_ => &["jarvis"],
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn get_wake_grammar(lang: &str) -> &'static [&'static str] {
|
|
|
|
|
|
match lang {
|
|
|
|
|
|
"ru" => &[
|
|
|
|
|
|
"джарвис", "[unk]", "джон", "джони", "джей",
|
|
|
|
|
|
"джонстон", "привет", "давай",
|
|
|
|
|
|
],
|
|
|
|
|
|
"ua" => &[
|
|
|
|
|
|
"джарвіс", "[unk]", "джон", "джоні", "джей",
|
|
|
|
|
|
"привіт", "давай",
|
|
|
|
|
|
],
|
|
|
|
|
|
"en" => &[
|
|
|
|
|
|
"jarvis", "[unk]", "john", "johnny", "jay",
|
|
|
|
|
|
"hello", "hey", "hi",
|
|
|
|
|
|
],
|
|
|
|
|
|
_ => &["jarvis", "[unk]"],
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|