vosk usage optimization
This commit is contained in:
parent
75edd47d18
commit
bd8e2c989d
6 changed files with 305 additions and 108 deletions
|
|
@ -9,80 +9,154 @@ use crate::stt::vosk_models;
|
|||
use crate::DB;
|
||||
|
||||
static MODEL: OnceCell<Model> = OnceCell::new();
|
||||
static RECOGNIZER: OnceCell<Mutex<Recognizer>> = OnceCell::new();
|
||||
static WAKE_RECOGNIZER: OnceCell<Mutex<Recognizer>> = OnceCell::new();
|
||||
static SPEECH_RECOGNIZER: OnceCell<Mutex<Recognizer>> = OnceCell::new();
|
||||
|
||||
pub fn init_vosk() -> Result<(), String> {
|
||||
if RECOGNIZER.get().is_some() {
|
||||
if MODEL.get().is_some() {
|
||||
return Ok(());
|
||||
} // already initialized
|
||||
|
||||
let model_path = get_configured_model_path()?;
|
||||
info!("Loading Vosk model from: {}", model_path.display());
|
||||
|
||||
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")?;
|
||||
//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)
|
||||
.ok_or("Failed to create wake word recognizer")?;
|
||||
|
||||
recognizer.set_max_alternatives(10);
|
||||
recognizer.set_words(true);
|
||||
recognizer.set_partial_words(true);
|
||||
wake_recognizer.set_max_alternatives(1); // required for confidence check later on
|
||||
|
||||
MODEL.set(model);
|
||||
RECOGNIZER.set(Mutex::new(recognizer));
|
||||
let mut speech_recognizer = Recognizer::new(&model, 16000.0)
|
||||
.ok_or("Failed to create speech recognizer")?;
|
||||
|
||||
speech_recognizer.set_max_alternatives(config::VOSK_SPEECH_RECOGNIZER_MAX_ALTERNATIVES);
|
||||
speech_recognizer.set_words(config::VOSK_SPEECH_RECOGNIZER_WORDS);
|
||||
speech_recognizer.set_partial_words(config::VOSK_SPEECH_PARTIAL_WORDS);
|
||||
|
||||
MODEL.set(model).map_err(|_| "Model already set")?;
|
||||
WAKE_RECOGNIZER.set(Mutex::new(wake_recognizer)).map_err(|_| "Wake recognizer already set")?;
|
||||
SPEECH_RECOGNIZER.set(Mutex::new(speech_recognizer)).map_err(|_| "Speech recognizer already set")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn recognize(data: &[i16], include_partial: bool) -> Option<String> {
|
||||
let state = RECOGNIZER
|
||||
.get()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.accept_waveform(data);
|
||||
|
||||
match state {
|
||||
Ok(ds) => {
|
||||
match ds {
|
||||
DecodingState::Running => {
|
||||
if include_partial {
|
||||
Some(
|
||||
RECOGNIZER
|
||||
.get()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.partial_result()
|
||||
.partial
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
pub fn recognize_wake_word(data: &[i16]) -> Option<(String, f32)> {
|
||||
let mut recognizer = WAKE_RECOGNIZER.get()?.lock().unwrap();
|
||||
|
||||
match recognizer.accept_waveform(data) {
|
||||
Ok(DecodingState::Running) => {
|
||||
// partials don't have confidence, skip them
|
||||
None
|
||||
}
|
||||
Ok(DecodingState::Finalized) => {
|
||||
let result = recognizer.result();
|
||||
|
||||
// compensate confidence issues
|
||||
if let Some(alternatives) = result.multiple() {
|
||||
if let Some(best) = alternatives.alternatives.first() {
|
||||
if !best.text.is_empty() {
|
||||
return Some((best.text.to_string(), best.confidence));
|
||||
}
|
||||
}
|
||||
DecodingState::Finalized => {
|
||||
// Result will always be multiple because we called set_max_alternatives
|
||||
RECOGNIZER
|
||||
.get()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.result()
|
||||
.multiple()
|
||||
.and_then(|m| m.alternatives.first().map(|a| a.text.to_string()))
|
||||
}
|
||||
DecodingState::Failed => None,
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
error!("Vosk accept waveform error.\nError details: {}", err);
|
||||
|
||||
None
|
||||
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn recognize_speech(data: &[i16]) -> Option<String> {
|
||||
let mut recognizer = SPEECH_RECOGNIZER.get()?.lock().unwrap();
|
||||
|
||||
match recognizer.accept_waveform(data) {
|
||||
Ok(DecodingState::Finalized) => {
|
||||
recognizer.result()
|
||||
.multiple()
|
||||
.and_then(|m| m.alternatives.first().map(|a| a.text.to_string()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn reset_speech_recognizer() {
|
||||
if let Some(recognizer) = SPEECH_RECOGNIZER.get() {
|
||||
recognizer.lock().unwrap().reset();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_wake_recognizer() {
|
||||
if let Some(recognizer) = WAKE_RECOGNIZER.get() {
|
||||
recognizer.lock().unwrap().reset();
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn recognize(data: &[i16], include_partial: bool) -> Option<String> {
|
||||
// let state = RECOGNIZER
|
||||
// .get()
|
||||
// .unwrap()
|
||||
// .lock()
|
||||
// .unwrap()
|
||||
// .accept_waveform(data);
|
||||
|
||||
// match state {
|
||||
// Ok(ds) => {
|
||||
// match ds {
|
||||
// DecodingState::Running => {
|
||||
// if include_partial {
|
||||
// Some(
|
||||
// RECOGNIZER
|
||||
// .get()
|
||||
// .unwrap()
|
||||
// .lock()
|
||||
// .unwrap()
|
||||
// .partial_result()
|
||||
// .partial
|
||||
// .into(),
|
||||
// )
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
// DecodingState::Finalized => {
|
||||
// // Result will always be multiple because we called set_max_alternatives
|
||||
// RECOGNIZER
|
||||
// .get()
|
||||
// .unwrap()
|
||||
// .lock()
|
||||
// .unwrap()
|
||||
// .result()
|
||||
// .multiple()
|
||||
// .and_then(|m| m.alternatives.first().map(|a| a.text.to_string()))
|
||||
// }
|
||||
// DecodingState::Failed => None,
|
||||
// }
|
||||
// },
|
||||
// Err(err) => {
|
||||
// error!("Vosk accept waveform error.\nError details: {}", err);
|
||||
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
fn get_configured_model_path() -> Result<std::path::PathBuf, String> {
|
||||
// try to get from settings
|
||||
if let Some(db) = DB.get() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue