Isolate speech transport failures and keep experimental media usable

This commit is contained in:
karl committed 2026-10-13 21:09:43 +02:00
1 parent f15ee07ed0
commit 296a39a6c2
7 files changed
+147 -3

No files matched your search

+61
View File
@@ -24,6 +24,10 @@ pub trait SpeechProvider: Send {
fn admission_us(&self) -> u64 {
0
}
/// Starts a new source without retrying a failed window from the previous source.
fn begin_source(&mut self) -> Result<()> {
Ok(())
}
fn transcribe(&mut self, pcm: &[f32], sample_rate: u32) -> Result<SpeechTranscription>;
}
@@ -31,6 +35,9 @@ impl SpeechProvider for searchi_speech::SpeechWorker {
fn fingerprint(&self) -> &str {
searchi_speech::SpeechWorker::fingerprint(self)
}
fn begin_source(&mut self) -> Result<()> {
searchi_speech::SpeechWorker::begin_source(self)
}
fn transcribe(&mut self, pcm: &[f32], sample_rate: u32) -> Result<SpeechTranscription> {
searchi_speech::SpeechWorker::transcribe(self, pcm, sample_rate)
}
@@ -58,6 +65,13 @@ impl SpeechProvider for BudgetedSpeechProvider {
fn admission_us(&self) -> u64 {
self.admission_us
}
fn begin_source(&mut self) -> Result<()> {
let start = std::time::Instant::now();
let permit = self.budget.acquire(InferenceRole::Background, 1);
self.admission_us = start.elapsed().as_micros().min(u64::MAX as u128) as u64;
let _permit = permit?;
self.inner.begin_source()
}
fn transcribe(&mut self, pcm: &[f32], sample_rate: u32) -> Result<SpeechTranscription> {
let start = std::time::Instant::now();
let permit = self.budget.acquire(InferenceRole::Background, 1);
@@ -275,6 +289,10 @@ impl HybridSearch {
let filename = path.file_name().unwrap_or_default().to_string_lossy();
let mut ordinal = 0usize;
if metadata.has_audio {
self.speech
.as_mut()
.ok_or_else(|| anyhow::anyhow!("Speech provider unavailable"))?
.begin_source()?;
for window in speech_windows(metadata.audio_start_ms, metadata.audio_end_ms)? {
let pcm = decode_audio_aligned(tools, path, window, limits)?;
let provider = self
@@ -372,6 +390,49 @@ impl HybridSearch {
mod tests {
use super::*;
#[test]
fn new_source_recovers_provider_without_retrying_failed_window() -> Result<()> {
struct SourceProvider {
sources: usize,
calls: usize,
failed: bool,
}
impl SpeechProvider for SourceProvider {
fn fingerprint(&self) -> &str {
"lifecycle-test"
}
fn begin_source(&mut self) -> Result<()> {
self.sources += 1;
self.failed = false;
Ok(())
}
fn transcribe(&mut self, _: &[f32], _: u32) -> Result<SpeechTranscription> {
self.calls += 1;
if self.sources == 1 || self.failed {
self.failed = true;
anyhow::bail!("first source transport failure");
}
Ok(SpeechTranscription {
passages: Vec::new(),
metrics: SpeechMetrics::default(),
})
}
}
let mut provider = SourceProvider {
sources: 0,
calls: 0,
failed: false,
};
provider.begin_source()?;
let first_failure = provider.transcribe(&[0.], 16000).unwrap_err().to_string();
assert_eq!(provider.calls, 1, "failed PCM is never retried");
provider.begin_source()?;
provider.transcribe(&[0.], 16000)?;
assert_eq!(provider.calls, 2);
assert_eq!(provider.sources, 2);
assert_eq!(first_failure, "first source transport failure");
Ok(())
}
#[test]
fn point_spans_are_legal_and_invalid_native_evidence_is_rejected() -> Result<()> {
let mut result = SpeechTranscription {
passages: vec![SpeechPassage {