use std::sync::{Arc, Mutex};
use audio_cpp::{load_wav, Backend, ModelFamily, Registry, RunMode, StreamEvent, TaskKind};
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 = format!(
r#"{{"audio_path":"{}","options":{{"audio_chunk_seconds":3.0}}}}"#,
wav_path.replace('\\', "\\\\").replace('"', "\\\"")
);
println!("请求: {request}");
session.start(Some(&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(())
}