Commands/voices multilanguage support + Ukranian vosk model added
This commit is contained in:
parent
64eb1093d5
commit
c9b9482cc8
67 changed files with 214473 additions and 293 deletions
|
|
@ -1,7 +1,8 @@
|
|||
use std::sync::mpsc::Receiver;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use jarvis_core::{audio_buffer::AudioRingBuffer, audio_processing, commands, config, listener, recorder, stt, COMMANDS_LIST, intent, voices, ipc::{self, IpcEvent}};
|
||||
use jarvis_core::{audio_buffer::AudioRingBuffer, audio_processing, commands, config, listener, recorder, stt, COMMANDS_LIST, intent, voices, ipc::{self, IpcEvent}, i18n};
|
||||
use rand::seq::SliceRandom;
|
||||
|
||||
use crate::should_stop;
|
||||
|
||||
|
|
@ -183,7 +184,8 @@ fn recognize_command(
|
|||
recognized_voice = recognized_voice.to_lowercase();
|
||||
|
||||
// check if wake word repeated (reactivate)
|
||||
if recognized_voice.contains(config::VOSK_FETCH_PHRASE) {
|
||||
let wake_phrase = config::get_wake_phrase(&i18n::get_language());
|
||||
if recognized_voice.contains(wake_phrase) {
|
||||
info!("Wake word detected during chaining, reactivating...");
|
||||
voices::play_reply();
|
||||
stt::reset_speech_recognizer();
|
||||
|
|
@ -198,9 +200,13 @@ fn recognize_command(
|
|||
}
|
||||
|
||||
// filter activation phrases
|
||||
for tbr in config::ASSISTANT_PHRASES_TBR {
|
||||
// for tbr in config::ASSISTANT_PHRASES_TBR {
|
||||
// recognized_voice = recognized_voice.replace(tbr, "");
|
||||
// }
|
||||
for tbr in config::get_phrases_to_remove(&i18n::get_language()) {
|
||||
recognized_voice = recognized_voice.replace(tbr, "");
|
||||
}
|
||||
|
||||
recognized_voice = recognized_voice.trim().to_string();
|
||||
|
||||
if recognized_voice.is_empty() {
|
||||
|
|
@ -257,9 +263,13 @@ fn process_text_command(text: &str, rt: &tokio::runtime::Runtime) {
|
|||
ipc::send(IpcEvent::SpeechRecognized { text: text.to_string() });
|
||||
|
||||
let mut filtered = text.to_lowercase();
|
||||
for tbr in config::ASSISTANT_PHRASES_TBR {
|
||||
// for tbr in config::ASSISTANT_PHRASES_TBR {
|
||||
// filtered = filtered.replace(tbr, "");
|
||||
// }
|
||||
for tbr in config::get_phrases_to_remove(&i18n::get_language()) {
|
||||
filtered = filtered.replace(tbr, "");
|
||||
}
|
||||
|
||||
let filtered = filtered.trim();
|
||||
|
||||
if filtered.is_empty() {
|
||||
|
|
@ -299,7 +309,8 @@ fn execute_command(text: &str, rt: &tokio::runtime::Runtime) -> bool {
|
|||
match commands::execute_command(&cmd_path, &cmd_config) {
|
||||
Ok(chain) => {
|
||||
info!("Command executed successfully");
|
||||
voices::play_ok();
|
||||
// voices::play_ok();
|
||||
voices::play_random_from(cmd_config.get_sounds(&i18n::get_language()).as_slice());
|
||||
ipc::send(IpcEvent::CommandExecuted {
|
||||
id: cmd_config.id.clone(),
|
||||
success: true,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ fn main() -> Result<(), String> {
|
|||
Vec::new()
|
||||
}
|
||||
};
|
||||
info!("Commands initialized. Count: {}, List: {:?}", cmds.len(), commands::list(&cmds));
|
||||
info!("Commands initialized. Count: {}, List: {:?}", cmds.len(), commands::list_paths(&cmds));
|
||||
COMMANDS_LIST.set(cmds).unwrap();
|
||||
|
||||
// init audio
|
||||
|
|
|
|||
|
|
@ -1,40 +1,24 @@
|
|||
use crate::APP_DIR;
|
||||
use rand::prelude::*;
|
||||
use seqdiff::ratio;
|
||||
// use serde_yaml;
|
||||
use std::path::Path;
|
||||
use std::{fs, fs::File};
|
||||
|
||||
use core::time::Duration;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::fs;
|
||||
use std::time::Duration;
|
||||
use std::process::{Child, Command};
|
||||
// use tauri::Manager;
|
||||
|
||||
use seqdiff::ratio;
|
||||
|
||||
mod structs;
|
||||
pub use structs::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use crate::{config, i18n, APP_DIR};
|
||||
|
||||
use crate::{config};
|
||||
|
||||
// @TODO. Allow commands both in yaml and json format.
|
||||
pub fn parse_commands() -> Result<Vec<JCommandsList>, String> {
|
||||
// collect commands
|
||||
let mut commands: Vec<JCommandsList> = Vec::new();
|
||||
|
||||
let commands_path = APP_DIR.join(config::COMMANDS_PATH);
|
||||
let cmd_dirs = fs::read_dir(&commands_path)
|
||||
.map_err(|e| format!("Error reading commands directory {:?}: {}", commands_path, e))?;
|
||||
|
||||
for entry in cmd_dirs {
|
||||
let entry = match entry {
|
||||
Ok(e) => e,
|
||||
Err(e) => {
|
||||
warn!("Failed to read command directory entry: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
for entry in cmd_dirs.flatten() {
|
||||
let cmd_path = entry.path();
|
||||
let toml_file = cmd_path.join("command.toml");
|
||||
|
||||
|
|
@ -42,7 +26,6 @@ pub fn parse_commands() -> Result<Vec<JCommandsList>, String> {
|
|||
continue;
|
||||
}
|
||||
|
||||
// read and parse TOML
|
||||
let content = match fs::read_to_string(&toml_file) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
|
|
@ -68,27 +51,30 @@ pub fn parse_commands() -> Result<Vec<JCommandsList>, String> {
|
|||
if commands.is_empty() {
|
||||
Err("No commands found".into())
|
||||
} else {
|
||||
info!("Loaded {} commands", commands.len());
|
||||
info!("Loaded {} command pack(s)", commands.len());
|
||||
Ok(commands)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Commands hash generation for cache invalidation (deterministi c)
|
||||
pub fn commands_hash(commands: &Vec<JCommandsList>) -> String {
|
||||
pub fn commands_hash(commands: &[JCommandsList]) -> String {
|
||||
use sha2::{Sha256, Digest};
|
||||
|
||||
let mut hasher = Sha256::new();
|
||||
|
||||
// collect all command ids and phrases, sorted
|
||||
let mut all_ids: Vec<_> = commands.iter()
|
||||
.flat_map(|ac| ac.commands.iter().map(|c| (&c.id, &c.phrases)))
|
||||
let lang = i18n::get_language();
|
||||
hasher.update(lang.as_bytes());
|
||||
hasher.update(b"|");
|
||||
|
||||
// collect all command ids and phrases for current language, sorted
|
||||
let mut all_data: Vec<(&str, _)> = commands.iter()
|
||||
.flat_map(|ac| ac.commands.iter().map(|c| (c.id.as_str(), c.get_phrases(&lang))))
|
||||
.collect();
|
||||
all_ids.sort_by_key(|(id, _)| *id);
|
||||
all_data.sort_by_key(|(id, _)| *id);
|
||||
|
||||
for (id, phrases) in all_ids {
|
||||
for (id, phrases) in all_data {
|
||||
hasher.update(id.as_bytes());
|
||||
for phrase in phrases {
|
||||
for phrase in phrases.iter() {
|
||||
hasher.update(phrase.as_bytes());
|
||||
}
|
||||
}
|
||||
|
|
@ -99,12 +85,10 @@ pub fn commands_hash(commands: &Vec<JCommandsList>) -> String {
|
|||
|
||||
pub fn fetch_command<'a>(
|
||||
phrase: &str,
|
||||
commands: &'a Vec<JCommandsList>,
|
||||
commands: &'a [JCommandsList],
|
||||
) -> Option<(&'a PathBuf, &'a JCommand)> {
|
||||
let mut result: Option<(&PathBuf, &JCommand)> = None;
|
||||
let mut best_score = config::CMD_RATIO_THRESHOLD;
|
||||
let lang = i18n::get_language();
|
||||
|
||||
// normalize input
|
||||
let phrase = phrase.trim().to_lowercase();
|
||||
if phrase.is_empty() {
|
||||
return None;
|
||||
|
|
@ -113,25 +97,30 @@ pub fn fetch_command<'a>(
|
|||
let phrase_chars: Vec<char> = phrase.chars().collect();
|
||||
let phrase_words: Vec<&str> = phrase.split_whitespace().collect();
|
||||
|
||||
let mut result: Option<(&PathBuf, &JCommand)> = None;
|
||||
let mut best_score = config::CMD_RATIO_THRESHOLD;
|
||||
|
||||
for cmd_list in commands {
|
||||
for cmd in &cmd_list.commands {
|
||||
for cmd_phrase in &cmd.phrases {
|
||||
let cmd_phrase = cmd_phrase.trim().to_lowercase();
|
||||
let cmd_phrase_chars: Vec<char> = cmd_phrase.chars().collect();
|
||||
let cmd_phrases = cmd.get_phrases(&lang);
|
||||
|
||||
for cmd_phrase in cmd_phrases.iter() {
|
||||
let cmd_phrase_lower = cmd_phrase.trim().to_lowercase();
|
||||
let cmd_phrase_chars: Vec<char> = cmd_phrase_lower.chars().collect();
|
||||
|
||||
// character-level similarity
|
||||
let char_ratio = ratio(&phrase_chars, &cmd_phrase_chars);
|
||||
|
||||
// word-level similarity (handles word order)
|
||||
let cmd_words: Vec<&str> = cmd_phrase.split_whitespace().collect();
|
||||
// word-level similarity
|
||||
let cmd_words: Vec<&str> = cmd_phrase_lower.split_whitespace().collect();
|
||||
let word_score = word_overlap_score(&phrase_words, &cmd_words);
|
||||
|
||||
// combined score (weighted average)
|
||||
// combined score
|
||||
let score = (char_ratio * 0.6) + (word_score * 0.4);
|
||||
|
||||
// early exit on perfect match
|
||||
if score >= 99.0 {
|
||||
debug!("Perfect match: '{}' -> '{}'", phrase, cmd_phrase);
|
||||
debug!("Perfect match: '{}' -> '{}'", phrase, cmd_phrase_lower);
|
||||
return Some((&cmd_list.path, cmd));
|
||||
}
|
||||
|
||||
|
|
@ -143,16 +132,13 @@ pub fn fetch_command<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
if let Some((cmd_path, cmd)) = result {
|
||||
info!(
|
||||
"Fuzzy match: '{}' -> cmd '{}' (score: {:.1}%)",
|
||||
phrase, cmd.id, best_score
|
||||
);
|
||||
Some((cmd_path, cmd))
|
||||
if let Some((_, cmd)) = result {
|
||||
info!("Fuzzy match: '{}' -> cmd '{}' (score: {:.1}%)", phrase, cmd.id, best_score);
|
||||
} else {
|
||||
debug!("No match for '{}' (best: {:.1}%)", phrase, best_score);
|
||||
None
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -163,36 +149,38 @@ fn word_overlap_score(input_words: &[&str], cmd_words: &[&str]) -> f64 {
|
|||
|
||||
let mut matched = 0.0;
|
||||
|
||||
// pre-compute cmd word chars to avoid repeated allocations
|
||||
let cmd_word_chars: Vec<Vec<char>> = cmd_words
|
||||
.iter()
|
||||
.map(|w| w.chars().collect())
|
||||
.collect();
|
||||
|
||||
for input_word in input_words {
|
||||
// find best matching word in command
|
||||
let best_word_match = cmd_words
|
||||
.iter()
|
||||
.map(|cmd_word| {
|
||||
let iw: Vec<char> = input_word.chars().collect();
|
||||
let cw: Vec<char> = cmd_word.chars().collect();
|
||||
ratio(&iw, &cw)
|
||||
})
|
||||
.fold(0.0_f64, |a, b| a.max(b));
|
||||
let input_chars: Vec<char> = input_word.chars().collect();
|
||||
|
||||
let best_word_match = cmd_word_chars
|
||||
.iter()
|
||||
.map(|cw| ratio(&input_chars, cw))
|
||||
.fold(0.0_f64, f64::max);
|
||||
|
||||
// count as match if word similarity > 70%
|
||||
if best_word_match > 70.0 {
|
||||
matched += best_word_match / 100.0;
|
||||
}
|
||||
}
|
||||
|
||||
// normalize by max word count
|
||||
let max_words = input_words.len().max(cmd_words.len()) as f64;
|
||||
(matched / max_words) * 100.0
|
||||
}
|
||||
|
||||
|
||||
// @TODO. Rewrite executors by executor type struct. (with match arms)
|
||||
pub fn execute_exe(exe: &str, args: &Vec<String>) -> std::io::Result<Child> {
|
||||
|
||||
|
||||
pub fn execute_exe(exe: &str, args: &[String]) -> std::io::Result<Child> {
|
||||
Command::new(exe).args(args).spawn()
|
||||
}
|
||||
|
||||
pub fn execute_cli(cmd: &str, args: &Vec<String>) -> std::io::Result<Child> {
|
||||
debug!("Spawning cmd as: cmd /C {} {:?}", cmd, args);
|
||||
pub fn execute_cli(cmd: &str, args: &[String]) -> std::io::Result<Child> {
|
||||
debug!("Spawning: cmd /C {} {:?}", cmd, args);
|
||||
|
||||
if cfg!(target_os = "windows") {
|
||||
Command::new("cmd").arg("/C").arg(cmd).args(args).spawn()
|
||||
|
|
@ -201,124 +189,42 @@ pub fn execute_cli(cmd: &str, args: &Vec<String>) -> std::io::Result<Child> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn execute_command(
|
||||
cmd_path: &PathBuf,
|
||||
cmd_config: &JCommand,
|
||||
// app_handle: &tauri::AppHandle,
|
||||
) -> Result<bool, String> {
|
||||
// let sounds_directory = audio::get_sound_directory().unwrap();
|
||||
|
||||
pub fn execute_command(cmd_path: &Path, cmd_config: &JCommand) -> Result<bool, String> {
|
||||
match cmd_config.action.as_str() {
|
||||
"voice" => {
|
||||
// VOICE command type
|
||||
let random_cmd_sound = format!(
|
||||
"{}.wav",
|
||||
cmd_config
|
||||
.sounds
|
||||
.choose(&mut rand::thread_rng())
|
||||
.unwrap()
|
||||
);
|
||||
// events::play(random_cmd_sound, app_handle);
|
||||
// audio::play_sound(&sounds_directory.join(random_cmd_sound));
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
"voice" => Ok(true),
|
||||
|
||||
"ahk" => {
|
||||
// AutoHotkey command type
|
||||
let exe_path_absolute = Path::new(&cmd_config.exe_path);
|
||||
let exe_path_local = Path::new(&cmd_path).join(&cmd_config.exe_path);
|
||||
let exe_path_local = cmd_path.join(&cmd_config.exe_path);
|
||||
|
||||
if let Ok(_) = execute_exe(
|
||||
if exe_path_absolute.exists() {
|
||||
exe_path_absolute.to_str().unwrap()
|
||||
} else {
|
||||
exe_path_local.to_str().unwrap()
|
||||
},
|
||||
&cmd_config.exe_args,
|
||||
) {
|
||||
let random_cmd_sound = format!(
|
||||
"{}.wav",
|
||||
cmd_config
|
||||
.sounds
|
||||
.choose(&mut rand::thread_rng())
|
||||
.unwrap()
|
||||
);
|
||||
// events::play(random_cmd_sound, app_handle);
|
||||
// audio::play_sound(&sounds_directory.join(random_cmd_sound));
|
||||
|
||||
Ok(true)
|
||||
let exe_path = if exe_path_absolute.exists() {
|
||||
exe_path_absolute
|
||||
} else {
|
||||
error!("AHK process spawn error (does exe path is valid?)");
|
||||
Err("AHK process spawn error (does exe path is valid?)".into())
|
||||
}
|
||||
exe_path_local.as_path()
|
||||
};
|
||||
|
||||
execute_exe(exe_path.to_str().unwrap(), &cmd_config.exe_args)
|
||||
.map(|_| true)
|
||||
.map_err(|e| format!("AHK process spawn error: {}", e))
|
||||
}
|
||||
|
||||
"cli" => {
|
||||
// CLI command type
|
||||
let cli_cmd = &cmd_config.cli_cmd;
|
||||
|
||||
match execute_cli(cli_cmd, &cmd_config.cli_args) {
|
||||
Ok(_) => {
|
||||
let random_cmd_sound = format!(
|
||||
"{}.wav",
|
||||
cmd_config
|
||||
.sounds
|
||||
.choose(&mut rand::thread_rng())
|
||||
.unwrap()
|
||||
);
|
||||
// events::play(random_cmd_sound, app_handle);
|
||||
// audio::play_sound(&sounds_directory.join(random_cmd_sound));
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
Err(msg) => {
|
||||
error!("CLI command error ({})", msg);
|
||||
Err(format!("Shell command error ({})", msg).into())
|
||||
}
|
||||
}
|
||||
execute_cli(&cmd_config.cli_cmd, &cmd_config.cli_args)
|
||||
.map(|_| true)
|
||||
.map_err(|e| format!("CLI command error: {}", e))
|
||||
}
|
||||
|
||||
"terminate" => {
|
||||
// TERMINATE command type
|
||||
let random_cmd_sound = format!(
|
||||
"{}.wav",
|
||||
cmd_config
|
||||
.sounds
|
||||
.choose(&mut rand::thread_rng())
|
||||
.unwrap()
|
||||
);
|
||||
// events::play(random_cmd_sound, app_handle);
|
||||
// audio::play_sound(&sounds_directory.join(random_cmd_sound));
|
||||
|
||||
std::thread::sleep(Duration::from_secs(2));
|
||||
std::process::exit(0);
|
||||
}
|
||||
"stop_chaining" => {
|
||||
// STOP_CHAINING command type
|
||||
let random_cmd_sound = format!(
|
||||
"{}.wav",
|
||||
cmd_config
|
||||
.sounds
|
||||
.choose(&mut rand::thread_rng())
|
||||
.unwrap()
|
||||
);
|
||||
// events::play(random_cmd_sound, app_handle);
|
||||
// audio::play_sound(&sounds_directory.join(random_cmd_sound));
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
_ => {
|
||||
error!("Command type unknown");
|
||||
Err("Command type unknown".into())
|
||||
}
|
||||
|
||||
"stop_chaining" => Ok(false),
|
||||
|
||||
_ => Err(format!("Unknown command type: {}", cmd_config.action)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list(from: &Vec<JCommandsList>) -> Vec<String> {
|
||||
let mut out: Vec<String> = vec![];
|
||||
|
||||
for x in from.iter() {
|
||||
out.push(String::from(x.path.to_str().unwrap()));
|
||||
// out.append()
|
||||
}
|
||||
|
||||
out
|
||||
pub fn list_paths(commands: &[JCommandsList]) -> Vec<&Path> {
|
||||
commands.iter().map(|x| x.path.as_path()).collect()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::path::PathBuf;
|
||||
use std::{collections::HashMap, path::PathBuf, sync::Arc};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use parking_lot::RwLock;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct JCommandsList {
|
||||
|
|
@ -11,7 +12,7 @@ pub struct JCommandsList {
|
|||
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct JCommand {
|
||||
pub id: String,
|
||||
pub action: String,
|
||||
|
|
@ -31,8 +32,98 @@ pub struct JCommand {
|
|||
#[serde(default)]
|
||||
pub cli_args: Vec<String>,
|
||||
|
||||
// #[serde(default)]
|
||||
// pub sounds: Vec<String>,
|
||||
|
||||
// Multi-language sounds
|
||||
#[serde(default)]
|
||||
pub sounds: Vec<String>,
|
||||
pub sounds: HashMap<String, Vec<String>>,
|
||||
|
||||
// Multi-language phrases
|
||||
#[serde(default)]
|
||||
pub phrases: HashMap<String, Vec<String>>,
|
||||
|
||||
|
||||
// CACHE
|
||||
#[serde(skip, default)]
|
||||
sounds_cache: RwLock<HashMap<String, Arc<Vec<String>>>>,
|
||||
|
||||
pub phrases: Vec<String>,
|
||||
#[serde(skip, default)]
|
||||
phrases_cache: RwLock<HashMap<String, Arc<Vec<String>>>>,
|
||||
}
|
||||
|
||||
// custom Clone
|
||||
impl Clone for JCommand {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
id: self.id.clone(),
|
||||
action: self.action.clone(),
|
||||
description: self.description.clone(),
|
||||
exe_path: self.exe_path.clone(),
|
||||
exe_args: self.exe_args.clone(),
|
||||
cli_cmd: self.cli_cmd.clone(),
|
||||
cli_args: self.cli_args.clone(),
|
||||
sounds: self.sounds.clone(),
|
||||
phrases: self.phrases.clone(),
|
||||
|
||||
// empty caches for cloned instance
|
||||
sounds_cache: RwLock::new(HashMap::new()),
|
||||
phrases_cache: RwLock::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl JCommand {
|
||||
// get phrases for current language
|
||||
pub fn get_phrases(&self, lang: &str) -> Arc<Vec<String>> {
|
||||
if let Some(cached) = self.phrases_cache.read().get(lang) {
|
||||
return Arc::clone(cached);
|
||||
}
|
||||
|
||||
let result = Arc::new(self.resolve_localized(&self.phrases, lang));
|
||||
self.phrases_cache.write().insert(lang.to_string(), Arc::clone(&result));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
// get all phrases (for backwards compat)
|
||||
pub fn get_all_phrases(&self) -> Vec<String> {
|
||||
self.phrases.values().flatten().cloned().collect()
|
||||
}
|
||||
|
||||
// get sounds for current language
|
||||
pub fn get_sounds(&self, lang: &str) -> Arc<Vec<String>> {
|
||||
if let Some(cached) = self.sounds_cache.read().get(lang) {
|
||||
return Arc::clone(cached);
|
||||
}
|
||||
|
||||
let result = Arc::new(self.resolve_localized(&self.sounds, lang));
|
||||
self.sounds_cache.write().insert(lang.to_string(), Arc::clone(&result));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
// get all sounds (for backwards compat)
|
||||
pub fn get_all_sounds(&self) -> Vec<String> {
|
||||
self.sounds.values().flatten().cloned().collect()
|
||||
}
|
||||
|
||||
|
||||
// shared fallback
|
||||
fn resolve_localized(&self, map: &HashMap<String, Vec<String>>, lang: &str) -> Vec<String> {
|
||||
// exact match
|
||||
if let Some(values) = map.get(lang) {
|
||||
return values.clone();
|
||||
}
|
||||
|
||||
// fallback to "en"
|
||||
if lang != "en" {
|
||||
if let Some(values) = map.get("en") {
|
||||
return values.clone();
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to first available
|
||||
map.values().next().cloned().unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
|
@ -180,23 +180,72 @@ pub const NNNOISELESS_FRAME_SIZE: usize = 480;
|
|||
pub const CMD_RATIO_THRESHOLD: f64 = 65f64;
|
||||
pub const CMS_WAIT_DELAY: std::time::Duration = std::time::Duration::from_secs(15);
|
||||
|
||||
pub const ASSISTANT_GREET_PHRASES: [&str; 3] = ["greet1", "greet2", "greet3"];
|
||||
pub const ASSISTANT_PHRASES_TBR: [&str; 17] = [
|
||||
"джарвис",
|
||||
"сэр",
|
||||
"слушаю сэр",
|
||||
"всегда к услугам",
|
||||
"произнеси",
|
||||
"ответь",
|
||||
"покажи",
|
||||
"скажи",
|
||||
"давай",
|
||||
"да сэр",
|
||||
"к вашим услугам сэр",
|
||||
"всегда к вашим услугам сэр",
|
||||
"запрос выполнен сэр",
|
||||
"выполнен сэр",
|
||||
"есть",
|
||||
"загружаю сэр",
|
||||
"очень тонкое замечание сэр",
|
||||
];
|
||||
// pub const ASSISTANT_GREET_PHRASES: [&str; 3] = ["greet1", "greet2", "greet3"];
|
||||
// pub const ASSISTANT_PHRASES_TBR: [&str; 17] = [
|
||||
// "джарвис",
|
||||
// "сэр",
|
||||
// "слушаю сэр",
|
||||
// "всегда к услугам",
|
||||
// "произнеси",
|
||||
// "ответь",
|
||||
// "покажи",
|
||||
// "скажи",
|
||||
// "давай",
|
||||
// "да сэр",
|
||||
// "к вашим услугам сэр",
|
||||
// "всегда к вашим услугам сэр",
|
||||
// "запрос выполнен сэр",
|
||||
// "выполнен сэр",
|
||||
// "есть",
|
||||
// "загружаю сэр",
|
||||
// "очень тонкое замечание сэр",
|
||||
// ];
|
||||
|
||||
|
||||
|
||||
pub fn get_wake_phrase(lang: &str) -> &'static str {
|
||||
match lang {
|
||||
"ru" => "джарвис",
|
||||
"ua" => "джарвіс",
|
||||
"en" => "jarvis",
|
||||
_ => "jarvis",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_phrases_to_remove(lang: &str) -> &'static [&'static str] {
|
||||
match lang {
|
||||
"ru" => &[
|
||||
"джарвис", "сэр", "слушаю сэр", "всегда к услугам",
|
||||
"произнеси", "ответь", "покажи", "скажи", "давай",
|
||||
"да сэр", "к вашим услугам сэр", "загружаю сэр",
|
||||
],
|
||||
"ua" => &[
|
||||
"джарвіс", "сер", "слухаю сер", "завжди до послуг",
|
||||
"скажи", "покажи", "відповідай", "давай",
|
||||
"так сер", "до ваших послуг сер",
|
||||
],
|
||||
"en" => &[
|
||||
"jarvis", "sir", "yes sir", "at your service",
|
||||
"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]"],
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +92,9 @@ settings-picovoice-key = Picovoice Key
|
|||
# settings - vosk
|
||||
settings-auto-detect = Auto-detect
|
||||
settings-vosk-model = Speech recognition model (Vosk)
|
||||
settings-vosk-model-desc = Select Vosk model for speech recognition.
|
||||
settings-vosk-model-desc =
|
||||
Select Vosk model for speech recognition.
|
||||
You can download models here: https://alphacephei.com/vosk/models
|
||||
settings-models-not-found = Models not found
|
||||
settings-models-hint = Place Vosk models in resources/vosk folder
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,9 @@ settings-picovoice-key = Ключ Picovoice
|
|||
# settings - vosk
|
||||
settings-auto-detect = Авто-определение
|
||||
settings-vosk-model = Модель распознавания речи (Vosk)
|
||||
settings-vosk-model-desc = Выберите модель Vosk для распознавания речи.
|
||||
settings-vosk-model-desc =
|
||||
Выберите модель Vosk для распознавания речи.
|
||||
Вы можете скачать модели здесь: https://alphacephei.com/vosk/models
|
||||
settings-models-not-found = Модели не найдены
|
||||
settings-models-hint = Поместите модели Vosk в папку resources/vosk
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,9 @@ settings-picovoice-key = Ключ Picovoice
|
|||
# settings - vosk
|
||||
settings-auto-detect = Авто-визначення
|
||||
settings-vosk-model = Модель розпізнавання мовлення (Vosk)
|
||||
settings-vosk-model-desc = Виберіть модель Vosk для розпізнавання мовлення.
|
||||
settings-vosk-model-desc =
|
||||
Виберіть модель Vosk для розпізнавання мовлення.
|
||||
Ви можете завантажити моделі тут: https://alphacephei.com/vosk/models
|
||||
settings-models-not-found = Моделі не знайдено
|
||||
settings-models-hint = Помістіть моделі Vosk в папку resources/vosk
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::path::PathBuf;
|
|||
use std::fs;
|
||||
|
||||
use crate::commands::{self, JCommand, JCommandsList};
|
||||
use crate::{APP_CONFIG_DIR};
|
||||
use crate::{APP_CONFIG_DIR, i18n};
|
||||
|
||||
static CLASSIFIER: OnceCell<IntentClassifier> = OnceCell::const_new();
|
||||
// static COMMANDS_MAP: OnceCell<Vec<JCommandsList>> = OnceCell::const_new();
|
||||
|
|
@ -16,7 +16,7 @@ static CLASSIFIER: OnceCell<IntentClassifier> = OnceCell::const_new();
|
|||
const TRAINING_CACHE_FILE: &str = "intent_training.json";
|
||||
const COMMANDS_HASH_FILE: &str = "commands_hash.txt";
|
||||
|
||||
pub async fn init(commands: &Vec<JCommandsList>) -> Result<(), String> {
|
||||
pub async fn init(commands: &[JCommandsList]) -> Result<(), String> {
|
||||
// parse commands first
|
||||
// let commands = commands::parse_commands()?;
|
||||
let current_hash = commands::commands_hash(&commands); // regen hash for current commands set
|
||||
|
|
@ -68,7 +68,7 @@ pub async fn classify(text: &str) -> Result<IntentPrediction, IntentError> {
|
|||
}
|
||||
|
||||
// get command by intent ID
|
||||
pub fn get_command(commands: &'static Vec<JCommandsList>, intent_id: &str) -> Option<(&'static PathBuf, &'static JCommand)> {
|
||||
pub fn get_command(commands: &'static [JCommandsList], intent_id: &str) -> Option<(&'static PathBuf, &'static JCommand)> {
|
||||
// let commands = COMMANDS_MAP.get()?;
|
||||
|
||||
for assistant_cmd in commands {
|
||||
|
|
@ -85,11 +85,19 @@ pub fn get_command(commands: &'static Vec<JCommandsList>, intent_id: &str) -> Op
|
|||
// based on: https://github.com/ciresnave/intent-classifier/blob/main/examples/basic_usage.rs
|
||||
async fn train_classifier(
|
||||
classifier: &IntentClassifier,
|
||||
commands: &Vec<JCommandsList>
|
||||
commands: &[JCommandsList]
|
||||
) -> Result<(), String> {
|
||||
let lang = i18n::get_language();
|
||||
info!("Training intent classifier for language: {}", lang);
|
||||
|
||||
let mut total_examples = 0;
|
||||
|
||||
for assistant_cmd in commands {
|
||||
for cmd in &assistant_cmd.commands {
|
||||
for phrase in &cmd.phrases {
|
||||
// use language-specific phrases
|
||||
let phrases = cmd.get_phrases(&lang);
|
||||
|
||||
for phrase in phrases.iter() {
|
||||
let example = TrainingExample {
|
||||
text: phrase.clone(),
|
||||
intent: IntentId::from(cmd.id.as_str()),
|
||||
|
|
@ -99,9 +107,12 @@ async fn train_classifier(
|
|||
|
||||
classifier.add_training_example(example).await
|
||||
.map_err(|e| format!("Failed to add training example: {}", e))?;
|
||||
|
||||
total_examples += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
info!("Added {} training examples for language '{}'", total_examples, lang);
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{config, stt};
|
||||
use crate::{config, stt, i18n};
|
||||
|
||||
pub fn init() -> Result<(), ()> {
|
||||
Ok(()) // nothing to init for Vosk
|
||||
|
|
@ -15,8 +15,12 @@ pub fn data_callback(frame_buffer: &[i16]) -> Option<i32> {
|
|||
|
||||
info!("Wake word candidate: '{}'", recognized);
|
||||
|
||||
// language-specific wake phrase
|
||||
let lang = i18n::get_language();
|
||||
let wake_phrase = config::get_wake_phrase(&lang);
|
||||
|
||||
// verify with seqdiff ratio
|
||||
let wake_chars: Vec<char> = config::VOSK_FETCH_PHRASE.chars().collect();
|
||||
let wake_chars: Vec<char> = wake_phrase.chars().collect();
|
||||
let recognized_chars: Vec<char> = recognized.chars().collect();
|
||||
let similarity = seqdiff::ratio(&wake_chars, &recognized_chars);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ use vosk::{DecodingState, Model, Recognizer};
|
|||
use std::sync::Mutex;
|
||||
|
||||
// use crate::config::VOSK_MODEL_PATH;
|
||||
use crate::config;
|
||||
use crate::stt::vosk_models;
|
||||
use crate::{stt::vosk_models, i18n, config};
|
||||
use crate::DB;
|
||||
|
||||
static MODEL: OnceCell<Model> = OnceCell::new();
|
||||
|
|
@ -23,19 +22,14 @@ pub fn init_vosk() -> Result<(), String> {
|
|||
let model = Model::new(model_path.to_str().unwrap())
|
||||
.ok_or_else(|| format!("Failed to load Vosk model from: {}", model_path.display()))?;
|
||||
|
||||
// language-specific wake grammar
|
||||
let lang = i18n::get_language();
|
||||
let wake_grammar = config::get_wake_grammar(&lang);
|
||||
info!("Wake grammar for '{}': {:?}", lang, wake_grammar);
|
||||
|
||||
//let mut recognizer = Recognizer::new(&model, 16000.0)
|
||||
// .ok_or("Failed to create Vosk recognizer")?;
|
||||
let wake_phrases: &[&str] = &[
|
||||
config::VOSK_FETCH_PHRASE,
|
||||
"[unk]",
|
||||
"джон",
|
||||
"джони",
|
||||
"джей",
|
||||
"джонстон",
|
||||
"привет",
|
||||
"давай",
|
||||
];
|
||||
let mut wake_recognizer = Recognizer::new_with_grammar(&model, 16000.0, wake_phrases)
|
||||
let mut wake_recognizer = Recognizer::new_with_grammar(&model, 16000.0, wake_grammar)
|
||||
.ok_or("Failed to create wake word recognizer")?;
|
||||
|
||||
wake_recognizer.set_max_alternatives(1); // required for confidence check later on
|
||||
|
|
|
|||
|
|
@ -78,15 +78,15 @@ fn load_voice_config(toml_path: &Path, voice_path: &Path) -> Result<structs::Voi
|
|||
|
||||
|
||||
|
||||
pub fn list_voices() -> Vec<structs::VoiceConfig> {
|
||||
VOICES.get().cloned().unwrap_or_default()
|
||||
pub fn list_voices() -> &'static [structs::VoiceConfig] {
|
||||
VOICES.get().map(|v| v.as_slice()).unwrap_or(&[])
|
||||
}
|
||||
|
||||
pub fn get_voice(voice_id: &str) -> Option<structs::VoiceConfig> {
|
||||
VOICES.get()?.iter().find(|v| v.voice.id == voice_id).cloned()
|
||||
pub fn get_voice(voice_id: &str) -> Option<&'static structs::VoiceConfig> {
|
||||
VOICES.get()?.iter().find(|v| v.voice.id == voice_id)
|
||||
}
|
||||
|
||||
pub fn get_current_voice() -> Option<structs::VoiceConfig> {
|
||||
pub fn get_current_voice() -> Option<&'static structs::VoiceConfig> {
|
||||
let current_id = CURRENT_VOICE_ID.get()?.read().clone();
|
||||
get_voice(¤t_id)
|
||||
}
|
||||
|
|
@ -106,11 +106,11 @@ fn get_current_language() -> String {
|
|||
|
||||
|
||||
fn find_sound_file(voice_path: &Path, lang: &str, sound_name: &str) -> Option<PathBuf> {
|
||||
let extensions = ["mp3", "wav", "ogg"];
|
||||
const EXTENSIONS: &[&str] = &["mp3", "wav", "ogg"];
|
||||
let lang_path = voice_path.join(lang);
|
||||
|
||||
// try language subfolder first
|
||||
for ext in &extensions {
|
||||
// try language subfolder first (/en, /ua, /ru, etc)
|
||||
for ext in EXTENSIONS {
|
||||
let file_path = lang_path.join(format!("{}.{}", sound_name, ext));
|
||||
if file_path.exists() {
|
||||
return Some(file_path);
|
||||
|
|
@ -118,7 +118,7 @@ fn find_sound_file(voice_path: &Path, lang: &str, sound_name: &str) -> Option<Pa
|
|||
}
|
||||
|
||||
// fallback to root voice folder
|
||||
for ext in &extensions {
|
||||
for ext in EXTENSIONS {
|
||||
let file_path = voice_path.join(format!("{}.{}", sound_name, ext));
|
||||
if file_path.exists() {
|
||||
return Some(file_path);
|
||||
|
|
@ -128,29 +128,20 @@ fn find_sound_file(voice_path: &Path, lang: &str, sound_name: &str) -> Option<Pa
|
|||
None
|
||||
}
|
||||
|
||||
fn play_random_from(sounds: &[String]) {
|
||||
fn play_random_from_list(voice_path: &Path, lang: &str, sounds: &[String]) {
|
||||
if sounds.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let voice = match get_current_voice() {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
warn!("No current voice set");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let lang = get_current_language();
|
||||
let sound_name = sounds.choose(&mut rand::thread_rng()).unwrap();
|
||||
|
||||
match find_sound_file(&voice.path, &lang, sound_name) {
|
||||
match find_sound_file(voice_path, lang, sound_name) {
|
||||
Some(path) => {
|
||||
debug!("Playing: {:?}", path);
|
||||
audio::play_sound(&path);
|
||||
}
|
||||
None => {
|
||||
warn!("Sound not found: {} (lang: {}, voice: {})", sound_name, lang, voice.voice.id);
|
||||
warn!("Sound not found: {} (lang: {})", sound_name, lang);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -164,32 +155,53 @@ pub fn play(reaction: structs::Reaction) {
|
|||
}
|
||||
};
|
||||
|
||||
let lang = get_current_language();
|
||||
|
||||
let reactions = match voice.reactions.get(&lang) {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
warn!("No reactions for language: {}", lang);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let sounds = match reaction {
|
||||
structs::Reaction::Greet => {
|
||||
// try time specific first
|
||||
// try time-specific first
|
||||
let time_specific = match time::TimeOfDay::now() {
|
||||
time::TimeOfDay::Morning => &voice.reactions.greet_morning,
|
||||
time::TimeOfDay::Day => &voice.reactions.greet_day,
|
||||
time::TimeOfDay::Evening => &voice.reactions.greet_evening,
|
||||
time::TimeOfDay::Night => &voice.reactions.greet_night,
|
||||
time::TimeOfDay::Morning => &reactions.greet_morning,
|
||||
time::TimeOfDay::Day => &reactions.greet_day,
|
||||
time::TimeOfDay::Evening => &reactions.greet_evening,
|
||||
time::TimeOfDay::Night => &reactions.greet_night,
|
||||
};
|
||||
|
||||
if time_specific.is_empty() {
|
||||
// fallback to simple run voice (not time specific)
|
||||
&voice.reactions.greet
|
||||
&reactions.greet
|
||||
} else {
|
||||
time_specific
|
||||
}
|
||||
}
|
||||
structs::Reaction::Reply => &voice.reactions.reply,
|
||||
structs::Reaction::Ok => &voice.reactions.ok,
|
||||
structs::Reaction::NotFound => &voice.reactions.not_found,
|
||||
structs::Reaction::Thanks => &voice.reactions.thanks,
|
||||
structs::Reaction::Error => &voice.reactions.error,
|
||||
structs::Reaction::Goodbye => &voice.reactions.goodbye,
|
||||
structs::Reaction::Reply => &reactions.reply,
|
||||
structs::Reaction::Ok => &reactions.ok,
|
||||
structs::Reaction::NotFound => &reactions.not_found,
|
||||
structs::Reaction::Thanks => &reactions.thanks,
|
||||
structs::Reaction::Error => &reactions.error,
|
||||
structs::Reaction::Goodbye => &reactions.goodbye,
|
||||
};
|
||||
|
||||
play_random_from(sounds);
|
||||
play_random_from_list(&voice.path, &lang, sounds);
|
||||
}
|
||||
|
||||
pub fn play_random_from(sounds: &[String]) {
|
||||
let voice = match get_current_voice() {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
warn!("No current voice set");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
play_random_from_list(&voice.path, &get_current_language(), sounds);
|
||||
}
|
||||
|
||||
// Play a preview sound for a specific voice
|
||||
|
|
@ -204,10 +216,18 @@ pub fn play_preview(voice_id: &str) {
|
|||
|
||||
let lang = get_current_language();
|
||||
|
||||
// pick from reply or ok sounds for preview
|
||||
let sounds: Vec<&String> = voice.reactions.reply.iter()
|
||||
.chain(voice.reactions.ok.iter())
|
||||
.chain(voice.reactions.greet.iter())
|
||||
let reactions = match voice.reactions.get(&lang) {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
warn!("No reactions for language {} in voice {}", lang, voice_id);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// pick from reply, ok, or greet sounds for preview
|
||||
let sounds: Vec<&String> = reactions.reply.iter()
|
||||
.chain(reactions.ok.iter())
|
||||
.chain(reactions.greet.iter())
|
||||
.collect();
|
||||
|
||||
if sounds.is_empty() {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,26 @@
|
|||
use std::path::PathBuf;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VoiceConfig {
|
||||
|
||||
#[serde(skip)]
|
||||
pub path: PathBuf,
|
||||
|
||||
pub voice: VoiceMeta,
|
||||
pub reactions: VoiceReactions,
|
||||
|
||||
// Multi-language reactions
|
||||
pub reactions: HashMap<String, VoiceReactions>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VoiceMeta {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub author: String,
|
||||
|
||||
pub languages: Vec<String>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ use jarvis_core::voices::{self, structs::VoiceConfig};
|
|||
|
||||
#[tauri::command]
|
||||
pub fn list_voices() -> Vec<VoiceConfig> {
|
||||
voices::list_voices()
|
||||
voices::list_voices().to_vec()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_voice(voice_id: String) -> Option<VoiceConfig> {
|
||||
voices::get_voice(&voice_id)
|
||||
voices::get_voice(&voice_id).cloned()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ body {
|
|||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.svelteui-InputWrapper-description {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
// ### FONTS
|
||||
$prim-font: "Roboto", sans-serif;
|
||||
$sec-font: "Roboto Condensed", sans-serif;
|
||||
|
|
|
|||
|
|
@ -158,9 +158,18 @@
|
|||
]
|
||||
|
||||
// load vosk models
|
||||
const languageNames: Record<string, string> = {
|
||||
us: 'English',
|
||||
ru: 'Русский',
|
||||
uk: 'Українська',
|
||||
de: 'German',
|
||||
fr: 'French',
|
||||
es: 'Spanish',
|
||||
// ..
|
||||
};
|
||||
const voskModels = await invoke<{ name: string; language: string; size: string }[]>("list_vosk_models")
|
||||
availableVoskModels = voskModels.map(m => ({
|
||||
label: `${m.name} (${m.language}, ${m.size})`,
|
||||
label: `${m.name} (${languageNames[m.language] ?? m.language}, ${m.size})`,
|
||||
value: m.name
|
||||
}))
|
||||
|
||||
|
|
|
|||
|
|
@ -2,51 +2,90 @@
|
|||
id = "browser_open"
|
||||
action = "ahk"
|
||||
exe_path = "ahk/Run browser.exe"
|
||||
sounds = ["ok1", "ok2", "ok3"]
|
||||
phrases = [
|
||||
sounds.ru = ["ok1", "ok2", "ok3", "ok4"]
|
||||
sounds.en = ["ok1", "ok2", "ok3"]
|
||||
sounds.ua = ["ok1", "ok2", "ok3", "ok4", "ok5", "ok6"]
|
||||
|
||||
phrases.ru = [
|
||||
"открой браузер",
|
||||
"запусти браузер",
|
||||
"открой хром",
|
||||
"запусти хром",
|
||||
"открой гугл хром",
|
||||
"запусти гугл хром",
|
||||
"включи браузер",
|
||||
"браузер открой",
|
||||
"нужен браузер",
|
||||
"мне нужен браузер",
|
||||
]
|
||||
phrases.en = [
|
||||
"open browser",
|
||||
"launch browser",
|
||||
"open chrome",
|
||||
"launch chrome",
|
||||
"start browser",
|
||||
"i need browser",
|
||||
]
|
||||
phrases.ua = [
|
||||
"відкрий браузер",
|
||||
"запусти браузер",
|
||||
"відкрий хром",
|
||||
"запусти хром",
|
||||
"увімкни браузер",
|
||||
"потрібен браузер",
|
||||
]
|
||||
|
||||
|
||||
|
||||
[[commands]]
|
||||
id = "browser_close"
|
||||
action = "ahk"
|
||||
exe_path = "ahk/Close browser.exe"
|
||||
sounds = ["ok1", "ok2", "ok3", "ok4"]
|
||||
phrases = [
|
||||
sounds.ru = ["ok1", "ok2", "ok3", "ok4"]
|
||||
sounds.en = ["ok1", "ok2", "ok3"]
|
||||
sounds.ua = ["ok1", "ok2", "ok3", "ok4", "ok5", "ok6"]
|
||||
|
||||
phrases.ru = [
|
||||
"закрой браузер",
|
||||
"закрой все браузеры",
|
||||
"выключи браузер",
|
||||
"убери браузер",
|
||||
"закрой хром",
|
||||
"выключи хром",
|
||||
"закрой гугл хром",
|
||||
"браузер закрой",
|
||||
"сверни браузер",
|
||||
]
|
||||
phrases.en = [
|
||||
"close browser",
|
||||
"close all browsers",
|
||||
"shut down browser",
|
||||
"exit browser",
|
||||
]
|
||||
phrases.ua = [
|
||||
"закрий браузер",
|
||||
"закрий всі браузери",
|
||||
"вимкни браузер",
|
||||
]
|
||||
|
||||
|
||||
|
||||
[[commands]]
|
||||
id = "open_google"
|
||||
action = "ahk"
|
||||
exe_path = "ahk/Run website.exe"
|
||||
exe_args = ["http://google.com"]
|
||||
sounds = ["ok1", "ok2", "ok3", "ok4"]
|
||||
phrases = [
|
||||
sounds.ru = ["ok1", "ok2", "ok3", "ok4"]
|
||||
sounds.en = ["ok1", "ok2", "ok3"]
|
||||
sounds.ua = ["ok1", "ok2", "ok3", "ok4", "ok5", "ok6"]
|
||||
|
||||
phrases.ru = [
|
||||
"открой гугл",
|
||||
"открой гугл поиск",
|
||||
"запусти гугл",
|
||||
"перейди в гугл",
|
||||
"перейди на гугл",
|
||||
"открой поисковик",
|
||||
"зайди в гугл",
|
||||
"гугл поиск",
|
||||
"поиск гугл",
|
||||
]
|
||||
]
|
||||
phrases.en = [
|
||||
"open google",
|
||||
"google search",
|
||||
"launch google",
|
||||
"go to google",
|
||||
]
|
||||
phrases.ua = [
|
||||
"відкрий гугл",
|
||||
"відкрий гугл пошук",
|
||||
"запусти гугл",
|
||||
"зайди в гугл",
|
||||
]
|
||||
|
|
|
|||
19
resources/commands/weather/ahk/Close browser.ahk
Normal file
19
resources/commands/weather/ahk/Close browser.ahk
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
; Rerun as admin, if required
|
||||
If Not A_IsAdmin
|
||||
{
|
||||
Run *RunAs "%A_ScriptFullPath%"
|
||||
ExitApp
|
||||
}
|
||||
|
||||
; set partial title matching mode
|
||||
SetTitleMatchMode, 2
|
||||
|
||||
; list of all browsers to close
|
||||
GroupAdd, browsers, ahk_class MozillaWindowClass
|
||||
GroupAdd, browsers, ahk_class IEFrame
|
||||
GroupAdd, browsers, ahk_exe msedge.exe
|
||||
GroupAdd, browsers, ahk_exe chrome.exe
|
||||
GroupAdd, browsers, ahk_exe firefox.exe
|
||||
|
||||
; kill them all
|
||||
Winclose, ahk_group browsers
|
||||
11
resources/commands/weather/ahk/Run browser.ahk
Normal file
11
resources/commands/weather/ahk/Run browser.ahk
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
|
||||
; #Warn ; Enable warnings to assist with detecting common errors.
|
||||
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
|
||||
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
|
||||
|
||||
RegRead, BrowserKeyName, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice, Progid
|
||||
RegRead, BrowserFullCommand, HKEY_CLASSES_ROOT, %BrowserKeyName%\shell\open\command
|
||||
StringGetPos, pos, BrowserFullCommand, ",,1
|
||||
pos := --pos
|
||||
StringMid, BrowserPathandEXE, BrowserFullCommand, 2, %pos%
|
||||
Run, % BrowserPathandEXE
|
||||
11
resources/commands/weather/ahk/Run website.ahk
Normal file
11
resources/commands/weather/ahk/Run website.ahk
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
|
||||
; #Warn ; Enable warnings to assist with detecting common errors.
|
||||
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
|
||||
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
|
||||
|
||||
#Include _include.ahk
|
||||
|
||||
args = %1%
|
||||
path := DefaultBrowser()
|
||||
|
||||
Run, %path% %args%
|
||||
19
resources/commands/weather/ahk/_include.ahk
Normal file
19
resources/commands/weather/ahk/_include.ahk
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
DefaultBrowser() {
|
||||
; Find the Registry key name for the default browser
|
||||
RegRead, BrowserKeyName, HKEY_CURRENT_USER, Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice, Progid
|
||||
|
||||
; Find the executable command associated with the above Registry key
|
||||
RegRead, BrowserFullCommand, HKEY_CLASSES_ROOT, %BrowserKeyName%\shell\open\command
|
||||
|
||||
; The above RegRead will return the path and executable name of the brower contained within quotes and optional parameters
|
||||
; We only want the text contained inside the first set of quotes which is the path and executable
|
||||
; Find the ending quote position (we know the beginning quote is in position 0 so start searching at position 1)
|
||||
StringGetPos, pos, BrowserFullCommand, ",,1
|
||||
|
||||
; Decrement the found position by one to work correctly with the StringMid function
|
||||
pos := --pos
|
||||
|
||||
; Extract and return the path and executable of the browser
|
||||
StringMid, BrowserPathandEXE, BrowserFullCommand, 2, %pos%
|
||||
Return BrowserPathandEXE
|
||||
}
|
||||
18
resources/commands/weather/command.toml
Normal file
18
resources/commands/weather/command.toml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[[commands]]
|
||||
id = "weather"
|
||||
action = "cli"
|
||||
cli_cmd = "weather.py"
|
||||
|
||||
[commands.phrases]
|
||||
ru = [
|
||||
"какая погода",
|
||||
"погода"
|
||||
]
|
||||
en = [
|
||||
"what's the weather",
|
||||
"weather"
|
||||
]
|
||||
|
||||
[commands.sounds]
|
||||
ru = ["weather_ru_1", "weather_ru_2"]
|
||||
en = ["weather_en_1", "weather_en_2"]
|
||||
|
|
@ -4,7 +4,7 @@ name = "Jarvis Howdy"
|
|||
author = "Abraham (Priler)"
|
||||
languages = ["ru"]
|
||||
|
||||
[reactions]
|
||||
[reactions.ru]
|
||||
# app startup
|
||||
greet = ["run", "ready"]
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ name = "Jarvis OG"
|
|||
author = "Abraham (Priler)"
|
||||
languages = ["ru"]
|
||||
|
||||
[reactions]
|
||||
[reactions.ru]
|
||||
# app startup
|
||||
greet = ["run"]
|
||||
|
||||
|
|
|
|||
BIN
resources/sound/voices/jarvis-remaster/en/good_morning.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/en/good_morning.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/en/greet_day.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/en/greet_day.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/en/greet_evening.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/en/greet_evening.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/en/greet_night.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/en/greet_night.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/greet_day1.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/greet_day1.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/greet_day2.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/greet_day2.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/greet_evening1.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/greet_evening1.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/greet_evening2.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/greet_evening2.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/greet_morning1.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/greet_morning1.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/greet_morning2.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/greet_morning2.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/greet_morning3.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/greet_morning3.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/greet_night1.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/greet_night1.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/greet_night2.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/greet_night2.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/ok1.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/ok1.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/ok2.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/ok2.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/ok3.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/ok3.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/ok4.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/ok4.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/ok5.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/ok5.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/ok6.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/ok6.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/reply1.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/reply1.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/reply2.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/reply2.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/reply3.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/reply3.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/reply4.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/reply4.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/reply5.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/reply5.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/stupid1.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/stupid1.mp3
Normal file
Binary file not shown.
BIN
resources/sound/voices/jarvis-remaster/ua/stupid2.mp3
Normal file
BIN
resources/sound/voices/jarvis-remaster/ua/stupid2.mp3
Normal file
Binary file not shown.
|
|
@ -2,9 +2,9 @@
|
|||
id = "jarvis-remaster"
|
||||
name = "Jarvis New"
|
||||
author = "Abraham (Priler)"
|
||||
languages = ["ru", "en"]
|
||||
languages = ["ru", "ua", "en"]
|
||||
|
||||
[reactions]
|
||||
[reactions.ru]
|
||||
# app startup
|
||||
greet = ["greet1"]
|
||||
greet_morning = ["greet_morning"]
|
||||
|
|
@ -27,5 +27,61 @@ thanks = ["thanks"]
|
|||
# error
|
||||
error = []
|
||||
|
||||
# goodbye
|
||||
goodbye = []
|
||||
|
||||
|
||||
|
||||
[reactions.ua]
|
||||
# app startup
|
||||
greet = []
|
||||
greet_morning = ["greet_morning1", "greet_morning2", "greet_morning3"]
|
||||
greet_day = ["greet_day1", "greet_day2"]
|
||||
greet_evening = ["greet_evening1", "greet_evening2"]
|
||||
greet_night = ["greet_night1", "greet_night2"]
|
||||
|
||||
# wake word detected
|
||||
reply = ["reply1", "reply2", "reply3", "reply4", "reply5"]
|
||||
|
||||
# command executed
|
||||
ok = ["ok1", "ok2", "ok3", "ok4", "ok5", "ok6"]
|
||||
|
||||
# command not found
|
||||
not_found = []
|
||||
|
||||
# thanks
|
||||
thanks = []
|
||||
|
||||
# error
|
||||
error = []
|
||||
|
||||
# goodbye
|
||||
goodbye = []
|
||||
|
||||
|
||||
|
||||
[reactions.en]
|
||||
# app startup
|
||||
greet = []
|
||||
greet_morning = ["greet_morning"]
|
||||
greet_day = ["greet_day"]
|
||||
greet_evening = ["greet_evening"]
|
||||
greet_night = ["greet_night"]
|
||||
|
||||
# wake word detected
|
||||
reply = ["reply1", "reply2", "reply3", "reply4", "reply5"]
|
||||
|
||||
# command executed
|
||||
ok = ["ok1", "ok2", "ok3", "ok4", "ok5", "ok6"]
|
||||
|
||||
# command not found
|
||||
not_found = []
|
||||
|
||||
# thanks
|
||||
thanks = []
|
||||
|
||||
# error
|
||||
error = []
|
||||
|
||||
# goodbye
|
||||
goodbye = []
|
||||
176
resources/vosk/vosk-model-small-uk-v3-nano/COPYING
Normal file
176
resources/vosk/vosk-model-small-uk-v3-nano/COPYING
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. this License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
BIN
resources/vosk/vosk-model-small-uk-v3-nano/am/final.mdl
Normal file
BIN
resources/vosk/vosk-model-small-uk-v3-nano/am/final.mdl
Normal file
Binary file not shown.
11
resources/vosk/vosk-model-small-uk-v3-nano/conf/mfcc.conf
Normal file
11
resources/vosk/vosk-model-small-uk-v3-nano/conf/mfcc.conf
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# config for high-resolution MFCC features, intended for neural network training
|
||||
# Note: we keep all cepstra, so it has the same info as filterbank features,
|
||||
# but MFCC is more easily compressible (because less correlated) which is why
|
||||
# we prefer this method.
|
||||
--use-energy=false # use average of log energy, not energy.
|
||||
--sample-frequency=16000
|
||||
--num-mel-bins=40 # similar to Google's setup.
|
||||
--num-ceps=40 # there is no dimensionality reduction.
|
||||
--low-freq=20 # low cutoff frequency for mel bins... this is high-bandwidth data, so
|
||||
# there might be some information at the low end.
|
||||
--high-freq=-400 # high cutoff frequently, relative to Nyquist of 8000 (=7600)
|
||||
10
resources/vosk/vosk-model-small-uk-v3-nano/conf/model.conf
Normal file
10
resources/vosk/vosk-model-small-uk-v3-nano/conf/model.conf
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
--min-active=200
|
||||
--max-active=3000
|
||||
--beam=13.0
|
||||
--lattice-beam=2.0
|
||||
--acoustic-scale=1.0
|
||||
--frame-subsampling-factor=3
|
||||
--endpoint.silence-phones=1:2:3:4:5:6:7:8:9:10
|
||||
--endpoint.rule2.min-trailing-silence=0.5
|
||||
--endpoint.rule3.min-trailing-silence=1.0
|
||||
--endpoint.rule4.min-trailing-silence=2.0
|
||||
BIN
resources/vosk/vosk-model-small-uk-v3-nano/graph/Gr.fst
Normal file
BIN
resources/vosk/vosk-model-small-uk-v3-nano/graph/Gr.fst
Normal file
Binary file not shown.
BIN
resources/vosk/vosk-model-small-uk-v3-nano/graph/HCLr.fst
Normal file
BIN
resources/vosk/vosk-model-small-uk-v3-nano/graph/HCLr.fst
Normal file
Binary file not shown.
|
|
@ -0,0 +1,6 @@
|
|||
28121
|
||||
28122
|
||||
28123
|
||||
28124
|
||||
28125
|
||||
28126
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
1 nonword
|
||||
2 begin
|
||||
3 end
|
||||
4 internal
|
||||
5 singleton
|
||||
6 nonword
|
||||
7 begin
|
||||
8 end
|
||||
9 internal
|
||||
10 singleton
|
||||
11 begin
|
||||
12 end
|
||||
13 internal
|
||||
14 singleton
|
||||
15 begin
|
||||
16 end
|
||||
17 internal
|
||||
18 singleton
|
||||
19 begin
|
||||
20 end
|
||||
21 internal
|
||||
22 singleton
|
||||
23 begin
|
||||
24 end
|
||||
25 internal
|
||||
26 singleton
|
||||
27 begin
|
||||
28 end
|
||||
29 internal
|
||||
30 singleton
|
||||
31 begin
|
||||
32 end
|
||||
33 internal
|
||||
34 singleton
|
||||
35 begin
|
||||
36 end
|
||||
37 internal
|
||||
38 singleton
|
||||
39 begin
|
||||
40 end
|
||||
41 internal
|
||||
42 singleton
|
||||
43 begin
|
||||
44 end
|
||||
45 internal
|
||||
46 singleton
|
||||
47 begin
|
||||
48 end
|
||||
49 internal
|
||||
50 singleton
|
||||
51 begin
|
||||
52 end
|
||||
53 internal
|
||||
54 singleton
|
||||
55 begin
|
||||
56 end
|
||||
57 internal
|
||||
58 singleton
|
||||
59 begin
|
||||
60 end
|
||||
61 internal
|
||||
62 singleton
|
||||
63 begin
|
||||
64 end
|
||||
65 internal
|
||||
66 singleton
|
||||
67 begin
|
||||
68 end
|
||||
69 internal
|
||||
70 singleton
|
||||
71 begin
|
||||
72 end
|
||||
73 internal
|
||||
74 singleton
|
||||
75 begin
|
||||
76 end
|
||||
77 internal
|
||||
78 singleton
|
||||
79 begin
|
||||
80 end
|
||||
81 internal
|
||||
82 singleton
|
||||
83 begin
|
||||
84 end
|
||||
85 internal
|
||||
86 singleton
|
||||
87 begin
|
||||
88 end
|
||||
89 internal
|
||||
90 singleton
|
||||
91 begin
|
||||
92 end
|
||||
93 internal
|
||||
94 singleton
|
||||
95 begin
|
||||
96 end
|
||||
97 internal
|
||||
98 singleton
|
||||
99 begin
|
||||
100 end
|
||||
101 internal
|
||||
102 singleton
|
||||
103 begin
|
||||
104 end
|
||||
105 internal
|
||||
106 singleton
|
||||
107 begin
|
||||
108 end
|
||||
109 internal
|
||||
110 singleton
|
||||
111 begin
|
||||
112 end
|
||||
113 internal
|
||||
114 singleton
|
||||
115 begin
|
||||
116 end
|
||||
117 internal
|
||||
118 singleton
|
||||
119 begin
|
||||
120 end
|
||||
121 internal
|
||||
122 singleton
|
||||
123 begin
|
||||
124 end
|
||||
125 internal
|
||||
126 singleton
|
||||
127 begin
|
||||
128 end
|
||||
129 internal
|
||||
130 singleton
|
||||
131 begin
|
||||
132 end
|
||||
133 internal
|
||||
134 singleton
|
||||
135 begin
|
||||
136 end
|
||||
137 internal
|
||||
138 singleton
|
||||
139 begin
|
||||
140 end
|
||||
141 internal
|
||||
142 singleton
|
||||
143 begin
|
||||
144 end
|
||||
145 internal
|
||||
146 singleton
|
||||
147 begin
|
||||
148 end
|
||||
149 internal
|
||||
150 singleton
|
||||
151 begin
|
||||
152 end
|
||||
153 internal
|
||||
154 singleton
|
||||
155 begin
|
||||
156 end
|
||||
157 internal
|
||||
158 singleton
|
||||
159 begin
|
||||
160 end
|
||||
161 internal
|
||||
162 singleton
|
||||
163 begin
|
||||
164 end
|
||||
165 internal
|
||||
166 singleton
|
||||
167 begin
|
||||
168 end
|
||||
169 internal
|
||||
170 singleton
|
||||
171 begin
|
||||
172 end
|
||||
173 internal
|
||||
174 singleton
|
||||
175 begin
|
||||
176 end
|
||||
177 internal
|
||||
178 singleton
|
||||
179 begin
|
||||
180 end
|
||||
181 internal
|
||||
182 singleton
|
||||
183 begin
|
||||
184 end
|
||||
185 internal
|
||||
186 singleton
|
||||
187 begin
|
||||
188 end
|
||||
189 internal
|
||||
190 singleton
|
||||
191 begin
|
||||
192 end
|
||||
193 internal
|
||||
194 singleton
|
||||
195 begin
|
||||
196 end
|
||||
197 internal
|
||||
198 singleton
|
||||
199 begin
|
||||
200 end
|
||||
201 internal
|
||||
202 singleton
|
||||
203 begin
|
||||
204 end
|
||||
205 internal
|
||||
206 singleton
|
||||
207 begin
|
||||
208 end
|
||||
209 internal
|
||||
210 singleton
|
||||
211 begin
|
||||
212 end
|
||||
213 internal
|
||||
214 singleton
|
||||
215 begin
|
||||
216 end
|
||||
217 internal
|
||||
218 singleton
|
||||
219 begin
|
||||
220 end
|
||||
221 internal
|
||||
222 singleton
|
||||
223 begin
|
||||
224 end
|
||||
225 internal
|
||||
226 singleton
|
||||
227 begin
|
||||
228 end
|
||||
229 internal
|
||||
230 singleton
|
||||
231 begin
|
||||
232 end
|
||||
233 internal
|
||||
234 singleton
|
||||
235 begin
|
||||
236 end
|
||||
237 internal
|
||||
238 singleton
|
||||
239 begin
|
||||
240 end
|
||||
241 internal
|
||||
242 singleton
|
||||
243 begin
|
||||
244 end
|
||||
245 internal
|
||||
246 singleton
|
||||
247 begin
|
||||
248 end
|
||||
249 internal
|
||||
250 singleton
|
||||
251 begin
|
||||
252 end
|
||||
253 internal
|
||||
254 singleton
|
||||
255 begin
|
||||
256 end
|
||||
257 internal
|
||||
258 singleton
|
||||
259 begin
|
||||
260 end
|
||||
261 internal
|
||||
262 singleton
|
||||
263 begin
|
||||
264 end
|
||||
265 internal
|
||||
266 singleton
|
||||
267 begin
|
||||
268 end
|
||||
269 internal
|
||||
270 singleton
|
||||
271 begin
|
||||
272 end
|
||||
273 internal
|
||||
274 singleton
|
||||
275 begin
|
||||
276 end
|
||||
277 internal
|
||||
278 singleton
|
||||
279 begin
|
||||
280 end
|
||||
281 internal
|
||||
282 singleton
|
||||
283 begin
|
||||
284 end
|
||||
285 internal
|
||||
286 singleton
|
||||
287 begin
|
||||
288 end
|
||||
289 internal
|
||||
290 singleton
|
||||
291 begin
|
||||
292 end
|
||||
293 internal
|
||||
294 singleton
|
||||
295 begin
|
||||
296 end
|
||||
297 internal
|
||||
298 singleton
|
||||
299 begin
|
||||
300 end
|
||||
301 internal
|
||||
302 singleton
|
||||
303 begin
|
||||
304 end
|
||||
305 internal
|
||||
306 singleton
|
||||
307 begin
|
||||
308 end
|
||||
309 internal
|
||||
310 singleton
|
||||
311 begin
|
||||
312 end
|
||||
313 internal
|
||||
314 singleton
|
||||
315 begin
|
||||
316 end
|
||||
317 internal
|
||||
318 singleton
|
||||
319 begin
|
||||
320 end
|
||||
321 internal
|
||||
322 singleton
|
||||
323 begin
|
||||
324 end
|
||||
325 internal
|
||||
326 singleton
|
||||
327 begin
|
||||
328 end
|
||||
329 internal
|
||||
330 singleton
|
||||
331 begin
|
||||
332 end
|
||||
333 internal
|
||||
334 singleton
|
||||
335 begin
|
||||
336 end
|
||||
337 internal
|
||||
338 singleton
|
||||
339 begin
|
||||
340 end
|
||||
341 internal
|
||||
342 singleton
|
||||
343 begin
|
||||
344 end
|
||||
345 internal
|
||||
346 singleton
|
||||
347 begin
|
||||
348 end
|
||||
349 internal
|
||||
350 singleton
|
||||
351 begin
|
||||
352 end
|
||||
353 internal
|
||||
354 singleton
|
||||
355 begin
|
||||
356 end
|
||||
357 internal
|
||||
358 singleton
|
||||
359 begin
|
||||
360 end
|
||||
361 internal
|
||||
362 singleton
|
||||
363 begin
|
||||
364 end
|
||||
365 internal
|
||||
366 singleton
|
||||
367 begin
|
||||
368 end
|
||||
369 internal
|
||||
370 singleton
|
||||
371 begin
|
||||
372 end
|
||||
373 internal
|
||||
374 singleton
|
||||
375 begin
|
||||
376 end
|
||||
377 internal
|
||||
378 singleton
|
||||
379 begin
|
||||
380 end
|
||||
381 internal
|
||||
382 singleton
|
||||
383 begin
|
||||
384 end
|
||||
385 internal
|
||||
386 singleton
|
||||
213300
resources/vosk/vosk-model-small-uk-v3-nano/graph/words.txt
Normal file
213300
resources/vosk/vosk-model-small-uk-v3-nano/graph/words.txt
Normal file
File diff suppressed because it is too large
Load diff
BIN
resources/vosk/vosk-model-small-uk-v3-nano/ivector/final.dubm
Normal file
BIN
resources/vosk/vosk-model-small-uk-v3-nano/ivector/final.dubm
Normal file
Binary file not shown.
BIN
resources/vosk/vosk-model-small-uk-v3-nano/ivector/final.ie
Normal file
BIN
resources/vosk/vosk-model-small-uk-v3-nano/ivector/final.ie
Normal file
Binary file not shown.
BIN
resources/vosk/vosk-model-small-uk-v3-nano/ivector/final.mat
Normal file
BIN
resources/vosk/vosk-model-small-uk-v3-nano/ivector/final.mat
Normal file
Binary file not shown.
|
|
@ -0,0 +1,3 @@
|
|||
[
|
||||
4.5109e+10 -2.00471e+09 -2.672177e+09 1.114113e+09 -8.008282e+09 -5.54918e+09 -8.087527e+09 -5.556585e+09 -6.347063e+09 -3.373851e+09 -3.843346e+09 -2.503764e+09 -4.038778e+09 -1.628978e+09 -3.658344e+09 -1.833892e+09 -2.750521e+09 -8.853997e+08 -1.515349e+09 -3.647572e+08 -6.377884e+08 -3.654417e+07 -9.805578e+07 -1849224 1.814711e+08 3.480522e+07 3.80909e+08 -4.716804e+07 3.213146e+08 -1.504913e+08 2.643303e+08 -3.810504e+07 3.958002e+08 1.283459e+08 4.22026e+08 1.628813e+08 2.36883e+08 -1.055832e+08 -1.122014e+08 -1.099238e+08 4.526635e+08
|
||||
4.711843e+12 2.762046e+11 2.171106e+11 2.422162e+11 4.382205e+11 3.213519e+11 3.843864e+11 3.195329e+11 3.268667e+11 2.552171e+11 2.418821e+11 2.378349e+11 2.052809e+11 1.633811e+11 1.478665e+11 1.004429e+11 8.785726e+10 5.500246e+10 4.097437e+10 2.183258e+10 1.194666e+10 3.761198e+09 5.177095e+08 1.362906e+08 1.739844e+09 4.326937e+09 7.570374e+09 9.9598e+09 1.258423e+10 1.362375e+10 1.458388e+10 1.413189e+10 1.478221e+10 1.534696e+10 1.329504e+10 1.025456e+10 9.890456e+09 7.986768e+09 6.064231e+09 3.940631e+09 0 ]
|
||||
|
|
@ -0,0 +1 @@
|
|||
# configuration file for apply-cmvn-online, used in the script ../local/run_online_decoding.sh
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
--left-context=3
|
||||
--right-context=3
|
||||
|
|
@ -0,0 +1 @@
|
|||
--left-context=3 --right-context=3
|
||||
Loading…
Add table
Add a link
Reference in a new issue