mirror of
https://github.com/Priler/jarvis.git
synced 2026-05-26 07:08:11 +00:00
vosk model selection in GUI
This commit is contained in:
@@ -7,7 +7,7 @@ repository.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
jarvis-core = { path = "../jarvis-core" }
|
||||
jarvis-core = { path = "../jarvis-core", features = ["intent"] }
|
||||
once_cell.workspace = true
|
||||
log.workspace = true
|
||||
simple-log = "2.4"
|
||||
|
||||
@@ -64,7 +64,7 @@ pub fn init_dirs() -> Result<(), String> {
|
||||
*/
|
||||
pub const DEFAULT_AUDIO_TYPE: AudioType = AudioType::Kira;
|
||||
pub const DEFAULT_RECORDER_TYPE: RecorderType = RecorderType::PvRecorder;
|
||||
pub const DEFAULT_WAKE_WORD_ENGINE: WakeWordEngine = WakeWordEngine::Rustpotter;
|
||||
pub const DEFAULT_WAKE_WORD_ENGINE: WakeWordEngine = WakeWordEngine::Vosk;
|
||||
pub const DEFAULT_INTENT_RECOGNITION_ENGINE: IntentRecognitionEngine = IntentRecognitionEngine::IntentClassifier;
|
||||
pub const DEFAULT_SPEECH_TO_TEXT_ENGINE: SpeechToTextEngine = SpeechToTextEngine::Vosk;
|
||||
|
||||
@@ -121,19 +121,20 @@ pub const RUSTPOTTER_DEFAULT_CONFIG: Lazy<RustpotterConfig> = Lazy::new(|| {
|
||||
});
|
||||
|
||||
// PICOVOICE
|
||||
pub const COMMANDS_PATH: &str = "commands/";
|
||||
pub const KEYWORDS_PATH: &str = "picovoice/keywords/";
|
||||
pub const COMMANDS_PATH: &str = "resources/commands/";
|
||||
pub const KEYWORDS_PATH: &str = "resources/picovoice/keywords/";
|
||||
pub const DEFAULT_KEYWORD: &str = "jarvis_windows.ppn";
|
||||
pub const DEFAULT_SENSITIVITY: f32 = 1.0;
|
||||
|
||||
// VOSK
|
||||
// pub const VOSK_MODEL_PATH: &str = const_concat!(PUBLIC_PATH, "/vosk/model_small");
|
||||
pub const VOSK_MODELS_PATH: &str = "resources/vosk";
|
||||
pub const VOSK_MODEL_PATH: &str = "resources/vosk/model_small";
|
||||
pub const VOSK_FETCH_PHRASE: &str = "джарвис";
|
||||
pub const VOSK_MODEL_PATH: &str = "vosk/model_small";
|
||||
pub const VOSK_MIN_RATIO: f64 = 70.0;
|
||||
|
||||
// IRE (intents recognition)
|
||||
pub const INTENT_CLASSIFIER_MIN_CONFIDENCE: f64 = 0.5;
|
||||
pub const INTENT_CLASSIFIER_MIN_CONFIDENCE: f64 = 0.75;
|
||||
|
||||
// ETC
|
||||
pub const CMD_RATIO_THRESHOLD: f64 = 65f64;
|
||||
|
||||
@@ -14,6 +14,8 @@ pub struct Settings {
|
||||
pub intent_recognition_engine: IntentRecognitionEngine,
|
||||
pub speech_to_text_engine: SpeechToTextEngine,
|
||||
|
||||
pub vosk_model: String,
|
||||
|
||||
pub api_keys: ApiKeys,
|
||||
}
|
||||
|
||||
@@ -27,6 +29,8 @@ impl Default for Settings {
|
||||
intent_recognition_engine: config::DEFAULT_INTENT_RECOGNITION_ENGINE,
|
||||
speech_to_text_engine: config::DEFAULT_SPEECH_TO_TEXT_ENGINE,
|
||||
|
||||
vosk_model: String::from(""), // auto detect first available
|
||||
|
||||
api_keys: ApiKeys {
|
||||
picovoice: String::from(""),
|
||||
openai: String::from(""),
|
||||
|
||||
@@ -23,9 +23,17 @@ pub mod stt;
|
||||
#[cfg(feature = "intent")]
|
||||
pub mod intent;
|
||||
|
||||
pub mod vosk_models;
|
||||
|
||||
// shared statics
|
||||
pub static APP_DIR: Lazy<PathBuf> = Lazy::new(|| std::env::current_dir().unwrap());
|
||||
pub static SOUND_DIR: Lazy<PathBuf> = Lazy::new(|| APP_DIR.clone().join("sound"));
|
||||
// pub static APP_DIR: Lazy<PathBuf> = Lazy::new(|| std::env::current_dir().unwrap());
|
||||
pub static APP_DIR: Lazy<PathBuf> = Lazy::new(|| {
|
||||
std::env::current_exe()
|
||||
.ok()
|
||||
.and_then(|p| p.parent().map(|p| p.to_path_buf()))
|
||||
.unwrap_or_else(|| std::env::current_dir().unwrap())
|
||||
});
|
||||
pub static SOUND_DIR: Lazy<PathBuf> = Lazy::new(|| APP_DIR.clone().join("resources/sound"));
|
||||
pub static APP_DIRS: OnceCell<AppDirs> = OnceCell::new();
|
||||
pub static APP_CONFIG_DIR: OnceCell<PathBuf> = OnceCell::new();
|
||||
pub static APP_LOG_DIR: OnceCell<PathBuf> = OnceCell::new();
|
||||
|
||||
@@ -6,6 +6,9 @@ use once_cell::sync::OnceCell;
|
||||
|
||||
use crate::config::structs::SpeechToTextEngine;
|
||||
|
||||
use crate::vosk_models;
|
||||
// use vosk_models::{scan_vosk_models, get_model_path, VoskModelInfo};
|
||||
|
||||
static STT_TYPE: OnceCell<SpeechToTextEngine> = OnceCell::new();
|
||||
|
||||
pub fn init() -> Result<(), ()> {
|
||||
@@ -30,6 +33,7 @@ pub fn init() -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn recognize(data: &[i16], partial: bool) -> Option<String> {
|
||||
match STT_TYPE.get().unwrap() {
|
||||
SpeechToTextEngine::Vosk => vosk::recognize(data, partial),
|
||||
|
||||
@@ -3,18 +3,26 @@ use vosk::{DecodingState, Model, Recognizer};
|
||||
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::config::VOSK_MODEL_PATH;
|
||||
// use crate::config::VOSK_MODEL_PATH;
|
||||
use crate::config;
|
||||
use crate::stt::vosk_models;
|
||||
use crate::DB;
|
||||
|
||||
static MODEL: OnceCell<Model> = OnceCell::new();
|
||||
static RECOGNIZER: OnceCell<Mutex<Recognizer>> = OnceCell::new();
|
||||
|
||||
pub fn init_vosk() {
|
||||
pub fn init_vosk() -> Result<(), String> {
|
||||
if RECOGNIZER.get().is_some() {
|
||||
return;
|
||||
return Ok(());
|
||||
} // already initialized
|
||||
|
||||
let model = Model::new(VOSK_MODEL_PATH).unwrap();
|
||||
let mut recognizer = Recognizer::new(&model, 16000.0).unwrap();
|
||||
let model_path = get_configured_model_path()?;
|
||||
|
||||
let model = Model::new(model_path.to_str().unwrap())
|
||||
.ok_or_else(|| format!("Failed to load Vosk model from: {}", model_path.display()))?;
|
||||
|
||||
let mut recognizer = Recognizer::new(&model, 16000.0)
|
||||
.ok_or("Failed to create Vosk recognizer")?;
|
||||
|
||||
recognizer.set_max_alternatives(10);
|
||||
recognizer.set_words(true);
|
||||
@@ -22,6 +30,8 @@ pub fn init_vosk() {
|
||||
|
||||
MODEL.set(model);
|
||||
RECOGNIZER.set(Mutex::new(recognizer));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn recognize(data: &[i16], include_partial: bool) -> Option<String> {
|
||||
@@ -73,6 +83,34 @@ pub fn recognize(data: &[i16], include_partial: bool) -> Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_configured_model_path() -> Result<std::path::PathBuf, String> {
|
||||
// try to get from settings
|
||||
if let Some(db) = DB.get() {
|
||||
let settings = db.read();
|
||||
if !settings.vosk_model.is_empty() {
|
||||
if let Some(path) = vosk_models::get_model_path(&settings.vosk_model) {
|
||||
return Ok(path);
|
||||
}
|
||||
warn!("Configured Vosk model '{}' not found, falling back to auto-detect", settings.vosk_model);
|
||||
}
|
||||
}
|
||||
|
||||
// auto-detect: use first available model
|
||||
let available = vosk_models::scan_vosk_models();
|
||||
if let Some(first) = available.first() {
|
||||
info!("Auto-detected Vosk model: {}", first.name);
|
||||
return Ok(first.path.clone());
|
||||
}
|
||||
|
||||
// fallback to legacy path
|
||||
let legacy_path = std::path::Path::new(config::VOSK_MODEL_PATH);
|
||||
if legacy_path.exists() {
|
||||
return Ok(legacy_path.to_path_buf());
|
||||
}
|
||||
|
||||
Err("No Vosk models found".into())
|
||||
}
|
||||
|
||||
// pub fn stereo_to_mono(input_data: &[i16]) -> Vec<i16> {
|
||||
// let mut result = Vec::with_capacity(input_data.len() / 2);
|
||||
// result.extend(
|
||||
|
||||
113
crates/jarvis-core/src/vosk_models.rs
Normal file
113
crates/jarvis-core/src/vosk_models.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::{APP_DIR, config};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VoskModelInfo {
|
||||
pub name: String, // folder name: "vosk-model-small-ru-0.22"
|
||||
pub path: PathBuf, // full path
|
||||
pub language: String, // extracted from name: "ru"
|
||||
pub size: String, // "small", "large", etc.
|
||||
}
|
||||
|
||||
// Scan for available Vosk models
|
||||
pub fn scan_vosk_models() -> Vec<VoskModelInfo> {
|
||||
let models_dir = {
|
||||
APP_DIR.join(config::VOSK_MODELS_PATH)
|
||||
};
|
||||
let mut models = Vec::new();
|
||||
|
||||
info!("TESTTTTTTTTTTTTT: {}", models_dir.display());
|
||||
|
||||
if !models_dir.exists() {
|
||||
warn!("Vosk models directory not found: {}", models_dir.display());
|
||||
return models;
|
||||
}
|
||||
|
||||
let entries = match fs::read_dir(models_dir) {
|
||||
Ok(e) => e,
|
||||
Err(e) => {
|
||||
warn!("Failed to read vosk models directory: {}", e);
|
||||
return models;
|
||||
}
|
||||
};
|
||||
|
||||
for entry in entries {
|
||||
let entry = match entry {
|
||||
Ok(e) => e,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let path = entry.path();
|
||||
|
||||
// must be a directory
|
||||
if !path.is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if it looks like a vosk model (has am/conf/graph folders or similar)
|
||||
if !is_vosk_model(&path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = path.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
|
||||
let (language, size) = parse_model_name(&name);
|
||||
|
||||
models.push(VoskModelInfo {
|
||||
name,
|
||||
path,
|
||||
language,
|
||||
size,
|
||||
});
|
||||
}
|
||||
|
||||
models.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
models
|
||||
}
|
||||
|
||||
// Check if directory looks like a Vosk model
|
||||
fn is_vosk_model(path: &Path) -> bool {
|
||||
// vosk models typically have these subdirectories
|
||||
path.join("am").exists() ||
|
||||
path.join("conf").exists() ||
|
||||
path.join("graph").exists() ||
|
||||
path.join("ivector").exists()
|
||||
}
|
||||
|
||||
// Extract language and size from model name
|
||||
// e.g., "vosk-model-small-ru-0.22" -> ("ru", "small")
|
||||
fn parse_model_name(name: &str) -> (String, String) {
|
||||
let parts: Vec<&str> = name.split('-').collect();
|
||||
|
||||
let mut language = String::from("unknown");
|
||||
let mut size = String::from("unknown");
|
||||
|
||||
// look for common size indicators
|
||||
for part in &parts {
|
||||
match *part {
|
||||
"small" | "big" | "large" | "lgraph" => size = part.to_string(),
|
||||
// language codes are usually 2 letters
|
||||
s if s.len() == 2 && s.chars().all(|c| c.is_alphabetic()) => {
|
||||
language = s.to_string();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
(language, size)
|
||||
}
|
||||
|
||||
// Get model path by name
|
||||
pub fn get_model_path(model_name: &str) -> Option<PathBuf> {
|
||||
let path = Path::new(config::VOSK_MODELS_PATH).join(model_name);
|
||||
if path.exists() && path.is_dir() {
|
||||
Some(path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,9 @@ fn main() {
|
||||
tauri_commands::get_peak_ram_usage,
|
||||
tauri_commands::get_cpu_temp,
|
||||
tauri_commands::get_cpu_usage,
|
||||
|
||||
// vosk
|
||||
tauri_commands::list_vosk_models,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
@@ -22,3 +22,7 @@ pub use fs::*;
|
||||
// import SYS commands
|
||||
mod sys;
|
||||
pub use sys::*;
|
||||
|
||||
// import STT commands
|
||||
mod stt;
|
||||
pub use stt::*;
|
||||
@@ -10,6 +10,7 @@ pub fn db_read(state: tauri::State<'_, AppState>, key: &str) -> String {
|
||||
"assistant_voice" => settings.voice.clone(),
|
||||
"selected_wake_word_engine" => format!("{:?}", settings.wake_word_engine),
|
||||
"selected_intent_recognition_engine" => format!("{:?}", settings.intent_recognition_engine),
|
||||
"selected_vosk_model" => settings.vosk_model.clone(),
|
||||
"speech_to_text_engine" => format!("{:?}", settings.speech_to_text_engine),
|
||||
"api_key__picovoice" => settings.api_keys.picovoice.clone(),
|
||||
"api_key__openai" => settings.api_keys.openai.clone(),
|
||||
@@ -49,6 +50,9 @@ pub fn db_write(state: tauri::State<'_, AppState>, key: &str, val: &str) -> bool
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
"selected_vosk_model" => {
|
||||
settings.vosk_model = val.to_string();
|
||||
}
|
||||
"api_key__picovoice" => {
|
||||
settings.api_keys.picovoice = val.to_string();
|
||||
}
|
||||
|
||||
21
crates/jarvis-gui/src/tauri_commands/stt.rs
Normal file
21
crates/jarvis-gui/src/tauri_commands/stt.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use jarvis_core::{vosk_models, DB};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct VoskModel {
|
||||
pub name: String,
|
||||
pub language: String,
|
||||
pub size: String,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn list_vosk_models() -> Vec<VoskModel> {
|
||||
vosk_models::scan_vosk_models()
|
||||
.into_iter()
|
||||
.map(|m| VoskModel {
|
||||
name: m.name,
|
||||
language: m.language,
|
||||
size: m.size,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -39,6 +39,7 @@
|
||||
}
|
||||
|
||||
let availableMicrophones: MicrophoneOption[] = []
|
||||
let availableVoskModels: { label: string; value: string }[] = []
|
||||
let settingsSaved = false
|
||||
let saveButtonDisabled = false
|
||||
|
||||
@@ -47,6 +48,7 @@
|
||||
let selectedMicrophone = ""
|
||||
let selectedWakeWordEngine = ""
|
||||
let selectedIntentRecognitionEngine = ""
|
||||
let selectedVoskModel = ""
|
||||
let apiKeyPicovoice = ""
|
||||
let apiKeyOpenai = ""
|
||||
|
||||
@@ -73,6 +75,7 @@
|
||||
invoke("db_write", { key: "selected_microphone", val: selectedMicrophone }),
|
||||
invoke("db_write", { key: "selected_wake_word_engine", val: selectedWakeWordEngine }),
|
||||
invoke("db_write", { key: "selected_intent_recognition_engine", val: selectedIntentRecognitionEngine }),
|
||||
invoke("db_write", { key: "selected_vosk_model", val: selectedVoskModel }),
|
||||
invoke("db_write", { key: "api_key__picovoice", val: apiKeyPicovoice }),
|
||||
invoke("db_write", { key: "api_key__openai", val: apiKeyOpenai })
|
||||
])
|
||||
@@ -107,11 +110,19 @@
|
||||
value: String(idx)
|
||||
}))
|
||||
|
||||
// load vosk models
|
||||
const voskModels = await invoke<{ name: string; language: string; size: string }[]>("list_vosk_models")
|
||||
availableVoskModels = voskModels.map(m => ({
|
||||
label: `${m.name} (${m.language}, ${m.size})`,
|
||||
value: m.name
|
||||
}))
|
||||
|
||||
// load settings from db
|
||||
const [mic, wakeWord, intentReco, pico, openai] = await Promise.all([
|
||||
const [mic, wakeWord, intentReco, voskModel, pico, openai] = await Promise.all([
|
||||
invoke<string>("db_read", { key: "selected_microphone" }),
|
||||
invoke<string>("db_read", { key: "selected_wake_word_engine" }),
|
||||
invoke<string>("db_read", { key: "selected_intent_recognition_engine" }),
|
||||
invoke<string>("db_read", { key: "selected_vosk_model" }),
|
||||
invoke<string>("db_read", { key: "api_key__picovoice" }),
|
||||
invoke<string>("db_read", { key: "api_key__openai" })
|
||||
])
|
||||
@@ -119,6 +130,7 @@
|
||||
selectedMicrophone = mic
|
||||
selectedWakeWordEngine = wakeWord
|
||||
selectedIntentRecognitionEngine = intentReco
|
||||
selectedVoskModel = voskModel
|
||||
apiKeyPicovoice = pico
|
||||
apiKeyOpenai = openai
|
||||
} catch (err) {
|
||||
@@ -232,6 +244,29 @@
|
||||
</Alert>
|
||||
{/if}
|
||||
|
||||
<Space h="xl" />
|
||||
{#key availableVoskModels}
|
||||
<NativeSelect
|
||||
data={[
|
||||
{ label: "Авто-определение", value: "" },
|
||||
...availableVoskModels
|
||||
]}
|
||||
label="Модель распознавания речи (Vosk)"
|
||||
description="Выберите модель Vosk для распознавания речи."
|
||||
variant="filled"
|
||||
bind:value={selectedVoskModel}
|
||||
/>
|
||||
{/key}
|
||||
|
||||
{#if availableVoskModels.length === 0}
|
||||
<Space h="sm" />
|
||||
<Alert title="Модели не найдены" color="orange" variant="outline">
|
||||
<Text size="sm" color="gray">
|
||||
Поместите модели Vosk в папку resources/vosk
|
||||
</Text>
|
||||
</Alert>
|
||||
{/if}
|
||||
|
||||
<Space h="xl" />
|
||||
<NativeSelect
|
||||
data={[
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// vite.config.ts
|
||||
import { defineConfig } from "file:///D:/Rust/jarvis-app/frontend/node_modules/vite/dist/node/index.js";
|
||||
import { svelte } from "file:///D:/Rust/jarvis-app/frontend/node_modules/@sveltejs/vite-plugin-svelte/src/index.js";
|
||||
import sveltePreprocess from "file:///D:/Rust/jarvis-app/frontend/node_modules/svelte-preprocess/dist/index.js";
|
||||
import tsconfigPaths from "file:///D:/Rust/jarvis-app/frontend/node_modules/vite-tsconfig-paths/dist/index.mjs";
|
||||
import routify from "file:///D:/Rust/jarvis-app/frontend/node_modules/@roxi/routify/lib/extra/vite-plugin/vite-plugin.js";
|
||||
var vite_config_default = defineConfig({
|
||||
plugins: [
|
||||
svelte({
|
||||
preprocess: [
|
||||
sveltePreprocess({
|
||||
typescript: true
|
||||
})
|
||||
],
|
||||
onwarn: (warning, handler) => {
|
||||
const { code, frame } = warning;
|
||||
if (code === "css-unused-selector")
|
||||
return;
|
||||
handler(warning);
|
||||
}
|
||||
}),
|
||||
routify(),
|
||||
tsconfigPaths()
|
||||
],
|
||||
clearScreen: false,
|
||||
server: {
|
||||
port: 1420,
|
||||
strictPort: true
|
||||
},
|
||||
envPrefix: ["VITE_", "TAURI_"],
|
||||
build: {
|
||||
target: process.env.TAURI_PLATFORM == "windows" ? "chrome105" : "safari13",
|
||||
minify: !process.env.TAURI_DEBUG ? "esbuild" : false,
|
||||
sourcemap: !!process.env.TAURI_DEBUG
|
||||
}
|
||||
});
|
||||
export {
|
||||
vite_config_default as default
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxSdXN0XFxcXGphcnZpcy1hcHBcXFxcZnJvbnRlbmRcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkQ6XFxcXFJ1c3RcXFxcamFydmlzLWFwcFxcXFxmcm9udGVuZFxcXFx2aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vRDovUnVzdC9qYXJ2aXMtYXBwL2Zyb250ZW5kL3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSBcInZpdGVcIjtcclxuaW1wb3J0IHsgc3ZlbHRlIH0gZnJvbSBcIkBzdmVsdGVqcy92aXRlLXBsdWdpbi1zdmVsdGVcIjtcclxuaW1wb3J0IHN2ZWx0ZVByZXByb2Nlc3MgZnJvbSBcInN2ZWx0ZS1wcmVwcm9jZXNzXCI7XHJcbmltcG9ydCB0c2NvbmZpZ1BhdGhzIGZyb20gJ3ZpdGUtdHNjb25maWctcGF0aHMnXHJcbmltcG9ydCByb3V0aWZ5IGZyb20gJ0Byb3hpL3JvdXRpZnkvdml0ZS1wbHVnaW4nXHJcblxyXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xyXG4gIHBsdWdpbnM6IFtcclxuICAgIHN2ZWx0ZSh7XHJcbiAgICAgIHByZXByb2Nlc3M6IFtcclxuICAgICAgICBzdmVsdGVQcmVwcm9jZXNzKHtcclxuICAgICAgICAgIHR5cGVzY3JpcHQ6IHRydWUsXHJcbiAgICAgICAgfSksXHJcbiAgICAgIF0sXHJcbiAgICAgIG9ud2FybjogKHdhcm5pbmcsIGhhbmRsZXIpID0+IHtcclxuICAgICAgICBjb25zdCB7IGNvZGUsIGZyYW1lIH0gPSB3YXJuaW5nO1xyXG4gICAgICAgIGlmIChjb2RlID09PSBcImNzcy11bnVzZWQtc2VsZWN0b3JcIilcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgICBoYW5kbGVyKHdhcm5pbmcpO1xyXG4gICAgICB9LFxyXG4gICAgfSksXHJcbiAgICByb3V0aWZ5KCksXHJcbiAgICB0c2NvbmZpZ1BhdGhzKClcclxuICBdLFxyXG5cclxuICBjbGVhclNjcmVlbjogZmFsc2UsXHJcbiAgc2VydmVyOiB7XHJcbiAgICBwb3J0OiAxNDIwLFxyXG4gICAgc3RyaWN0UG9ydDogdHJ1ZSxcclxuICB9LFxyXG4gIGVudlByZWZpeDogW1wiVklURV9cIiwgXCJUQVVSSV9cIl0sXHJcbiAgYnVpbGQ6IHtcclxuICAgIHRhcmdldDogcHJvY2Vzcy5lbnYuVEFVUklfUExBVEZPUk0gPT0gXCJ3aW5kb3dzXCIgPyBcImNocm9tZTEwNVwiIDogXCJzYWZhcmkxM1wiLFxyXG4gICAgbWluaWZ5OiAhcHJvY2Vzcy5lbnYuVEFVUklfREVCVUcgPyBcImVzYnVpbGRcIiA6IGZhbHNlLFxyXG4gICAgc291cmNlbWFwOiAhIXByb2Nlc3MuZW52LlRBVVJJX0RFQlVHLFxyXG4gIH0sXHJcbn0pOyJdLAogICJtYXBwaW5ncyI6ICI7QUFBMlEsU0FBUyxvQkFBb0I7QUFDeFMsU0FBUyxjQUFjO0FBQ3ZCLE9BQU8sc0JBQXNCO0FBQzdCLE9BQU8sbUJBQW1CO0FBQzFCLE9BQU8sYUFBYTtBQUVwQixJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTO0FBQUEsSUFDUCxPQUFPO0FBQUEsTUFDTCxZQUFZO0FBQUEsUUFDVixpQkFBaUI7QUFBQSxVQUNmLFlBQVk7QUFBQSxRQUNkLENBQUM7QUFBQSxNQUNIO0FBQUEsTUFDQSxRQUFRLENBQUMsU0FBUyxZQUFZO0FBQzVCLGNBQU0sRUFBRSxNQUFNLE1BQU0sSUFBSTtBQUN4QixZQUFJLFNBQVM7QUFDVDtBQUVKLGdCQUFRLE9BQU87QUFBQSxNQUNqQjtBQUFBLElBQ0YsQ0FBQztBQUFBLElBQ0QsUUFBUTtBQUFBLElBQ1IsY0FBYztBQUFBLEVBQ2hCO0FBQUEsRUFFQSxhQUFhO0FBQUEsRUFDYixRQUFRO0FBQUEsSUFDTixNQUFNO0FBQUEsSUFDTixZQUFZO0FBQUEsRUFDZDtBQUFBLEVBQ0EsV0FBVyxDQUFDLFNBQVMsUUFBUTtBQUFBLEVBQzdCLE9BQU87QUFBQSxJQUNMLFFBQVEsUUFBUSxJQUFJLGtCQUFrQixZQUFZLGNBQWM7QUFBQSxJQUNoRSxRQUFRLENBQUMsUUFBUSxJQUFJLGNBQWMsWUFBWTtBQUFBLElBQy9DLFdBQVcsQ0FBQyxDQUFDLFFBQVEsSUFBSTtBQUFBLEVBQzNCO0FBQ0YsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
|
||||
@@ -1,27 +1,26 @@
|
||||
# Simple python script used to
|
||||
# copy some libraries to the "target" directory
|
||||
# after Rust build
|
||||
|
||||
# Note that Rust build should be run via "cargo make <cmd>" command
|
||||
# in order to automate all the compile process
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
# some config vars
|
||||
# format: (source, destination_name)
|
||||
SOURCE = (
|
||||
"resources/commands/",
|
||||
"resources/vosk/",
|
||||
"resources/lib/",
|
||||
"resources/keywords/",
|
||||
"resources/rustpotter/",
|
||||
"resources/sound/",
|
||||
"lib/windows/amd64/libgcc_s_seh-1.dll",
|
||||
"lib/windows/amd64/libstdc++-6.dll",
|
||||
"lib/windows/amd64/libvosk.dll",
|
||||
"lib/windows/amd64/libvosk.lib",
|
||||
"lib/windows/amd64/libwinpthread-1.dll"
|
||||
("resources/commands/", "resources/commands/"),
|
||||
("resources/vosk/", "resources/vosk/"),
|
||||
("resources/lib/", "lib/"),
|
||||
("resources/keywords/", "resources/keywords/"),
|
||||
("resources/rustpotter/", "resources/rustpotter/"),
|
||||
("resources/sound/", "resources/sound/"),
|
||||
("lib/windows/amd64/libgcc_s_seh-1.dll", None),
|
||||
("lib/windows/amd64/libstdc++-6.dll", None),
|
||||
("lib/windows/amd64/libvosk.dll", None),
|
||||
("lib/windows/amd64/libvosk.lib", None),
|
||||
("lib/windows/amd64/libwinpthread-1.dll", None)
|
||||
)
|
||||
|
||||
TARGET_DIRS = (
|
||||
@@ -39,27 +38,36 @@ for tdir in TARGET_DIRS:
|
||||
continue
|
||||
|
||||
# copy lib files
|
||||
for src in SOURCE:
|
||||
if os.path.isdir(ABS_PATH + src):
|
||||
for entry in SOURCE:
|
||||
if isinstance(entry, tuple):
|
||||
src, dest_name = entry
|
||||
else:
|
||||
src, dest_name = entry, None
|
||||
|
||||
src_path = ABS_PATH + src
|
||||
|
||||
if os.path.isdir(src_path):
|
||||
# copy the whole directory
|
||||
full_target_dir_path = os.path.join(tdir, src)
|
||||
|
||||
target_name = dest_name if dest_name else os.path.basename(src.rstrip('/'))
|
||||
full_target_dir_path = os.path.join(tdir, target_name)
|
||||
|
||||
if os.path.isdir(full_target_dir_path):
|
||||
print("[-] Directory already exists, skipping: ", src)
|
||||
print("[-] Directory already exists, skipping: ", src, "->", target_name)
|
||||
else:
|
||||
shutil.copytree(ABS_PATH + src, os.path.join(tdir, src))
|
||||
shutil.copytree(src_path, full_target_dir_path)
|
||||
print("[+] Directory copied: ", src, "->", target_name)
|
||||
|
||||
print("[+] Directory copied: ", src)
|
||||
elif os.path.isfile(ABS_PATH + src):
|
||||
elif os.path.isfile(src_path):
|
||||
# copy file
|
||||
full_target_file_path = os.path.join(tdir, src)
|
||||
target_name = dest_name if dest_name else os.path.basename(src)
|
||||
full_target_file_path = os.path.join(tdir, target_name)
|
||||
|
||||
if os.path.isfile(full_target_file_path):
|
||||
print("[-] File already exists, skipping: ", src)
|
||||
print("[-] File already exists, skipping: ", src, "->", target_name)
|
||||
else:
|
||||
shutil.copy(ABS_PATH + src, tdir)
|
||||
print("[+] File copied: ", src)
|
||||
shutil.copy(src_path, full_target_file_path)
|
||||
print("[+] File copied: ", src, "->", target_name)
|
||||
else:
|
||||
print("[?] Unknown entity to copy: ", src)
|
||||
|
||||
|
||||
print("Post compile build done.")
|
||||
Reference in New Issue
Block a user