#![allow(clippy::unwrap_used, clippy::expect_used)]
use audio_cpp::{Backend, Registry, Request, StreamingSession, 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,
audio_cpp::ModelFamily::from_path(model_path),
None,
)?;
let wav = load_wav(wav_path)?;
println!(
"音频: {}Hz {}ch {}采样",
wav.sample_rate,
wav.channels,
wav.samples.len()
);
let stream = StreamingSession::from_model(
&model,
TaskKind::Asr,
Backend::Cpu,
0, 4, None,
)?;
println!(
"会话: family={} task={} mode={}",
stream.session().family(),
stream.session().task_kind(),
stream.session().run_mode()
);
let policy = stream.session().streaming_policy()?;
println!("流式策略: {:?}", policy);
stream.start(Request::asr(wav_path).option("audio_chunk_seconds", 3.0))?;
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 partial = Vec::<String>::new();
let mut pos = 0usize;
let mut start_sample = 0i64;
while pos < wav.samples.len() {
let end = (pos + chunk).min(wav.samples.len());
let events = stream.push_audio(
&wav.samples[pos..end],
wav.sample_rate,
wav.channels,
start_sample,
)?;
for ev in &events {
if let Some(t) = &ev.partial_text {
partial.push(t.text.clone());
}
}
let block_len = (end - pos) as i64;
pos = end;
start_sample += block_len;
}
let result = stream.finish()?;
stream.reset();
println!("=== 部分转录 ===");
for t in &partial {
println!(" {t}");
}
println!("=== 最终转录 ===");
match &result.text_output {
Some(t) => println!(" {}(语言: {})", t.text, t.language),
None => println!(" (无文本输出;报告信息: {result:?})"),
}
Ok(())
}