2026-01-05 01:22:45 +05:00
|
|
|
use parking_lot::RwLock;
|
|
|
|
|
use std::sync::Arc;
|
2023-06-11 19:17:50 +05:00
|
|
|
|
2026-01-04 05:19:47 +05:00
|
|
|
// include core
|
|
|
|
|
use jarvis_core::{
|
2026-01-05 01:22:45 +05:00
|
|
|
audio, commands, config, db, listener, recorder, stt, intent,
|
2026-01-04 05:19:47 +05:00
|
|
|
APP_CONFIG_DIR, APP_LOG_DIR, COMMANDS_LIST, DB,
|
|
|
|
|
};
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
|
|
|
// include log
|
|
|
|
|
#[macro_use]
|
|
|
|
|
extern crate simple_log;
|
|
|
|
|
mod log;
|
|
|
|
|
|
|
|
|
|
// include app
|
|
|
|
|
mod app;
|
|
|
|
|
|
|
|
|
|
// include tray
|
|
|
|
|
// @TODO. macOS currently not supported for tray functionality.
|
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
|
|
|
mod tray;
|
|
|
|
|
|
|
|
|
|
fn main() -> Result<(), String> {
|
|
|
|
|
// initialize directories
|
|
|
|
|
config::init_dirs()?;
|
|
|
|
|
|
|
|
|
|
// initialize logging
|
|
|
|
|
log::init_logging()?;
|
|
|
|
|
|
|
|
|
|
// log some base info
|
|
|
|
|
info!("Starting Jarvis v{} ...", config::APP_VERSION.unwrap());
|
2026-01-04 05:19:47 +05:00
|
|
|
info!("Config directory is: {}", APP_CONFIG_DIR.get().unwrap().display());
|
2023-06-11 19:17:50 +05:00
|
|
|
info!("Log directory is: {}", APP_LOG_DIR.get().unwrap().display());
|
|
|
|
|
|
|
|
|
|
// initialize database (settings)
|
2026-01-05 01:22:45 +05:00
|
|
|
DB.set(Arc::new(RwLock::new(db::init_settings())))
|
|
|
|
|
.expect("DB already initialized");
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
|
|
|
// initialize tray
|
|
|
|
|
// @TODO. macOS currently not supported for tray functionality,
|
|
|
|
|
// due to the separate thread in which tray processing works,
|
|
|
|
|
// but macOS requires it to be processed in the main thread only
|
|
|
|
|
// The solution may be to include wake-word detection etc. in the winit event loop. (only for MacOS, though?)
|
2026-01-04 05:19:47 +05:00
|
|
|
//#[cfg(not(target_os = "macos"))]
|
|
|
|
|
//tray::init();
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
|
|
|
// init recorder
|
|
|
|
|
if recorder::init().is_err() {
|
2026-01-04 05:19:47 +05:00
|
|
|
app::close(1);
|
2023-06-11 19:17:50 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// init stt engine
|
|
|
|
|
if stt::init().is_err() {
|
|
|
|
|
// @TODO. Allow continuing even without STT, if commands is using keywords or smthng?
|
|
|
|
|
app::close(1); // cannot continue without stt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// init tts engine
|
|
|
|
|
// none for now (Silero-rs coming)
|
|
|
|
|
|
|
|
|
|
// init commands
|
|
|
|
|
info!("Initializing commands.");
|
2026-01-05 01:22:45 +05:00
|
|
|
let cmds = match commands::parse_commands() {
|
|
|
|
|
Ok(c) => c,
|
|
|
|
|
Err(e) => {
|
|
|
|
|
warn!("Failed to parse commands: {}. Starting with empty command list.", e);
|
|
|
|
|
Vec::new()
|
|
|
|
|
}
|
|
|
|
|
};
|
2026-01-04 05:19:47 +05:00
|
|
|
info!("Commands initialized. Count: {}, List: {:?}", cmds.len(), commands::list(&cmds));
|
|
|
|
|
COMMANDS_LIST.set(cmds).unwrap();
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
|
|
|
// init audio
|
|
|
|
|
if audio::init().is_err() {
|
|
|
|
|
// @TODO. Allow continuing even without audio?
|
|
|
|
|
app::close(1); // cannot continue without audio
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// init wake-word engine
|
|
|
|
|
if listener::init().is_err() {
|
2026-01-04 05:19:47 +05:00
|
|
|
app::close(1); // cannot continue without wake-word engine
|
2023-06-11 19:17:50 +05:00
|
|
|
}
|
|
|
|
|
|
2026-01-05 01:22:45 +05:00
|
|
|
// init intent-recognition engine
|
|
|
|
|
let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime");
|
|
|
|
|
rt.block_on(async {
|
|
|
|
|
if intent::init(COMMANDS_LIST.get().unwrap()).await.is_err() {
|
|
|
|
|
error!("Failed to initialize intent classifier");
|
|
|
|
|
app::close(1);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2026-01-04 05:19:47 +05:00
|
|
|
// start the app (in the background thread)
|
|
|
|
|
std::thread::spawn(|| {
|
2026-01-04 06:14:05 +05:00
|
|
|
let _ = app::start();
|
2026-01-04 05:19:47 +05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
tray::init_blocking();
|
2023-06-11 19:17:50 +05:00
|
|
|
|
|
|
|
|
Ok(())
|
2026-01-04 05:19:47 +05:00
|
|
|
}
|