use crate::ComputeUnits;
use crate::audio::whisper::{
options::{ComputeOptions, DecodingOptions},
result::{TranscriptionResult, TranscriptionSegment},
task_facts::TaskFacts,
};
#[cfg(test)]
mod tests;
fn unanimous_temperature(segments: &[TranscriptionSegment]) -> Option<f32> {
let first = segments.first()?.temperature();
segments
.iter()
.all(|segment| segment.temperature() == first)
.then_some(first)
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Provenance {
decoding: DecodingOptions,
compute: ComputeOptions,
#[cfg_attr(
feature = "serde",
serde(with = "crate::audio::whisper::options::finite_f32_option")
)]
effective_temperature: Option<f32>,
task_facts: TaskFacts,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
model_id: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
model_revision: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
tokenizer_id: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
tokenizer_revision: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
vad_detector: Option<String>,
}
macro_rules! provenance_field_names {
($($field:ident),+ $(,)?) => {
#[cfg(test)]
#[allow(dead_code)] pub(crate) const PROVENANCE_FIELD_NAMES: &[&str] = &[$(stringify!($field)),+];
#[cfg(test)]
#[allow(dead_code)]
fn _provenance_field_exhaustiveness_guard(provenance: Provenance) {
let Provenance { $($field: _),+ } = provenance;
}
};
}
provenance_field_names!(
decoding,
compute,
effective_temperature,
task_facts,
model_id,
model_revision,
tokenizer_id,
tokenizer_revision,
vad_detector,
);
impl Provenance {
fn capture(
decoding: &DecodingOptions,
compute: &ComputeOptions,
effective_temperature: Option<f32>,
task_facts: TaskFacts,
) -> Self {
Self {
decoding: decoding.clone(),
compute: *compute,
effective_temperature,
task_facts,
model_id: None,
model_revision: None,
tokenizer_id: None,
tokenizer_revision: None,
vad_detector: None,
}
}
pub fn from_options(
decoding: &DecodingOptions,
compute: &ComputeOptions,
effective_temperature: f32,
sampled_at_nonzero_temperature: bool,
) -> Self {
Self::capture(
decoding,
compute,
Some(effective_temperature),
TaskFacts::unknown().with_drew_from_rng(sampled_at_nonzero_temperature),
)
}
pub fn for_segment(
decoding: &DecodingOptions,
compute: &ComputeOptions,
segment: &TranscriptionSegment,
sampled_at_nonzero_temperature: bool,
) -> Self {
Self::from_options(
decoding,
compute,
segment.temperature(),
sampled_at_nonzero_temperature,
)
}
pub fn for_result(
decoding: &DecodingOptions,
compute: &ComputeOptions,
result: &TranscriptionResult,
) -> Self {
Self::capture(
decoding,
compute,
unanimous_temperature(result.segments_slice()),
result.task_facts().clone(),
)
}
#[inline(always)]
pub const fn decoding(&self) -> &DecodingOptions {
&self.decoding
}
#[inline(always)]
pub const fn compute(&self) -> ComputeOptions {
self.compute
}
#[inline(always)]
pub const fn encoder_compute_units(&self) -> ComputeUnits {
self.compute.encoder()
}
#[inline(always)]
pub const fn effective_temperature(&self) -> Option<f32> {
self.effective_temperature
}
#[inline(always)]
pub const fn task_facts(&self) -> &TaskFacts {
&self.task_facts
}
#[inline(always)]
pub const fn is_reproducible(&self) -> bool {
self
.task_facts
.is_reproducible_under(self.decoding.seed().is_some())
}
#[inline(always)]
pub fn model_id(&self) -> Option<&str> {
self.model_id.as_deref()
}
#[must_use]
#[inline(always)]
pub fn with_model_id(mut self, model_id: impl Into<String>) -> Self {
self.set_model_id(model_id);
self
}
#[inline(always)]
pub fn set_model_id(&mut self, model_id: impl Into<String>) -> &mut Self {
self.model_id = Some(model_id.into());
self
}
#[must_use]
#[inline(always)]
pub fn maybe_model_id(mut self, model_id: Option<String>) -> Self {
self.update_model_id(model_id);
self
}
#[inline(always)]
pub fn update_model_id(&mut self, model_id: Option<String>) -> &mut Self {
self.model_id = model_id;
self
}
#[inline(always)]
pub fn clear_model_id(&mut self) -> &mut Self {
self.model_id = None;
self
}
#[inline(always)]
pub fn model_revision(&self) -> Option<&str> {
self.model_revision.as_deref()
}
#[must_use]
#[inline(always)]
pub fn with_model_revision(mut self, model_revision: impl Into<String>) -> Self {
self.set_model_revision(model_revision);
self
}
#[inline(always)]
pub fn set_model_revision(&mut self, model_revision: impl Into<String>) -> &mut Self {
self.model_revision = Some(model_revision.into());
self
}
#[must_use]
#[inline(always)]
pub fn maybe_model_revision(mut self, model_revision: Option<String>) -> Self {
self.update_model_revision(model_revision);
self
}
#[inline(always)]
pub fn update_model_revision(&mut self, model_revision: Option<String>) -> &mut Self {
self.model_revision = model_revision;
self
}
#[inline(always)]
pub fn clear_model_revision(&mut self) -> &mut Self {
self.model_revision = None;
self
}
#[inline(always)]
pub fn tokenizer_id(&self) -> Option<&str> {
self.tokenizer_id.as_deref()
}
#[must_use]
#[inline(always)]
pub fn with_tokenizer_id(mut self, tokenizer_id: impl Into<String>) -> Self {
self.set_tokenizer_id(tokenizer_id);
self
}
#[inline(always)]
pub fn set_tokenizer_id(&mut self, tokenizer_id: impl Into<String>) -> &mut Self {
self.tokenizer_id = Some(tokenizer_id.into());
self
}
#[must_use]
#[inline(always)]
pub fn maybe_tokenizer_id(mut self, tokenizer_id: Option<String>) -> Self {
self.update_tokenizer_id(tokenizer_id);
self
}
#[inline(always)]
pub fn update_tokenizer_id(&mut self, tokenizer_id: Option<String>) -> &mut Self {
self.tokenizer_id = tokenizer_id;
self
}
#[inline(always)]
pub fn clear_tokenizer_id(&mut self) -> &mut Self {
self.tokenizer_id = None;
self
}
#[inline(always)]
pub fn tokenizer_revision(&self) -> Option<&str> {
self.tokenizer_revision.as_deref()
}
#[must_use]
#[inline(always)]
pub fn with_tokenizer_revision(mut self, tokenizer_revision: impl Into<String>) -> Self {
self.set_tokenizer_revision(tokenizer_revision);
self
}
#[inline(always)]
pub fn set_tokenizer_revision(&mut self, tokenizer_revision: impl Into<String>) -> &mut Self {
self.tokenizer_revision = Some(tokenizer_revision.into());
self
}
#[must_use]
#[inline(always)]
pub fn maybe_tokenizer_revision(mut self, tokenizer_revision: Option<String>) -> Self {
self.update_tokenizer_revision(tokenizer_revision);
self
}
#[inline(always)]
pub fn update_tokenizer_revision(&mut self, tokenizer_revision: Option<String>) -> &mut Self {
self.tokenizer_revision = tokenizer_revision;
self
}
#[inline(always)]
pub fn clear_tokenizer_revision(&mut self) -> &mut Self {
self.tokenizer_revision = None;
self
}
#[inline(always)]
pub fn vad_detector(&self) -> Option<&str> {
self.vad_detector.as_deref()
}
#[must_use]
#[inline(always)]
pub fn with_vad_detector(mut self, vad_detector: impl Into<String>) -> Self {
self.set_vad_detector(vad_detector);
self
}
#[inline(always)]
pub fn set_vad_detector(&mut self, vad_detector: impl Into<String>) -> &mut Self {
self.vad_detector = Some(vad_detector.into());
self
}
#[must_use]
#[inline(always)]
pub fn maybe_vad_detector(mut self, vad_detector: Option<String>) -> Self {
self.update_vad_detector(vad_detector);
self
}
#[inline(always)]
pub fn update_vad_detector(&mut self, vad_detector: Option<String>) -> &mut Self {
self.vad_detector = vad_detector;
self
}
#[inline(always)]
pub fn clear_vad_detector(&mut self) -> &mut Self {
self.vad_detector = None;
self
}
}