use crate::embeddings::clap::{embedding::Embedding, window::WindowEmbedding};
#[cfg(test)]
mod tests;
pub const LOGIT_SCALE_AUDIO: f32 = 18.661177;
pub const LOGIT_SCALE_TEXT: f32 = 14.285714;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum ScoreMode {
Cosine,
LogitScaled,
}
impl ScoreMode {
#[inline]
fn apply(self, cosine: f32) -> f32 {
match self {
Self::Cosine => cosine,
Self::LogitScaled => cosine * LOGIT_SCALE_AUDIO,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct TextAnchor<'a> {
label: &'a str,
embedding: &'a Embedding,
}
impl<'a> TextAnchor<'a> {
pub const fn new(label: &'a str, embedding: &'a Embedding) -> Self {
Self { label, embedding }
}
#[inline]
pub const fn label(&self) -> &'a str {
self.label
}
#[inline]
pub const fn embedding(&self) -> &'a Embedding {
self.embedding
}
}
#[derive(Debug, Clone, Copy)]
pub struct LabeledScore<'a> {
label: &'a str,
score: f32,
}
impl<'a> LabeledScore<'a> {
#[inline]
pub const fn label(&self) -> &'a str {
self.label
}
#[inline]
pub const fn score(&self) -> f32 {
self.score
}
pub fn to_owned(&self) -> LabeledScoreOwned {
LabeledScoreOwned {
label: self.label.to_string(),
score: self.score,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct LabeledScoreOwned {
label: String,
score: f32,
}
impl LabeledScoreOwned {
#[inline]
pub fn label(&self) -> &str {
&self.label
}
#[inline]
pub const fn score(&self) -> f32 {
self.score
}
#[inline]
pub fn into_label(self) -> String {
self.label
}
}
#[must_use]
pub fn score<'a>(
audio: &Embedding,
anchors: &[TextAnchor<'a>],
mode: ScoreMode,
) -> Vec<LabeledScore<'a>> {
let mut out: Vec<LabeledScore<'a>> = anchors
.iter()
.map(|a| LabeledScore {
label: a.label(),
score: mode.apply(audio.cosine(a.embedding())),
})
.collect();
out.sort_by(|x, y| {
y.score
.partial_cmp(&x.score)
.unwrap_or(std::cmp::Ordering::Equal)
});
out
}
#[must_use]
pub fn score_windows<'a>(
windows: &[WindowEmbedding],
anchors: &[TextAnchor<'a>],
mode: ScoreMode,
) -> Vec<Vec<LabeledScore<'a>>> {
windows
.iter()
.map(|w| score(w.value(), anchors, mode))
.collect()
}