@@ -22,35 +22,58 @@ use std::path::{Path, PathBuf};
2222use std:: process:: ExitCode ;
2323
2424mod asr_eval_session;
25+ mod asr_eval_stream;
2526
2627use app_lib:: audio_preprocess:: { AudioPreprocessConfig , AudioPreprocessor } ;
2728use app_lib:: cer;
2829use app_lib:: eval_confusion:: { profile, ConfusionAggregator } ;
2930use app_lib:: eval_report:: { ab_verdict, cer_stats, is_regression, CerStats } ;
3031use app_lib:: eval_samples:: { is_media_file, parse_srt, reference_text, srt_path_for} ;
32+ use asr_eval_stream:: { transcribe_stream, StreamParams } ;
3133use sherpa_onnx:: { OfflineRecognizer , OfflineRecognizerConfig , OfflineSenseVoiceModelConfig } ;
3234
3335/// 默认 SenseVoice 模型目录(与 cer_bench/download 脚本约定一致)。
3436const DEFAULT_MODEL_DIR : & str = "models/asr/sensevoice" ;
37+ /// 流式 zipformer 模型目录(与 streaming 下载脚本约定一致)。
38+ const STREAM_MODEL_DEFAULT : & str = "models/asr/streaming-zipformer-zh-fp16-2025-06-30" ;
3539/// 基线回归容差(v0.20.0 契约:相对基线均值 CER 退化 >2% 即失败)。
3640const REGRESSION_TOLERANCE : f32 = 0.02 ;
3741
38- /// A/B 路选择。
42+ /// A/B 路选择 + 流式档(序 2:stream 为附加被测路径) 。
3943#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
4044enum Route {
4145 Off ,
4246 On ,
4347 Both ,
48+ Stream ,
4449}
4550
4651impl Route {
47- fn names ( & self ) -> Vec < & ' static str > {
52+ fn label ( & self ) -> & ' static str {
4853 match self {
49- Route :: Off => vec ! [ "preproc_off" ] ,
50- Route :: On => vec ! [ "preproc_on" ] ,
51- Route :: Both => vec ! [ "preproc_off" , "preproc_on" ] ,
54+ Route :: Off => "preproc_off" ,
55+ Route :: On => "preproc_on" ,
56+ Route :: Both => unreachable ! ( "Both 是组合态,不入单行标签" ) ,
57+ Route :: Stream => "stream" ,
5258 }
5359 }
60+
61+ fn steps ( preproc : Route , stream : bool ) -> Vec < Route > {
62+ let mut v = Vec :: new ( ) ;
63+ match preproc {
64+ Route :: Off => v. push ( Route :: Off ) ,
65+ Route :: On => v. push ( Route :: On ) ,
66+ Route :: Both => {
67+ v. push ( Route :: Off ) ;
68+ v. push ( Route :: On ) ;
69+ }
70+ Route :: Stream => { }
71+ }
72+ if stream {
73+ v. push ( Route :: Stream ) ;
74+ }
75+ v
76+ }
5477}
5578
5679#[ derive( Debug ) ]
@@ -63,6 +86,10 @@ struct Options {
6386 baseline : Option < PathBuf > ,
6487 update_baseline : bool ,
6588 preproc : Route ,
89+ /// 流式档开关 + 模型目录 + 端点规则覆盖(REQ-265 参数注入面)。
90+ stream : bool ,
91+ stream_model : String ,
92+ stream_params : StreamParams ,
6693}
6794
6895/// 单样本(文件对信道)。
@@ -116,16 +143,27 @@ fn main() -> ExitCode {
116143 continue ;
117144 } ;
118145 let ( sr, samples_f32) = ( wave. sample_rate ( ) , wave. samples ( ) ) ;
119- for route in opts. preproc . names ( ) {
120- let preproc_on = route == "preproc_on" ;
121- let text = transcribe ( & recognizer, samples_f32, sr, preproc_on) ;
146+ for route in Route :: steps ( opts. preproc , opts. stream ) {
147+ let text = match route {
148+ Route :: Off => transcribe ( & recognizer, samples_f32, sr, false ) ,
149+ Route :: On => transcribe ( & recognizer, samples_f32, sr, true ) ,
150+ Route :: Stream => {
151+ // 流式档自读音频(独立引擎),模型缺失 → None 提示后跳过该路
152+ match transcribe_stream ( & s. wav . to_string_lossy ( ) , & opts. stream_model , & opts. stream_params ) {
153+ Some ( t) => t,
154+ None => continue ,
155+ }
156+ }
157+ Route :: Both => unreachable ! ( ) ,
158+ } ;
159+ let label = route. label ( ) ;
122160 let c = cer:: cer ( & s. reference , & text) ;
123- rows. push ( ( s. name . clone ( ) , route . to_string ( ) , c) ) ;
161+ rows. push ( ( s. name . clone ( ) , label . to_string ( ) , c) ) ;
124162 if let Some ( v) = c {
125- cers. entry ( route . to_string ( ) ) . or_default ( ) . push ( v) ;
163+ cers. entry ( label . to_string ( ) ) . or_default ( ) . push ( v) ;
126164 }
127165 portraits
128- . entry ( route . to_string ( ) )
166+ . entry ( label . to_string ( ) )
129167 . or_default ( )
130168 . add ( & profile ( & s. reference , & text) ) ;
131169 }
@@ -141,7 +179,15 @@ fn main() -> ExitCode {
141179 None => out. push_str ( & format ! ( "{name}\t {route}\t -\n " ) ) ,
142180 }
143181 }
144- for route in opts. preproc . names ( ) {
182+ // 汇总:按路统计(含 stream 档;Both 展开为两路后此处用单一路集合遍历)
183+ let mut route_labels: Vec < & ' static str > = Vec :: new ( ) ;
184+ for r in Route :: steps ( opts. preproc , false ) {
185+ route_labels. push ( r. label ( ) ) ;
186+ }
187+ if opts. stream {
188+ route_labels. push ( "stream" ) ;
189+ }
190+ for route in route_labels {
145191 let stats = cer_stats ( cers. get ( route) . map ( |v| v. as_slice ( ) ) . unwrap_or ( & [ ] ) ) ;
146192 out. push_str ( & format ! (
147193 "\n [{}] 样本={} CER均值={} 范围={}~{}" ,
@@ -177,7 +223,7 @@ fn main() -> ExitCode {
177223 let _ = fs:: write ( opts. out_dir . join ( "summary.txt" ) , & out) ;
178224
179225 // ── 基线回归门 ──
180- let primary = cers. get ( "preproc_off" ) . map ( |v| cer_stats ( v) ) . flatten ( ) ;
226+ let primary = cers. get ( "preproc_off" ) . and_then ( |v| cer_stats ( v) ) ;
181227 if let Some ( bp) = & opts. baseline {
182228 let cur = primary. map ( |s| s. mean ) ;
183229 let base_mean = read_baseline_mean ( bp) ;
@@ -273,6 +319,9 @@ fn parse_args() -> Option<Options> {
273319 let mut baseline = None ;
274320 let mut update_baseline = false ;
275321 let mut preproc = Route :: Both ;
322+ let mut stream = false ;
323+ let mut stream_model = STREAM_MODEL_DEFAULT . to_string ( ) ;
324+ let mut stream_params = StreamParams :: default ( ) ;
276325 let mut it = args. iter ( ) ;
277326 while let Some ( a) = it. next ( ) {
278327 match a. as_str ( ) {
@@ -288,6 +337,11 @@ fn parse_args() -> Option<Options> {
288337 . collect ( ) ,
289338 ) ;
290339 }
340+ "--stream" => stream = true ,
341+ "--stream-model" => stream_model = it. next ( ) ?. clone ( ) ,
342+ "--rule1-s" => stream_params. rule1_s = it. next ( ) ?. parse ( ) . ok ( ) ?,
343+ "--rule2-s" => stream_params. rule2_s = it. next ( ) ?. parse ( ) . ok ( ) ?,
344+ "--rule3-s" => stream_params. rule3_s = it. next ( ) ?. parse ( ) . ok ( ) ?,
291345 "--update-baseline" => update_baseline = true ,
292346 "--preproc" => {
293347 preproc = match it. next ( ) ?. as_str ( ) {
@@ -313,6 +367,9 @@ fn parse_args() -> Option<Options> {
313367 baseline,
314368 update_baseline,
315369 preproc,
370+ stream,
371+ stream_model,
372+ stream_params,
316373 } )
317374}
318375
0 commit comments