use crate::audio::AudioFeatures;
use log::{debug, info};
use ndarray::{Array2, Array3, Ix2};
use std::path::Path;
use log::warn;
use ort::inputs;
use ort::session::builder::SessionBuilder;
use ort::session::{Session, SessionOutputs};
use ort::value::Tensor;
pub struct Model {
pub model_name: String,
pub session: Session,
threshold: f32,
}
impl Model {
pub(crate) fn detect(&mut self, embeddings: &Array2<f32>) -> (bool, f32) {
let s = convert_array_shape(embeddings);
let out = self.session.run(inputs![Tensor::from_array(s).unwrap()]).unwrap();
let probability = get_probability(out);
(probability > self.threshold, probability)
}
pub fn new(model_path: &Path, threshold: f32) -> Model {
let session = SessionBuilder::new().unwrap()
.with_intra_threads(1).unwrap() .with_inter_threads(1).unwrap()
.commit_from_file(model_path)
.unwrap();
Model {
model_name: model_path.to_str().unwrap().to_string(),
session,
threshold,
}
}
pub(crate) fn detection(&mut self, mut audio: &mut AudioFeatures, continues_buffer: &Vec<f32>) -> Result<(bool, f32), String> {
let embeddings = audio.get_audio_features(continues_buffer.clone())?;
let (detected, prc) = self.detect(&embeddings);
if detected {
let detection_prc = (prc * 100.0) as u32;
info!("Detected {}%", detection_prc);
}
Ok((detected, prc))
}
}
fn get_probability(out: SessionOutputs) -> f32 {
for v in out.values() {
let array1 = v.try_extract_array::<f32>().unwrap();
let array2 = array1.into_dimensionality::<Ix2>().unwrap();
return match array2.as_slice() {
None => {
warn!("No prob from model");
0.0
}
Some(p) if p.len() == 1 => {
p[0]
}
_ => {
warn!("Invalid output from model");
0.0
}
};
}
warn!("No values probability found from model");
0.0
}
fn convert_array_shape(input: &Array2<f32>) -> Array3<f32> {
assert_eq!(input.shape(), &[41, 96], "Input array must be shape (41,96)");
let mut output = Array3::<f32>::zeros((1, 16, 96));
let offset = 41 - 16;
for i in offset..41 {
for j in 0..96 {
output[[0, i - (offset), j]] = input[[i, j]];
}
}
output
}