feat(diarization): Diarizer::diarize_samples + short-input guard for masked far-side pass (FR-SPK)
This commit is contained in:
1 parent
6d4204fb22
commit
51f5ff085c
1 file changed
+21
@@ -23,6 +23,11 @@ pub enum DiarError {
|
||||
pub trait Diarizer: Send + Sync {
|
||||
/// Partition audio into speaker spans.
|
||||
fn diarize(&self, wav: &Path) -> Result<Vec<SpeakerSpan>, DiarError>;
|
||||
/// Partition already-loaded 16kHz mono samples into speaker spans. Phase 3
|
||||
/// (FR-SPK) diarizes a *masked* far-side signal (the mic's "You" ranges
|
||||
/// zeroed), so the caller loads and masks the samples itself rather than
|
||||
/// pointing at the raw WAV.
|
||||
fn diarize_samples(&self, samples: Vec<f32>) -> Result<Vec<SpeakerSpan>, DiarError>;
|
||||
/// Assign speaker labels to transcript segments by overlap with spans.
|
||||
fn assign(&self, segments: &mut [TranscriptSegment], spans: &[SpeakerSpan]);
|
||||
}
|
||||
@@ -92,6 +97,16 @@ impl Diarizer for SherpaDiarizer {
|
||||
fn diarize(&self, wav: &Path) -> Result<Vec<SpeakerSpan>, DiarError> {
|
||||
let samples =
|
||||
crate::audio::read_wav_mono_16k(wav).map_err(|e| DiarError::Run(e.to_string()))?;
|
||||
self.diarize_samples(samples)
|
||||
}
|
||||
|
||||
fn diarize_samples(&self, samples: Vec<f32>) -> Result<Vec<SpeakerSpan>, DiarError> {
|
||||
// Guard the native FFI against degenerate input (a fully-masked far side
|
||||
// is all zeros; a tiny buffer has no usable window). sherpa can crash
|
||||
// rather than error on these, so skip cleanly instead.
|
||||
if samples.len() < MIN_DIARIZE_SAMPLES {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
let mut engine = self.engine.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let segments = engine
|
||||
.compute(samples, None)
|
||||
@@ -116,6 +131,12 @@ impl Diarizer for SherpaDiarizer {
|
||||
#[cfg(feature = "diarization")]
|
||||
const MIN_SPAN_MS: u64 = 700;
|
||||
|
||||
/// Below this many 16kHz samples (~1s) the diarizer skips the sherpa FFI: a
|
||||
/// fully-masked far side is all zeros and a tiny buffer has no usable
|
||||
/// segmentation window, either of which can crash the native code.
|
||||
#[cfg(feature = "diarization")]
|
||||
const MIN_DIARIZE_SAMPLES: usize = 16_000;
|
||||
|
||||
/// A span is kept only if it lasts at least [`MIN_SPAN_MS`].
|
||||
#[cfg(feature = "diarization")]
|
||||
fn span_long_enough(span: &SpeakerSpan) -> bool {
|
||||
|
||||
Reference in new issue
Block a user