App icon, logs are now stored to log.txt file, work in progress on intergration with rustpotter
|
|
@ -2,7 +2,7 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/media/app-icon.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Tauri + Svelte + TS</title>
|
<title>Tauri + Svelte + TS</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "jarvis-app",
|
"name": "jarvis-app",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "routify -c dev:vite",
|
"dev": "routify -c dev:vite",
|
||||||
|
|
|
||||||
BIN
public/media/app-icon.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 30 KiB |
1
src-tauri/.gitignore
vendored
|
|
@ -2,3 +2,4 @@
|
||||||
# will have compiled files and executables
|
# will have compiled files and executables
|
||||||
/target/
|
/target/
|
||||||
app.db
|
app.db
|
||||||
|
log.txt
|
||||||
148
src-tauri/Cargo.lock
generated
|
|
@ -312,6 +312,33 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"ciborium-ll",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-io"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ciborium-ll"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium-io",
|
||||||
|
"half",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
|
|
@ -1145,6 +1172,12 @@ dependencies = [
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "1.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
|
|
@ -1332,16 +1365,20 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hound",
|
"hound",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
"peak_alloc",
|
"peak_alloc",
|
||||||
"pickledb",
|
"pickledb",
|
||||||
"pv_porcupine",
|
"pv_porcupine",
|
||||||
"pv_recorder",
|
"pv_recorder",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rodio",
|
"rodio",
|
||||||
|
"rustpotter",
|
||||||
"seqdiff",
|
"seqdiff",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
"simple-logging",
|
||||||
"systemstat",
|
"systemstat",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
|
|
@ -1721,6 +1758,15 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-derive"
|
name = "num-derive"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
|
@ -2129,6 +2175,15 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "primal-check"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9df7f93fd637f083201473dab4fee2db4c429d32e55e3299980ab3957ab916a0"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
|
@ -2303,6 +2358,21 @@ version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
|
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "realfft"
|
||||||
|
version = "3.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93d6b8e8f0c6d2234aa58048d7290c60bf92cd36fd2888cd8331c66ad4f2e1d2"
|
||||||
|
dependencies = [
|
||||||
|
"rustfft",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.1.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
|
@ -2401,6 +2471,18 @@ dependencies = [
|
||||||
"symphonia",
|
"symphonia",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rubato"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd70209c27d5b08f5528bdc779ea3ffb418954e28987f9f9775c6eac41003f9c"
|
||||||
|
dependencies = [
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"realfft",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -2416,6 +2498,21 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustfft"
|
||||||
|
version = "6.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e17d4f6cbdb180c9f4b2a26bbf01c4e647f1e1dea22fe8eb9db54198b32f9434"
|
||||||
|
dependencies = [
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"primal-check",
|
||||||
|
"strength_reduce",
|
||||||
|
"transpose",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.37.13"
|
version = "0.37.13"
|
||||||
|
|
@ -2430,6 +2527,19 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustpotter"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6a88d0514dd5dcc988c78f61be4f60fdb37d4872e23c7d8d6d2d3ea23655f97"
|
||||||
|
dependencies = [
|
||||||
|
"ciborium",
|
||||||
|
"hound",
|
||||||
|
"rubato",
|
||||||
|
"rustfft",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
|
|
@ -2654,6 +2764,17 @@ version = "0.3.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f"
|
checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simple-logging"
|
||||||
|
version = "2.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b00d48e85675326bb182a2286ea7c1a0b264333ae10f27a937a72be08628b542"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"thread-id",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.10"
|
version = "0.3.10"
|
||||||
|
|
@ -2718,6 +2839,12 @@ dependencies = [
|
||||||
"loom",
|
"loom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strength_reduce"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "string_cache"
|
name = "string_cache"
|
||||||
version = "0.8.7"
|
version = "0.8.7"
|
||||||
|
|
@ -3147,6 +3274,17 @@ dependencies = [
|
||||||
"syn 2.0.15",
|
"syn 2.0.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread-id"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"redox_syscall 0.1.57",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.1.7"
|
version = "1.1.7"
|
||||||
|
|
@ -3317,6 +3455,16 @@ dependencies = [
|
||||||
"tracing-log",
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "transpose"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6522d49d03727ffb138ae4cbc1283d3774f0d10aa7f9bf52e6784c45daf9b23"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"strength_reduce",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "treediff"
|
name = "treediff"
|
||||||
version = "3.0.2"
|
version = "3.0.2"
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,15 @@ systemstat = "0.2.3"
|
||||||
hound = "3.5.0"
|
hound = "3.5.0"
|
||||||
pv_recorder = "1.1.1"
|
pv_recorder = "1.1.1"
|
||||||
pv_porcupine = "2.2.0"
|
pv_porcupine = "2.2.0"
|
||||||
rodio = "0.17.1"
|
|
||||||
serde_yaml = "0.9.21"
|
serde_yaml = "0.9.21"
|
||||||
seqdiff = "0.3.0"
|
seqdiff = "0.3.0"
|
||||||
vosk = "0.2.0"
|
vosk = "0.2.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
rodio = "0.17.1"
|
||||||
|
rustpotter = "2.0.0"
|
||||||
|
simple-logging = "2.0.2"
|
||||||
|
log = "0.4.17"
|
||||||
|
once_cell = "1.17.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# this feature is used for production builds or when `devPath` points to the filesystem
|
# this feature is used for production builds or when `devPath` points to the filesystem
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
// link to Vosk lib
|
// link to Vosk lib
|
||||||
println!("cargo:rustc-link-search=vosk/");
|
println!("cargo:rustc-link-lib=libvosk.dll");
|
||||||
|
|
||||||
// println!("cargo:rustc-link-lib=dylib=D:/Rust/vosk/libvosk.dll");
|
|
||||||
|
|
||||||
// Tauri build
|
// Tauri build
|
||||||
tauri_build::build()
|
tauri_build::build()
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 974 B After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 105 KiB |
|
|
@ -8,7 +8,7 @@ use core::time::Duration;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Child;
|
use std::process::Child;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use tauri::Manager;
|
// use tauri::Manager;
|
||||||
|
|
||||||
mod structs;
|
mod structs;
|
||||||
pub use structs::*;
|
pub use structs::*;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
use const_concat::const_concat;
|
// use const_concat::const_concat;
|
||||||
use std::env::current_dir;
|
|
||||||
|
|
||||||
// pub const IS_DEV: bool = cfg!(debug_assertions);// cfg!(debug_assertions);
|
// pub const IS_DEV: bool = cfg!(debug_assertions);// cfg!(debug_assertions);
|
||||||
// pub const PUBLIC_PATH: &str = if IS_DEV {
|
// pub const PUBLIC_PATH: &str = if IS_DEV {
|
||||||
|
|
@ -8,14 +7,17 @@ use std::env::current_dir;
|
||||||
// "./public"
|
// "./public"
|
||||||
// };
|
// };
|
||||||
|
|
||||||
pub const COMMANDS_PATH: &str = "commands/";
|
pub const WAKE_WORD_ENGINES: [&str; 2] = ["rustpotter", "picovoice"];
|
||||||
pub const KEYWORDS_PATH: &str = "picovoice/keywords/";
|
|
||||||
|
|
||||||
pub const DB_FILE_NAME: &str = "app.db";
|
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 APP_VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");
|
||||||
pub const AUTHOR_NAME: Option<&str> = option_env!("CARGO_PKG_AUTHORS");
|
pub const AUTHOR_NAME: Option<&str> = option_env!("CARGO_PKG_AUTHORS");
|
||||||
pub const REPOSITORY_LINK: Option<&str> = option_env!("CARGO_PKG_REPOSITORY");
|
pub const REPOSITORY_LINK: Option<&str> = option_env!("CARGO_PKG_REPOSITORY");
|
||||||
|
|
||||||
|
pub const COMMANDS_PATH: &str = "commands/";
|
||||||
|
pub const KEYWORDS_PATH: &str = "picovoice/keywords/";
|
||||||
|
|
||||||
// pub const VOSK_MODEL_PATH: &str = const_concat!(PUBLIC_PATH, "/vosk/model_small");
|
// pub const VOSK_MODEL_PATH: &str = const_concat!(PUBLIC_PATH, "/vosk/model_small");
|
||||||
pub const VOSK_MODEL_PATH: &str = "vosk/model_small";
|
pub const VOSK_MODEL_PATH: &str = "vosk/model_small";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ pub struct Payload {
|
||||||
pub data: String,
|
pub data: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub enum EventTypes {
|
pub enum EventTypes {
|
||||||
AudioPlay,
|
AudioPlay,
|
||||||
AssistantWaiting,
|
AssistantWaiting,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static; // better switch to once_cell ?
|
extern crate lazy_static; // better switch to once_cell ?
|
||||||
use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod};
|
use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod};
|
||||||
|
use log::{info};
|
||||||
|
use log::LevelFilter;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
// expose the config
|
// expose the config
|
||||||
|
|
@ -23,6 +25,9 @@ mod vosk;
|
||||||
// include events
|
// include events
|
||||||
mod events;
|
mod events;
|
||||||
|
|
||||||
|
// include recorder
|
||||||
|
mod recorder;
|
||||||
|
|
||||||
// app dir
|
// app dir
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref APP_CONFIG_DIR: Mutex<String> = Mutex::new(String::new());
|
static ref APP_CONFIG_DIR: Mutex<String> = Mutex::new(String::new());
|
||||||
|
|
@ -37,7 +42,7 @@ lazy_static! {
|
||||||
SerializationMethod::Json
|
SerializationMethod::Json
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|_x: _| {
|
.unwrap_or_else(|_x: _| {
|
||||||
println!("Creating new db file at {} ...", format!("{}/{}", APP_CONFIG_DIR.lock().unwrap(), DB_FILE_NAME));
|
info!("Creating new db file at {} ...", format!("{}/{}", APP_CONFIG_DIR.lock().unwrap(), DB_FILE_NAME));
|
||||||
PickleDb::new(
|
PickleDb::new(
|
||||||
format!("{}/{}", APP_CONFIG_DIR.lock().unwrap(), DB_FILE_NAME),
|
format!("{}/{}", APP_CONFIG_DIR.lock().unwrap(), DB_FILE_NAME),
|
||||||
PickleDbDumpPolicy::AutoDump,
|
PickleDbDumpPolicy::AutoDump,
|
||||||
|
|
@ -53,8 +58,13 @@ lazy_static! {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
// log to file
|
||||||
|
simple_logging::log_to_file(config::LOG_FILE_NAME, LevelFilter::max()).expect("Failed to start logger ... is directory writable?");
|
||||||
|
|
||||||
|
// init vosk
|
||||||
vosk::init_vosk();
|
vosk::init_vosk();
|
||||||
|
|
||||||
|
// run the app
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
std::fs::create_dir_all(app.path_resolver().app_config_dir().unwrap())?;
|
std::fs::create_dir_all(app.path_resolver().app_config_dir().unwrap())?;
|
||||||
|
|
|
||||||
63
src-tauri/src/recorder.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use std::sync::atomic::{AtomicU32, AtomicBool, Ordering};
|
||||||
|
use pv_recorder::{Recorder, RecorderBuilder};
|
||||||
|
use log::{info};
|
||||||
|
|
||||||
|
use crate::DB;
|
||||||
|
|
||||||
|
pub static FRAME_LENGTH: AtomicU32 = AtomicU32::new(0);
|
||||||
|
static RECORDER: OnceCell<Recorder> = OnceCell::new();
|
||||||
|
pub static IS_RECORDING: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
fn init_microphone() {
|
||||||
|
if RECORDER.get().is_none() {
|
||||||
|
RECORDER.get_or_init(|| RecorderBuilder::new()
|
||||||
|
.device_index(get_selected_microphone_index())
|
||||||
|
.frame_length(FRAME_LENGTH.load(Ordering::SeqCst) as i32)
|
||||||
|
.init()
|
||||||
|
.expect("Failed to initialize pvrecorder"));
|
||||||
|
|
||||||
|
info!("Microphone recorder initialized!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_microphone(frame_buffer: &mut [i16]) {
|
||||||
|
// ensure microphone is initialized
|
||||||
|
init_microphone();
|
||||||
|
|
||||||
|
// read to frame buffer
|
||||||
|
RECORDER.get().unwrap().read(frame_buffer).expect("Failed to read audio frame");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_recording() {
|
||||||
|
// ensure microphone is initialized
|
||||||
|
init_microphone();
|
||||||
|
|
||||||
|
RECORDER.get().unwrap().start().expect("Failed to start audio recording!");
|
||||||
|
IS_RECORDING.store(true, Ordering::SeqCst);
|
||||||
|
info!("START recording from microphone ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop_recording() {
|
||||||
|
// ensure microphone is initialized
|
||||||
|
init_microphone();
|
||||||
|
|
||||||
|
RECORDER.get().unwrap().start().expect("Failed to start audio recording!");
|
||||||
|
IS_RECORDING.store(false, Ordering::SeqCst);
|
||||||
|
info!("STOP recording from microphone ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_selected_microphone_index() -> i32 {
|
||||||
|
let selected_microphone: i32;
|
||||||
|
|
||||||
|
// Retrieve microphone index
|
||||||
|
if let Some(smic) = DB.lock().unwrap().get::<String>("selected_microphone") {
|
||||||
|
selected_microphone = smic.parse().unwrap_or(-1);
|
||||||
|
} else {
|
||||||
|
selected_microphone = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return microphone index
|
||||||
|
info!("Selected microphone index = {selected_microphone}");
|
||||||
|
selected_microphone
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use porcupine::{BuiltinKeywords, Porcupine, PorcupineBuilder};
|
use porcupine::{Porcupine, PorcupineBuilder};
|
||||||
use pv_recorder::RecorderBuilder;
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use log::{info, warn, error};
|
||||||
|
|
||||||
use crate::events::Payload;
|
// use crate::events::Payload;
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
|
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
|
|
@ -14,6 +14,7 @@ use crate::events;
|
||||||
|
|
||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::vosk;
|
use crate::vosk;
|
||||||
|
use crate::recorder;
|
||||||
|
|
||||||
use crate::COMMANDS;
|
use crate::COMMANDS;
|
||||||
use crate::DB;
|
use crate::DB;
|
||||||
|
|
@ -46,91 +47,57 @@ pub fn start_listening(app_handle: tauri::AppHandle) -> Result<bool, String> {
|
||||||
return Err("Already listening.".into());
|
return Err("Already listening.".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// vars
|
// Retrieve selected wake-word engine from DB
|
||||||
let porcupine: Porcupine;
|
let selected_wake_word_engine;
|
||||||
let mut picovoice_api_key: String = String::from("");
|
if let Some(wwengine) = DB.lock().unwrap().get::<String>("selected_wake_word_engine") {
|
||||||
let selected_microphone: i32;
|
// from db
|
||||||
|
selected_wake_word_engine = wwengine;
|
||||||
let mut start = SystemTime::now();
|
|
||||||
|
|
||||||
// Retrieve API key from DB
|
|
||||||
if let Some(pkey) = DB.lock().unwrap().get::<String>("api_key__picovoice") {
|
|
||||||
if !pkey.is_empty() {
|
|
||||||
picovoice_api_key = pkey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if picovoice_api_key.is_empty() {
|
|
||||||
return Err("Picovoice API key is not set!".into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create instance of Porcupine with the given API key
|
|
||||||
match PorcupineBuilder::new_with_keyword_paths(picovoice_api_key, &[Path::new(config::KEYWORDS_PATH).join("jarvis_windows.ppn")])
|
|
||||||
.sensitivities(&[1.0f32]) // max sensitivity possible
|
|
||||||
.init() {
|
|
||||||
Ok(pinstance) => {
|
|
||||||
// porcupine successfully initialized with the valid API key
|
|
||||||
println!("Porcupine successfully initialized with the valid API key ...");
|
|
||||||
porcupine = pinstance;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
println!("Porcupine error: either API key is not valid or there is no internet connection");
|
|
||||||
println!("Error details: {}", e);
|
|
||||||
return Err(
|
|
||||||
"Porcupine error: either API key is not valid or there is no internet connection"
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve microphone index
|
|
||||||
if let Some(smic) = DB.lock().unwrap().get::<String>("selected_microphone") {
|
|
||||||
selected_microphone = smic.parse().unwrap_or(-1);
|
|
||||||
} else {
|
} else {
|
||||||
selected_microphone = -1; // use default, if not selected
|
// default
|
||||||
|
selected_wake_word_engine = config::WAKE_WORD_ENGINES.first().expect("No wake-word engines found ...").to_string(); // set default wake_word engine
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create recorder instance
|
// call selected wake-word engine listener command
|
||||||
let recorder = RecorderBuilder::new()
|
match selected_wake_word_engine.as_str() {
|
||||||
.device_index(selected_microphone)
|
"rustpotter" => {
|
||||||
.frame_length(porcupine.frame_length() as i32)
|
info!("Starting rustpotter wake-word engine ...");
|
||||||
.init()
|
return picovoice_listen(&app_handle, |_app| {
|
||||||
.expect("Failed to initialize pvrecorder");
|
|
||||||
|
|
||||||
// Start recording
|
|
||||||
println!("Listening (microphone idx = {selected_microphone}) ...");
|
|
||||||
recorder.start().expect("Failed to start audio recording");
|
|
||||||
LISTENING.store(true, Ordering::SeqCst);
|
|
||||||
|
|
||||||
// Greet user
|
// Greet user
|
||||||
events::play("run", &app_handle);
|
events::play("run", &app_handle);
|
||||||
|
}, |app, kidx| keyword_callback(app, kidx));
|
||||||
|
},
|
||||||
|
"picovoice" => {
|
||||||
|
info!("Starting picovoice wake-word engine ...");
|
||||||
|
return picovoice_listen(&app_handle, |_app| {
|
||||||
|
// Greet user
|
||||||
|
events::play("run", &app_handle);
|
||||||
|
}, |app, kidx| keyword_callback(app, kidx));
|
||||||
|
},
|
||||||
|
_ => Err("No wake-word engine selected ...".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Listen until stop flag will be true
|
pub fn keyword_callback(app_handle: &tauri::AppHandle, _keyword_index: i32) {
|
||||||
let mut frame_buffer = vec![0; porcupine.frame_length() as usize];
|
// vars
|
||||||
while !STOP_LISTENING.load(Ordering::SeqCst) {
|
let mut start: SystemTime = SystemTime::now();
|
||||||
recorder
|
let mut frame_buffer = vec![0; recorder::FRAME_LENGTH.load(Ordering::SeqCst) as usize];
|
||||||
.read(&mut frame_buffer)
|
|
||||||
.expect("Failed to read audio frame");
|
|
||||||
|
|
||||||
if let Ok(keyword_index) = porcupine.process(&frame_buffer) {
|
// play greet phrase
|
||||||
if keyword_index >= 0 {
|
|
||||||
println!("Yes, sir! {}", keyword_index);
|
|
||||||
events::play(
|
events::play(
|
||||||
config::ASSISTANT_GREET_PHRASES
|
config::ASSISTANT_GREET_PHRASES
|
||||||
.choose(&mut rand::thread_rng())
|
.choose(&mut rand::thread_rng())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
&app_handle,
|
&app_handle,
|
||||||
);
|
);
|
||||||
start = SystemTime::now();
|
|
||||||
|
|
||||||
|
// emit assistant greet event
|
||||||
app_handle
|
app_handle
|
||||||
.emit_all(events::EventTypes::AssistantGreet.get(), ())
|
.emit_all(events::EventTypes::AssistantGreet.get(), ())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
loop {
|
// the loop
|
||||||
recorder
|
while !STOP_LISTENING.load(Ordering::SeqCst) {
|
||||||
.read(&mut frame_buffer)
|
recorder::read_microphone(&mut frame_buffer);
|
||||||
.expect("Failed to read audio frame");
|
|
||||||
|
|
||||||
// vosk part (partials included)
|
// vosk part (partials included)
|
||||||
if let Some(mut test) = vosk::recognize(&frame_buffer) {
|
if let Some(mut test) = vosk::recognize(&frame_buffer) {
|
||||||
|
|
@ -187,13 +154,66 @@ pub fn start_listening(app_handle: tauri::AppHandle) -> Result<bool, String> {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn picovoice_listen<'s, S, K>(app_handle: &tauri::AppHandle, start_callback: S, mut keyword_callback: K) -> Result<bool, String>
|
||||||
|
where S: Fn(&tauri::AppHandle),
|
||||||
|
K: FnMut(&tauri::AppHandle, i32) {
|
||||||
|
|
||||||
|
// VARS
|
||||||
|
let porcupine: Porcupine;
|
||||||
|
let picovoice_api_key: String;
|
||||||
|
|
||||||
|
// Retrieve API key from DB
|
||||||
|
if let Some(pkey) = DB.lock().unwrap().get::<String>("api_key__picovoice") {
|
||||||
|
picovoice_api_key = pkey;
|
||||||
|
} else {
|
||||||
|
warn!("Picovoice API key is not set!");
|
||||||
|
return Err("Picovoice API key is not set!".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create instance of Porcupine with the given API key
|
||||||
|
match PorcupineBuilder::new_with_keyword_paths(picovoice_api_key, &[Path::new(config::KEYWORDS_PATH).join("jarvis_windows.ppn")])
|
||||||
|
.sensitivities(&[1.0f32]) // max sensitivity possible
|
||||||
|
.init() {
|
||||||
|
Ok(pinstance) => {
|
||||||
|
// porcupine successfully initialized with the valid API key
|
||||||
|
info!("Porcupine successfully initialized with the valid API key ...");
|
||||||
|
porcupine = pinstance;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Porcupine error: either API key is not valid or there is no internet connection");
|
||||||
|
error!("Error details: {}", e);
|
||||||
|
return Err(
|
||||||
|
"Porcupine error: either API key is not valid or there is no internet connection"
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start recording
|
||||||
|
let mut frame_buffer = vec![0; porcupine.frame_length() as usize];
|
||||||
|
recorder::FRAME_LENGTH.store(porcupine.frame_length(), Ordering::SeqCst);
|
||||||
|
recorder::start_recording();
|
||||||
|
LISTENING.store(true, Ordering::SeqCst);
|
||||||
|
|
||||||
|
// run start callback
|
||||||
|
start_callback(app_handle);
|
||||||
|
|
||||||
|
// Listen until stop flag will be true
|
||||||
|
while !STOP_LISTENING.load(Ordering::SeqCst) {
|
||||||
|
recorder::read_microphone(&mut frame_buffer);
|
||||||
|
|
||||||
|
if let Ok(keyword_index) = porcupine.process(&frame_buffer) {
|
||||||
|
if keyword_index >= 0 {
|
||||||
|
// println!("Yes, sir! {}", keyword_index);
|
||||||
|
keyword_callback(&app_handle, keyword_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop listening
|
// Stop listening
|
||||||
println!("Stop listening ...");
|
recorder::stop_recording();
|
||||||
recorder.stop().expect("Failed to stop audio recording");
|
|
||||||
LISTENING.store(false, Ordering::SeqCst);
|
LISTENING.store(false, Ordering::SeqCst);
|
||||||
STOP_LISTENING.store(false, Ordering::SeqCst);
|
STOP_LISTENING.store(false, Ordering::SeqCst);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ static PEAK_ALLOC: PeakAlloc = PeakAlloc;
|
||||||
extern crate systemstat;
|
extern crate systemstat;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use systemstat::{saturating_sub_bytes, Platform, System};
|
use systemstat::{Platform, System};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref SYS: System = System::new();
|
static ref SYS: System = System::new();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use vosk::{CompleteResult, DecodingState, Model, Recognizer};
|
use vosk::{DecodingState, Model, Recognizer};
|
||||||
|
|
||||||
use crate::config::VOSK_MODEL_PATH;
|
use crate::config::VOSK_MODEL_PATH;
|
||||||
|
|
||||||
|
|
@ -46,13 +46,13 @@ pub fn recognize(data: &[i16]) -> Option<String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stereo_to_mono(input_data: &[i16]) -> Vec<i16> {
|
// pub fn stereo_to_mono(input_data: &[i16]) -> Vec<i16> {
|
||||||
let mut result = Vec::with_capacity(input_data.len() / 2);
|
// let mut result = Vec::with_capacity(input_data.len() / 2);
|
||||||
result.extend(
|
// result.extend(
|
||||||
input_data
|
// input_data
|
||||||
.chunks_exact(2)
|
// .chunks_exact(2)
|
||||||
.map(|chunk| chunk[0] / 2 + chunk[1] / 2),
|
// .map(|chunk| chunk[0] / 2 + chunk[1] / 2),
|
||||||
);
|
// );
|
||||||
|
|
||||||
result
|
// result
|
||||||
}
|
// }
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "jarvis-app",
|
"productName": "jarvis-app",
|
||||||
"version": "0.0.0"
|
"version": "0.0.1"
|
||||||
},
|
},
|
||||||
"tauri": {
|
"tauri": {
|
||||||
"allowlist": {
|
"allowlist": {
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
"libstdc++-6.dll",
|
"libstdc++-6.dll",
|
||||||
"libwinpthread-1.dll",
|
"libwinpthread-1.dll",
|
||||||
"libgcc_s_seh-1.dll",
|
"libgcc_s_seh-1.dll",
|
||||||
"libpv_recorder.dll"
|
"libvosk.lib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
|
|
|
||||||
|
|
@ -1,361 +0,0 @@
|
||||||
// Copyright 2020-2021 Alpha Cephei Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
/* This header contains the C API for Vosk speech recognition system */
|
|
||||||
|
|
||||||
#ifndef VOSK_API_H
|
|
||||||
#define VOSK_API_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Model stores all the data required for recognition
|
|
||||||
* it contains static data and can be shared across processing
|
|
||||||
* threads. */
|
|
||||||
typedef struct VoskModel VoskModel;
|
|
||||||
|
|
||||||
|
|
||||||
/** Speaker model is the same as model but contains the data
|
|
||||||
* for speaker identification. */
|
|
||||||
typedef struct VoskSpkModel VoskSpkModel;
|
|
||||||
|
|
||||||
|
|
||||||
/** Recognizer object is the main object which processes data.
|
|
||||||
* Each recognizer usually runs in own thread and takes audio as input.
|
|
||||||
* Once audio is processed recognizer returns JSON object as a string
|
|
||||||
* which represent decoded information - words, confidences, times, n-best lists,
|
|
||||||
* speaker information and so on */
|
|
||||||
typedef struct VoskRecognizer VoskRecognizer;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Batch model object
|
|
||||||
*/
|
|
||||||
typedef struct VoskBatchModel VoskBatchModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Batch recognizer object
|
|
||||||
*/
|
|
||||||
typedef struct VoskBatchRecognizer VoskBatchRecognizer;
|
|
||||||
|
|
||||||
|
|
||||||
/** Loads model data from the file and returns the model object
|
|
||||||
*
|
|
||||||
* @param model_path: the path of the model on the filesystem
|
|
||||||
* @returns model object or NULL if problem occured */
|
|
||||||
VoskModel *vosk_model_new(const char *model_path);
|
|
||||||
|
|
||||||
|
|
||||||
/** Releases the model memory
|
|
||||||
*
|
|
||||||
* The model object is reference-counted so if some recognizer
|
|
||||||
* depends on this model, model might still stay alive. When
|
|
||||||
* last recognizer is released, model will be released too. */
|
|
||||||
void vosk_model_free(VoskModel *model);
|
|
||||||
|
|
||||||
|
|
||||||
/** Check if a word can be recognized by the model
|
|
||||||
* @param word: the word
|
|
||||||
* @returns the word symbol if @param word exists inside the model
|
|
||||||
* or -1 otherwise.
|
|
||||||
* Reminding that word symbol 0 is for <epsilon> */
|
|
||||||
int vosk_model_find_word(VoskModel *model, const char *word);
|
|
||||||
|
|
||||||
|
|
||||||
/** Loads speaker model data from the file and returns the model object
|
|
||||||
*
|
|
||||||
* @param model_path: the path of the model on the filesystem
|
|
||||||
* @returns model object or NULL if problem occured */
|
|
||||||
VoskSpkModel *vosk_spk_model_new(const char *model_path);
|
|
||||||
|
|
||||||
|
|
||||||
/** Releases the model memory
|
|
||||||
*
|
|
||||||
* The model object is reference-counted so if some recognizer
|
|
||||||
* depends on this model, model might still stay alive. When
|
|
||||||
* last recognizer is released, model will be released too. */
|
|
||||||
void vosk_spk_model_free(VoskSpkModel *model);
|
|
||||||
|
|
||||||
/** Creates the recognizer object
|
|
||||||
*
|
|
||||||
* The recognizers process the speech and return text using shared model data
|
|
||||||
* @param model VoskModel containing static data for recognizer. Model can be
|
|
||||||
* shared across recognizers, even running in different threads.
|
|
||||||
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
|
|
||||||
* Make sure this rate matches the audio content, it is a common
|
|
||||||
* issue causing accuracy problems.
|
|
||||||
* @returns recognizer object or NULL if problem occured */
|
|
||||||
VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate);
|
|
||||||
|
|
||||||
|
|
||||||
/** Creates the recognizer object with speaker recognition
|
|
||||||
*
|
|
||||||
* With the speaker recognition mode the recognizer not just recognize
|
|
||||||
* text but also return speaker vectors one can use for speaker identification
|
|
||||||
*
|
|
||||||
* @param model VoskModel containing static data for recognizer. Model can be
|
|
||||||
* shared across recognizers, even running in different threads.
|
|
||||||
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
|
|
||||||
* Make sure this rate matches the audio content, it is a common
|
|
||||||
* issue causing accuracy problems.
|
|
||||||
* @param spk_model speaker model for speaker identification
|
|
||||||
* @returns recognizer object or NULL if problem occured */
|
|
||||||
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, float sample_rate, VoskSpkModel *spk_model);
|
|
||||||
|
|
||||||
|
|
||||||
/** Creates the recognizer object with the phrase list
|
|
||||||
*
|
|
||||||
* Sometimes when you want to improve recognition accuracy and when you don't need
|
|
||||||
* to recognize large vocabulary you can specify a list of phrases to recognize. This
|
|
||||||
* will improve recognizer speed and accuracy but might return [unk] if user said
|
|
||||||
* something different.
|
|
||||||
*
|
|
||||||
* Only recognizers with lookahead models support this type of quick configuration.
|
|
||||||
* Precompiled HCLG graph models are not supported.
|
|
||||||
*
|
|
||||||
* @param model VoskModel containing static data for recognizer. Model can be
|
|
||||||
* shared across recognizers, even running in different threads.
|
|
||||||
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
|
|
||||||
* Make sure this rate matches the audio content, it is a common
|
|
||||||
* issue causing accuracy problems.
|
|
||||||
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
|
|
||||||
* for example "["one two three four five", "[unk]"]".
|
|
||||||
*
|
|
||||||
* @returns recognizer object or NULL if problem occured */
|
|
||||||
VoskRecognizer *vosk_recognizer_new_grm(VoskModel *model, float sample_rate, const char *grammar);
|
|
||||||
|
|
||||||
|
|
||||||
/** Adds speaker model to already initialized recognizer
|
|
||||||
*
|
|
||||||
* Can add speaker recognition model to already created recognizer. Helps to initialize
|
|
||||||
* speaker recognition for grammar-based recognizer.
|
|
||||||
*
|
|
||||||
* @param spk_model Speaker recognition model */
|
|
||||||
void vosk_recognizer_set_spk_model(VoskRecognizer *recognizer, VoskSpkModel *spk_model);
|
|
||||||
|
|
||||||
|
|
||||||
/** Reconfigures recognizer to use grammar
|
|
||||||
*
|
|
||||||
* @param recognizer Already running VoskRecognizer
|
|
||||||
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
|
|
||||||
* See also vosk_recognizer_new_grm
|
|
||||||
*/
|
|
||||||
void vosk_recognizer_set_grm(VoskRecognizer *recognizer, char const *grammar);
|
|
||||||
|
|
||||||
|
|
||||||
/** Configures recognizer to output n-best results
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {
|
|
||||||
* "alternatives": [
|
|
||||||
* { "text": "one two three four five", "confidence": 0.97 },
|
|
||||||
* { "text": "one two three for five", "confidence": 0.03 },
|
|
||||||
* ]
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param max_alternatives - maximum alternatives to return from recognition results
|
|
||||||
*/
|
|
||||||
void vosk_recognizer_set_max_alternatives(VoskRecognizer *recognizer, int max_alternatives);
|
|
||||||
|
|
||||||
|
|
||||||
/** Enables words with times in the output
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* "result" : [{
|
|
||||||
* "conf" : 1.000000,
|
|
||||||
* "end" : 1.110000,
|
|
||||||
* "start" : 0.870000,
|
|
||||||
* "word" : "what"
|
|
||||||
* }, {
|
|
||||||
* "conf" : 1.000000,
|
|
||||||
* "end" : 1.530000,
|
|
||||||
* "start" : 1.110000,
|
|
||||||
* "word" : "zero"
|
|
||||||
* }, {
|
|
||||||
* "conf" : 1.000000,
|
|
||||||
* "end" : 1.950000,
|
|
||||||
* "start" : 1.530000,
|
|
||||||
* "word" : "zero"
|
|
||||||
* }, {
|
|
||||||
* "conf" : 1.000000,
|
|
||||||
* "end" : 2.340000,
|
|
||||||
* "start" : 1.950000,
|
|
||||||
* "word" : "zero"
|
|
||||||
* }, {
|
|
||||||
* "conf" : 1.000000,
|
|
||||||
* "end" : 2.610000,
|
|
||||||
* "start" : 2.340000,
|
|
||||||
* "word" : "one"
|
|
||||||
* }],
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param words - boolean value
|
|
||||||
*/
|
|
||||||
void vosk_recognizer_set_words(VoskRecognizer *recognizer, int words);
|
|
||||||
|
|
||||||
/** Like above return words and confidences in partial results
|
|
||||||
*
|
|
||||||
* @param partial_words - boolean value
|
|
||||||
*/
|
|
||||||
void vosk_recognizer_set_partial_words(VoskRecognizer *recognizer, int partial_words);
|
|
||||||
|
|
||||||
/** Set NLSML output
|
|
||||||
* @param nlsml - boolean value
|
|
||||||
*/
|
|
||||||
void vosk_recognizer_set_nlsml(VoskRecognizer *recognizer, int nlsml);
|
|
||||||
|
|
||||||
|
|
||||||
/** Accept voice data
|
|
||||||
*
|
|
||||||
* accept and process new chunk of voice data
|
|
||||||
*
|
|
||||||
* @param data - audio data in PCM 16-bit mono format
|
|
||||||
* @param length - length of the audio data
|
|
||||||
* @returns 1 if silence is occured and you can retrieve a new utterance with result method
|
|
||||||
* 0 if decoding continues
|
|
||||||
* -1 if exception occured */
|
|
||||||
int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length);
|
|
||||||
|
|
||||||
|
|
||||||
/** Same as above but the version with the short data for language bindings where you have
|
|
||||||
* audio as array of shorts */
|
|
||||||
int vosk_recognizer_accept_waveform_s(VoskRecognizer *recognizer, const short *data, int length);
|
|
||||||
|
|
||||||
|
|
||||||
/** Same as above but the version with the float data for language bindings where you have
|
|
||||||
* audio as array of floats */
|
|
||||||
int vosk_recognizer_accept_waveform_f(VoskRecognizer *recognizer, const float *data, int length);
|
|
||||||
|
|
||||||
|
|
||||||
/** Returns speech recognition result
|
|
||||||
*
|
|
||||||
* @returns the result in JSON format which contains decoded line, decoded
|
|
||||||
* words, times in seconds and confidences. You can parse this result
|
|
||||||
* with any json parser
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {
|
|
||||||
* "text" : "what zero zero zero one"
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* If alternatives enabled it returns result with alternatives, see also vosk_recognizer_set_max_alternatives().
|
|
||||||
*
|
|
||||||
* If word times enabled returns word time, see also vosk_recognizer_set_word_times().
|
|
||||||
*/
|
|
||||||
const char *vosk_recognizer_result(VoskRecognizer *recognizer);
|
|
||||||
|
|
||||||
|
|
||||||
/** Returns partial speech recognition
|
|
||||||
*
|
|
||||||
* @returns partial speech recognition text which is not yet finalized.
|
|
||||||
* result may change as recognizer process more data.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {
|
|
||||||
* "partial" : "cyril one eight zero"
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
const char *vosk_recognizer_partial_result(VoskRecognizer *recognizer);
|
|
||||||
|
|
||||||
|
|
||||||
/** Returns speech recognition result. Same as result, but doesn't wait for silence
|
|
||||||
* You usually call it in the end of the stream to get final bits of audio. It
|
|
||||||
* flushes the feature pipeline, so all remaining audio chunks got processed.
|
|
||||||
*
|
|
||||||
* @returns speech result in JSON format.
|
|
||||||
*/
|
|
||||||
const char *vosk_recognizer_final_result(VoskRecognizer *recognizer);
|
|
||||||
|
|
||||||
|
|
||||||
/** Resets the recognizer
|
|
||||||
*
|
|
||||||
* Resets current results so the recognition can continue from scratch */
|
|
||||||
void vosk_recognizer_reset(VoskRecognizer *recognizer);
|
|
||||||
|
|
||||||
|
|
||||||
/** Releases recognizer object
|
|
||||||
*
|
|
||||||
* Underlying model is also unreferenced and if needed released */
|
|
||||||
void vosk_recognizer_free(VoskRecognizer *recognizer);
|
|
||||||
|
|
||||||
/** Set log level for Kaldi messages
|
|
||||||
*
|
|
||||||
* @param log_level the level
|
|
||||||
* 0 - default value to print info and error messages but no debug
|
|
||||||
* less than 0 - don't print info messages
|
|
||||||
* greather than 0 - more verbose mode
|
|
||||||
*/
|
|
||||||
void vosk_set_log_level(int log_level);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init, automatically select a CUDA device and allow multithreading.
|
|
||||||
* Must be called once from the main thread.
|
|
||||||
* Has no effect if HAVE_CUDA flag is not set.
|
|
||||||
*/
|
|
||||||
void vosk_gpu_init();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init CUDA device in a multi-threaded environment.
|
|
||||||
* Must be called for each thread.
|
|
||||||
* Has no effect if HAVE_CUDA flag is not set.
|
|
||||||
*/
|
|
||||||
void vosk_gpu_thread_init();
|
|
||||||
|
|
||||||
/** Creates the batch recognizer object
|
|
||||||
*
|
|
||||||
* @returns model object or NULL if problem occured */
|
|
||||||
VoskBatchModel *vosk_batch_model_new(const char *model_path);
|
|
||||||
|
|
||||||
/** Releases batch model object */
|
|
||||||
void vosk_batch_model_free(VoskBatchModel *model);
|
|
||||||
|
|
||||||
/** Wait for the processing */
|
|
||||||
void vosk_batch_model_wait(VoskBatchModel *model);
|
|
||||||
|
|
||||||
/** Creates batch recognizer object
|
|
||||||
* @returns recognizer object or NULL if problem occured */
|
|
||||||
VoskBatchRecognizer *vosk_batch_recognizer_new(VoskBatchModel *model, float sample_rate);
|
|
||||||
|
|
||||||
/** Releases batch recognizer object */
|
|
||||||
void vosk_batch_recognizer_free(VoskBatchRecognizer *recognizer);
|
|
||||||
|
|
||||||
/** Accept batch voice data */
|
|
||||||
void vosk_batch_recognizer_accept_waveform(VoskBatchRecognizer *recognizer, const char *data, int length);
|
|
||||||
|
|
||||||
/** Set NLSML output
|
|
||||||
* @param nlsml - boolean value
|
|
||||||
*/
|
|
||||||
void vosk_batch_recognizer_set_nlsml(VoskBatchRecognizer *recognizer, int nlsml);
|
|
||||||
|
|
||||||
/** Closes the stream */
|
|
||||||
void vosk_batch_recognizer_finish_stream(VoskBatchRecognizer *recognizer);
|
|
||||||
|
|
||||||
/** Return results */
|
|
||||||
const char *vosk_batch_recognizer_front_result(VoskBatchRecognizer *recognizer);
|
|
||||||
|
|
||||||
/** Release and free first retrieved result */
|
|
||||||
void vosk_batch_recognizer_pop(VoskBatchRecognizer *recognizer);
|
|
||||||
|
|
||||||
/** Get amount of pending chunks for more intelligent waiting */
|
|
||||||
int vosk_batch_recognizer_get_pending_chunks(VoskBatchRecognizer *recognizer);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* VOSK_API_H */
|
|
||||||
|
|
@ -13,10 +13,10 @@
|
||||||
</script>
|
</script>
|
||||||
<header id="header">
|
<header id="header">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<a href="/" title="Хауди Хо!"><img src="/media/app-logo.png"></a>
|
<a href="/" title="Хауди Хо!"><img src="/media/app-logo.png" alt=""></a>
|
||||||
<div>
|
<div>
|
||||||
<h1><a href="/">JARVIS</a></h1>
|
<h1><a href="/">JARVIS</a></h1>
|
||||||
<h2>v{app_version} beta</h2>
|
<h2>v{app_version} <small style="color: #8AC832;opacity: .9;font-size: 13px;">BETA</small></h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<nav class="top-menu">
|
<nav class="top-menu">
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,23 @@
|
||||||
<script>
|
<script>
|
||||||
|
// IMPORTS
|
||||||
import { invoke } from "@tauri-apps/api/tauri"
|
import { invoke } from "@tauri-apps/api/tauri"
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
import { capitalizeFirstLetter } from "@/functions";
|
||||||
|
|
||||||
|
// VARIABLES
|
||||||
let selected_microphone = 0;
|
let selected_microphone = 0;
|
||||||
let microphone_label = "";
|
let microphone_label = "";
|
||||||
let nn_label = "Picovoice + Vosk";
|
|
||||||
|
let nn_details = {
|
||||||
|
"ww_engine": "",
|
||||||
|
"stt_engine": "Vosk"
|
||||||
|
}
|
||||||
|
|
||||||
// let resources_cpu_temp = 0;
|
// let resources_cpu_temp = 0;
|
||||||
// let resources_cpu_usage = 0;
|
// let resources_cpu_usage = 0;
|
||||||
let resources_ram_usage = "-";
|
let resources_ram_usage = "-";
|
||||||
|
|
||||||
|
// CODE
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
resources_ram_usage = Number(await invoke("get_current_ram_usage")).toFixed(2);
|
resources_ram_usage = Number(await invoke("get_current_ram_usage")).toFixed(2);
|
||||||
|
|
@ -18,12 +28,13 @@
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
import { onMount } from 'svelte';
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
(async () => {
|
(async () => {
|
||||||
selected_microphone = +Number(await invoke("db_read", {key: "selected_microphone"}));
|
selected_microphone = +Number(await invoke("db_read", {key: "selected_microphone"}));
|
||||||
microphone_label = await invoke("pv_get_audio_device_name", {idx: selected_microphone});
|
microphone_label = await invoke("pv_get_audio_device_name", {idx: selected_microphone});
|
||||||
|
|
||||||
|
nn_details["ww_engine"] = capitalizeFirstLetter(await invoke("db_read", {key: "selected_wake_word_engine"}));
|
||||||
|
|
||||||
// resources_cpu_temp = await invoke("get_cpu_temp");
|
// resources_cpu_temp = await invoke("get_cpu_temp");
|
||||||
// resources_cpu_usage = +Number(await invoke("get_cpu_usage")).toFixed(2);
|
// resources_cpu_usage = +Number(await invoke("get_cpu_usage")).toFixed(2);
|
||||||
})().catch(err => {
|
})().catch(err => {
|
||||||
|
|
@ -44,7 +55,7 @@
|
||||||
<div class="pulse"><div class="wave"></div></div>
|
<div class="pulse"><div class="wave"></div></div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<span class="num">Нейросети</span>
|
<span class="num">Нейросети</span>
|
||||||
<small title="{nn_label}">{nn_label}</small>
|
<small>{nn_details["ww_engine"]} + {nn_details["stt_engine"]}</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="downloads hint--bottom" aria-label="Общее количество скачиваний по всему проекту">
|
<div class="downloads hint--bottom" aria-label="Общее количество скачиваний по всему проекту">
|
||||||
|
|
|
||||||
2432
src/css/main.scss
|
|
@ -72,3 +72,21 @@ a {
|
||||||
select, input {
|
select, input {
|
||||||
color: #ccc!important;
|
color: #ccc!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
label {
|
||||||
|
font-weight: bold!important;
|
||||||
|
color: #8AC832!important;
|
||||||
|
font-size: 15px!important;
|
||||||
|
border-bottom: 1px dotted gray;
|
||||||
|
margin-bottom: 10px!important;
|
||||||
|
|
||||||
|
& + div {
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.svelteui-Tab-label {
|
||||||
|
font-size: 18px!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -42,3 +42,7 @@ export function stopListening(callback) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function capitalizeFirstLetter(string) {
|
||||||
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<HDivider />
|
<HDivider />
|
||||||
<Notification title='Этот раздел еще находится в разработке.' icon={InfoCircled} color='blue'></Notification>
|
<Notification title='404' icon={InfoCircled} color='blue' withCloseButton={false}>
|
||||||
|
Этот раздел еще находится в разработке.
|
||||||
|
</Notification>
|
||||||
<HDivider />
|
<HDivider />
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|
@ -1,31 +1,62 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
// IMPORTS
|
||||||
import { invoke } from "@tauri-apps/api/tauri"
|
import { invoke } from "@tauri-apps/api/tauri"
|
||||||
import { goto } from '@roxi/routify'
|
import { goto } from '@roxi/routify'
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
import { startListening, stopListening } from "@/functions";
|
||||||
|
import { setTimeout } from 'worker-timers';
|
||||||
|
|
||||||
|
// COMPONENTS & STUFF
|
||||||
import HDivider from "@/components/elements/HDivider.svelte"
|
import HDivider from "@/components/elements/HDivider.svelte"
|
||||||
import Footer from "@/components/Footer.svelte"
|
import Footer from "@/components/Footer.svelte"
|
||||||
|
|
||||||
import { Notification, Button, Text, Tabs, Space, Alert, Input, InputWrapper, NativeSelect } from '@svelteuidev/core';
|
import { Notification, Button, Text, Tabs, Space, Alert, Input, InputWrapper, NativeSelect } from '@svelteuidev/core';
|
||||||
import { Check, Mix, Code, Gear, InfoCircled } from 'radix-icons-svelte';
|
import { Check, Mix, Cube, Code, Gear, QuestionMarkCircled } from 'radix-icons-svelte';
|
||||||
|
|
||||||
// vars
|
// VARIABLES
|
||||||
let available_microphones = [];
|
let available_microphones = [];
|
||||||
let settings_saved = false;
|
let settings_saved = false;
|
||||||
|
|
||||||
// settings field values
|
|
||||||
let assistant_voice_val = ""; // shared
|
let assistant_voice_val = ""; // shared
|
||||||
let selected_microphone = "";
|
let selected_microphone = "";
|
||||||
|
|
||||||
|
let selected_wake_word_engine = "";
|
||||||
let api_key__picovoice = "";
|
let api_key__picovoice = "";
|
||||||
let api_key__openai = "";
|
let api_key__openai = "";
|
||||||
|
|
||||||
// shared values
|
// SHARED VALUES
|
||||||
import { assistant_voice } from "@/stores"
|
import { assistant_voice } from "@/stores"
|
||||||
assistant_voice.subscribe(value => {
|
assistant_voice.subscribe(value => {
|
||||||
assistant_voice_val = value;
|
assistant_voice_val = value;
|
||||||
});
|
});
|
||||||
|
|
||||||
(async () => {
|
// FUNCTIONS
|
||||||
|
async function save_settings() {
|
||||||
|
settings_saved = false; // hide alert
|
||||||
|
|
||||||
|
await invoke("db_write", {key: "assistant_voice", val: assistant_voice_val});
|
||||||
|
await invoke("db_write", {key: "selected_microphone", val: selected_microphone});
|
||||||
|
|
||||||
|
await invoke("db_write", {key: "selected_wake_word_engine", val: selected_wake_word_engine});
|
||||||
|
await invoke("db_write", {key: "api_key__picovoice", val: api_key__picovoice});
|
||||||
|
await invoke("db_write", {key: "api_key__openai", val: api_key__openai});
|
||||||
|
|
||||||
|
// update shared
|
||||||
|
assistant_voice.set(assistant_voice_val);
|
||||||
|
|
||||||
|
settings_saved = true; // show alert
|
||||||
|
setTimeout(() => {
|
||||||
|
settings_saved = false; // hide alert again after N seconds
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
// restart listening everytime new settings is saved
|
||||||
|
stopListening(() => {
|
||||||
|
startListening();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// CODE
|
||||||
|
onMount(async () => {
|
||||||
// preload some vars
|
// preload some vars
|
||||||
let _available_microphones: Array<Number> = await invoke("pv_get_audio_devices");
|
let _available_microphones: Array<Number> = await invoke("pv_get_audio_devices");
|
||||||
Object.entries(_available_microphones).forEach(entry => {
|
Object.entries(_available_microphones).forEach(entry => {
|
||||||
|
|
@ -43,53 +74,31 @@
|
||||||
// assistant_voice.set(await invoke("db_read", {key: "assistant_voice"}));
|
// assistant_voice.set(await invoke("db_read", {key: "assistant_voice"}));
|
||||||
selected_microphone = await invoke("db_read", {key: "selected_microphone"});
|
selected_microphone = await invoke("db_read", {key: "selected_microphone"});
|
||||||
|
|
||||||
|
selected_wake_word_engine = await invoke("db_read", {key: "selected_wake_word_engine"});
|
||||||
api_key__picovoice = await invoke("db_read", {key: "api_key__picovoice"});
|
api_key__picovoice = await invoke("db_read", {key: "api_key__picovoice"});
|
||||||
api_key__openai = await invoke("db_read", {key: "api_key__openai"});
|
api_key__openai = await invoke("db_read", {key: "api_key__openai"});
|
||||||
})().catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// subscribe to listen state
|
|
||||||
import { startListening, stopListening } from "@/functions";
|
|
||||||
|
|
||||||
// save values to db
|
|
||||||
async function save_settings(event) {
|
|
||||||
await invoke("db_write", {key: "assistant_voice", val: assistant_voice_val});
|
|
||||||
await invoke("db_write", {key: "selected_microphone", val: selected_microphone});
|
|
||||||
|
|
||||||
await invoke("db_write", {key: "api_key__picovoice", val: api_key__picovoice});
|
|
||||||
await invoke("db_write", {key: "api_key__openai", val: api_key__openai});
|
|
||||||
|
|
||||||
// update shared
|
|
||||||
assistant_voice.set(assistant_voice_val);
|
|
||||||
|
|
||||||
settings_saved = true;
|
|
||||||
|
|
||||||
// restart listening everytime
|
|
||||||
stopListening(() => {
|
|
||||||
startListening();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Space h="xl" />
|
<Space h="xl" />
|
||||||
|
|
||||||
<Alert icon={InfoCircled} title="Внимание!" color="cyan" variant="outline">
|
<Notification title='БЕТА версия!' icon={QuestionMarkCircled} color='blue' withCloseButton={false}>
|
||||||
Приложение находится в <strong>БЕТА</strong> режиме.<br />
|
|
||||||
Часть функций может работать некорректно.<br />
|
Часть функций может работать некорректно.<br />
|
||||||
Сообщайте обо всех найденных багах в <a href="https://t.me/hhsharebot" target="_blank">наш телеграм бот</a>.
|
Сообщайте обо всех найденных багах в <a href="https://t.me/hhsharebot" target="_blank">наш телеграм бот</a>.
|
||||||
</Alert>
|
</Notification>
|
||||||
|
|
||||||
<Space h="xl" />
|
<Space h="xl" />
|
||||||
|
|
||||||
{#if settings_saved }
|
{#if settings_saved }
|
||||||
<Notification title='Настройки сохранены!' icon={Check} color='teal' on:close="{() => {settings_saved = false}}"></Notification>
|
<Notification title='Настройки сохранены!' icon={Check} color='teal' on:close="{() => {settings_saved = false}}"></Notification>
|
||||||
|
<Space h="xl" />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<Space h="xl" />
|
<Tabs class="form" color='#8AC832' position="left">
|
||||||
|
|
||||||
<Tabs color='cyan' position="left">
|
|
||||||
<Tabs.Tab label='Общее' icon={Gear}>
|
<Tabs.Tab label='Общее' icon={Gear}>
|
||||||
|
<Space h="sm" />
|
||||||
|
|
||||||
<NativeSelect data={[
|
<NativeSelect data={[
|
||||||
{ label: 'Jarvis ремейк (от Хауди)', value: 'jarvis-remake' },
|
{ label: 'Jarvis ремейк (от Хауди)', value: 'jarvis-remake' },
|
||||||
{ label: 'Jarvis OG (из фильмов)', value: 'jarvis-og' }
|
{ label: 'Jarvis OG (из фильмов)', value: 'jarvis-og' }
|
||||||
|
|
@ -101,6 +110,8 @@
|
||||||
/>
|
/>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
<Tabs.Tab label='Устройства' icon={Mix}>
|
<Tabs.Tab label='Устройства' icon={Mix}>
|
||||||
|
<Space h="sm" />
|
||||||
|
|
||||||
<NativeSelect data={available_microphones}
|
<NativeSelect data={available_microphones}
|
||||||
label="Выберите микрофон"
|
label="Выберите микрофон"
|
||||||
description="Его будет слушать ассистент."
|
description="Его будет слушать ассистент."
|
||||||
|
|
@ -108,17 +119,37 @@
|
||||||
bind:value={selected_microphone}
|
bind:value={selected_microphone}
|
||||||
/>
|
/>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
<Tabs.Tab label='API ключи' icon={Code}>
|
<Tabs.Tab label='Нейросети' icon={Cube}>
|
||||||
<InputWrapper label="Ключ Picovoice">
|
<Space h="sm" />
|
||||||
<Text size='xs'>Введите сюда свой ключ Picovoice.<br />Он выдается бесплатно при регистрации в <a href='https://console.picovoice.ai/' target="_blank">Picovoice Console</a>.</Text>
|
|
||||||
|
<NativeSelect data={[
|
||||||
|
{ label: 'Rustpotter', value: 'rustpotter' },
|
||||||
|
{ label: 'Picovoice Porcupine (требует API ключ)', value: 'picovoice' }
|
||||||
|
]}
|
||||||
|
label="Распознавание активационной фразы (Wake Word)"
|
||||||
|
description="Выберите, какая нейросеть будет отвечать за распознавание активационной фразы."
|
||||||
|
variant="filled"
|
||||||
|
bind:value={selected_wake_word_engine}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{#if selected_wake_word_engine == "picovoice"}
|
||||||
|
<Space h="sm" />
|
||||||
|
<Alert title="Внимание!" color="#868E96" variant="outline">
|
||||||
|
|
||||||
|
<Text size='sm' color="gray">Введите сюда свой ключ Picovoice.<br />Он выдается бесплатно при регистрации в <a href='https://console.picovoice.ai/' target="_blank">Picovoice Console</a>.</Text>
|
||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<Input icon={Code} placeholder='Ключ Picovoice' variant='filled' autocomplete="off" bind:value={api_key__picovoice}/>
|
<Input icon={Code} placeholder='Ключ Picovoice' variant='filled' autocomplete="off" bind:value={api_key__picovoice}/>
|
||||||
</InputWrapper>
|
|
||||||
|
</Alert>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<Space h="xl" />
|
<Space h="xl" />
|
||||||
|
|
||||||
<InputWrapper label="Ключ OpenAI">
|
<InputWrapper label="Ключ OpenAI">
|
||||||
<Text size='xs'>Введите сюда свой ключ OpenAI, он требуется для работы ChatGPT.<br />Получить его можно <a href="https://chat.openai.com/auth/login" target="_blank">на официальном сайте OpenAI</a>.</Text>
|
<!-- <Text size='sm' color="gray">Введите сюда свой ключ OpenAI, он требуется для работы ChatGPT.<br />Получить его можно <a href="https://chat.openai.com/auth/login" target="_blank">на официальном сайте OpenAI</a>.</Text> -->
|
||||||
|
<Text size='sm' color="gray">В данный момент ChatGPT <u>не поддерживается</u>. Он будет добавлен в ближайших обновлениях.</Text>
|
||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<Input icon={Code} placeholder='Ключ OpenAI' variant='filled' autocomplete="off" bind:value={api_key__openai}/>
|
<Input icon={Code} placeholder='Ключ OpenAI' variant='filled' autocomplete="off" bind:value={api_key__openai} disabled/>
|
||||||
</InputWrapper>
|
</InputWrapper>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
|
||||||