Skip to content

Commit 532f675

Browse files
committed
fix(asr): 流式解码器切换 modified_beam_search(热词 ContextGraph 兼容)
1 parent cd269ca commit 532f675

2 files changed

Lines changed: 47 additions & 0 deletions

File tree

‎app/src-tauri/src/streaming_asr.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ impl StreamingAsrEngine {
122122
// 2025-06-30)依赖 C++ 侧按 transducer 三件套自动推断;
123123
// 误设 zipformer2 会要求 query_head_dims 元数据而崩溃(原项目踩坑)。
124124
recognizer_config.enable_endpoint = true;
125+
// 2026-08-21 热词解码崩溃修复:带 ContextGraph(热词)的流必须用
126+
// modified_beam_search 解码——greedy_search(默认)的 Decode 接口不处理
127+
// 带 graph 的流,断言 abort(exit 0xffffffff,用户真机日志实证 Decode:101);
128+
// 无热词时同样兼容(beam 搜索对普通流无副作用,识别质量相当或更优)。
129+
recognizer_config.decoding_method = Some("modified_beam_search".into());
125130
// 端点规则:尾静音 2.4s / 1.2s 断句(sherpa-onnx 默认),
126131
// rule3 强制断句 = 可配置(ADR-012 F3-1:默认 8s,env 可覆盖)
127132
recognizer_config.rule1_min_trailing_silence = 2.4;

‎app/src-tauri/src/streaming_asr_tests.rs‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,48 @@ fn load_and_feed_streaming_zipformer_integration() {
157157
println!("流式引擎加载与喂入通过(模型目录: {}", base);
158158
}
159159

160+
/// 集成测试:热词 + 流式解码不崩溃(2026-08-21 崩溃回归——领域预热首次注入热词
161+
/// 暴露 greedy_search 解码器不兼容 ContextGraph 流,断言 abort exit 0xffffffff;
162+
/// 修复为 modified_beam_search 后带热词解码正常)。
163+
///
164+
/// @ai-context: 模型目录同 load_and_feed 集成测试;热词表注入领域种子词
165+
/// ("心理/成长"——tokens 全覆盖,编码必然成功——专门验证
166+
/// ContextGraph 流解码路径)。
167+
#[test]
168+
#[ignore = "集成测试:需要真实模型文件(崩溃回归,热词+解码)"]
169+
fn hotwords_streaming_decode_integration() {
170+
use std::sync::{Arc, Mutex};
171+
// Arrange:模型路径(环境变量优先,回退 AppData 默认)
172+
let base = std::env::var("ENTROPY_STREAMING_MODEL_DIR").unwrap_or_else(|_| {
173+
let appdata = std::env::var("APPDATA").expect("APPDATA 环境变量");
174+
format!("{}\\com.entropydecrease.app\\models\\streaming-zipformer", appdata)
175+
});
176+
let p = |name: &str| format!("{}\\{}", base, name);
177+
let models = StreamingAsrModels {
178+
encoder: p("encoder.fp16.onnx"),
179+
decoder: p("decoder.fp16.onnx"),
180+
joiner: p("joiner.fp16.onnx"),
181+
tokens: p("tokens.txt"),
182+
};
183+
// 热词表(REQ-040 通道):领域种子词(tokens 全覆盖——编码必成功)
184+
let vocab: Arc<Mutex<crate::vocab::VocabStore>> =
185+
Arc::new(Mutex::new(crate::vocab::VocabStore::default()));
186+
vocab
187+
.lock()
188+
.expect("vocab lock")
189+
.add_hotwords(&["心理".to_string(), "成长".to_string()]);
190+
// Act:加载(带热词 → create_stream_with_hotwords → ContextGraph 流)
191+
let mut engine =
192+
StreamingAsrEngine::load(&models, &StreamingAsrConfig::default(), None, Some(vocab), None)
193+
.expect("流式模型加载成功");
194+
// 喂入合成音频(非静音,走完整 decode 路径——崩溃点:带 graph 流 Decode)
195+
let samples: Vec<f32> = (0..16000).map(|i| ((i % 997) as f32 / 997.0 - 0.5) * 0.2).collect();
196+
let _ = engine.feed(&samples, false);
197+
let _ = engine.flush();
198+
// Assert:不崩溃即通过(热词解码断言 abort 修复回归)
199+
println!("热词流式解码通过(模型目录: {}", base);
200+
}
201+
160202
/// 集成测试:标点恢复模型加载与中文标点补全(ADR-012 F4-2)。
161203
///
162204
/// @ai-context: 模型目录取 ENTROPY_PUNCT_MODEL_DIR 环境变量,默认

0 commit comments

Comments
 (0)