vosk model selection in GUI

This commit is contained in:
Priler 2026-01-05 03:38:04 +05:00
parent 36acacf259
commit cab53abcbe
14 changed files with 323 additions and 40 deletions

View 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
}
}