#![allow(clippy::unwrap_used, clippy::expect_used)]
use std::sync::{Arc, Mutex};
use audio_cpp::{
Backend, ModelFamily, Registry, Request, RunMode, StreamEvent, TaskKind, load_wav,
};
fn main() -> Result<(), audio_cpp::Error> {
let args: Vec<String> = std::env::args().collect();
if args.len() < 3 {
eprintln!("用法: asr_streaming <qwen3-asr-q8_0.gguf> <input.wav>");
std::process::exit(1);
}
let model_path = &args[1];
let wav_path = &args[2];
let registry = Registry::new()?;
println!("模型族: {:?}", registry.families()?);
let model = registry.load(model_path, Some(ModelFamily::Qwen3Asr), None)?;
let wav = load_wav(wav_path)?;
println!(
"音频: {}Hz {}ch {}采样",
wav.sample_rate,
wav.channels,
wav.samples.len()
);
let mut session = model.create_task_session(
TaskKind::Asr,
RunMode::Streaming,
Backend::Cpu,
0, 4, None,
)?;
println!(
"会话: family={} task={} mode={}",
session.family(),
session.task_kind(),
session.run_mode()
);
let policy = session.streaming_policy()?;
println!("流式策略: {:?}", policy);
let partial = Arc::new(Mutex::new(Vec::<String>::new()));
let collector = Arc::clone(&partial);
session.set_event_callback(Some(move |event: StreamEvent| {
if let Some(t) = &event.partial_text {
collector.lock().unwrap().push(t.text.clone());
}
}));
let request = Request::asr(wav_path).option("audio_chunk_seconds", 3.0);
println!("请求: {}", request.to_json()?);
session.start(request)?;
let chunk = if policy.preferred_audio_chunk_samples > 0 {
policy.preferred_audio_chunk_samples
} else if policy.preferred_audio_chunk_seconds > 0.0 {
(policy.preferred_audio_chunk_seconds * wav.sample_rate as f64).round() as usize
} else {
512
};
let mut pos = 0usize;
let mut start_sample = 0i64;
while pos < wav.samples.len() {
let end = (pos + chunk).min(wav.samples.len());
session.process_audio(
&wav.samples[pos..end],
wav.sample_rate,
wav.channels,
start_sample,
)?;
let block_len = (end - pos) as i64;
pos = end;
start_sample += block_len;
}
let result = session.finish()?;
session.reset();
let partial = partial.lock().unwrap();
println!("=== 部分转录 ===");
for t in partial.iter() {
println!(" {t}");
}
println!("=== 最终转录 ===");
match &result.text_output {
Some(t) => println!(" {}(语言: {})", t.text, t.language),
None => println!(" (无文本输出;报告信息: {result:?})"),
}
Ok(())
}