Skip to content

Commit c433485

Browse files
committed
feat(asr): REQ-265 rule3 默认 12s 定案 + REQ-267 排空专用单测
1 parent 07d8cda commit c433485

4 files changed

Lines changed: 45 additions & 7 deletions

File tree

‎app/src-tauri/src/bin/asr_eval_stream.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ pub struct StreamParams {
2727

2828
impl Default for StreamParams {
2929
fn default() -> Self {
30-
Self { rule1_s: 2.4, rule2_s: 1.2, rule3_s: 8.0 }
30+
// rule3 与生产同默认(12s,REQ-265 首轮标定定案 2026-09-05)
31+
Self { rule1_s: 2.4, rule2_s: 1.2, rule3_s: 12.0 }
3132
}
3233
}
3334

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,16 @@ impl EnginePool {
161161
Self::assemble(asr_tx, ocr_tx)
162162
}
163163

164+
/// 测试用:注入 ASR 通道并共享 receiver(REQ-267 排空单测专用——
165+
/// 队列中已有请求时 drain_asr_backlog 应逐条回复 Err 并清空)。
166+
#[cfg(test)]
167+
pub fn with_asr_channel_and_rx(asr_tx: Sender<AsrRequest>, asr_rx: Receiver<AsrRequest>) -> Self {
168+
let (ocr_tx, _) = mpsc::channel::<OcrRequest>();
169+
let mut p = Self::assemble(asr_tx, ocr_tx);
170+
p.asr_rx = Some(Arc::new(Mutex::new(asr_rx)));
171+
p
172+
}
173+
164174
/// 测试装配:计数/状态 Arc 全部归零或默认(start 与测试构造共用,避免重复)。
165175
#[cfg(test)]
166176
fn assemble(asr_tx: Sender<AsrRequest>, ocr_tx: Sender<OcrRequest>) -> Self {
@@ -479,6 +489,29 @@ mod tests {
479489
assert_eq!(pool.rescore_timeout_count(), 1);
480490
}
481491

492+
#[test]
493+
fn drain_asr_backlog_replies_err_and_empties_queue() {
494+
// Arrange:持活 receiver + 队列中 2 个待处理请求(REQ-267:worker 串行
495+
// 慢机下调用方超时后积压——排空必须逐条回复 Err 而非滞留陈旧状态)
496+
let (asr_tx, asr_rx) = mpsc::channel::<AsrRequest>();
497+
let pool = EnginePool::with_asr_channel_and_rx(asr_tx, asr_rx);
498+
let (r1, rr1) = mpsc::channel();
499+
let (r2, rr2) = mpsc::channel();
500+
pool.asr_tx
501+
.send(AsrRequest::TranscribePcm { samples: vec![0.0f32], sample_rate: 16_000, reply: r1 })
502+
.expect("send1");
503+
pool.asr_tx
504+
.send(AsrRequest::Transcribe { path: String::new(), reply: r2 })
505+
.expect("send2");
506+
// Act:排空
507+
pool.drain_asr_backlog();
508+
// Assert:两条积压请求即刻收到可诊断 Err;队列清空后再排为空操作
509+
let e1 = rr1.recv_timeout(std::time::Duration::from_millis(200)).expect("reply1 应即时到达");
510+
let e2 = rr2.recv_timeout(std::time::Duration::from_millis(200)).expect("reply2 应即时到达");
511+
assert!(e1.is_err() && e2.is_err(), "积压请求应收到废弃 Err");
512+
pool.drain_asr_backlog(); // 不 panic(空队列 no-op)
513+
}
514+
482515
#[test]
483516
fn recognize_image_timeout_returns_err_on_bounded_wait() {
484517
// Arrange:持活 receiver 的 OCR 通道——send 成功、recv 必超时(无 worker 应答)

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ pub struct StreamingAsrConfig {
4949
pub rule1_min_trailing_silence: f32,
5050
/// 端点 rule2:短停顿断句秒数(默认 1.2)。
5151
pub rule2_min_trailing_silence: f32,
52-
/// rule3 最长句强制断句(秒;默认 8s——5s 过短致句中硬切,20s 过长)。
52+
/// rule3 最长句强制断句(秒;默认 12s——REQ-265 首轮标定定案:
53+
/// 8s 硬切中长句致句碎,12s 5/5 样本一致更优;20s 仍过长)。
5354
pub rule3_min_utterance_secs: f32,
5455
}
5556

@@ -58,7 +59,9 @@ impl Default for StreamingAsrConfig {
5859
Self {
5960
rule1_min_trailing_silence: 2.4,
6061
rule2_min_trailing_silence: 1.2,
61-
rule3_min_utterance_secs: 8.0,
62+
// REQ-265 首轮标定(2026-09-05,弱参考 5 样本 5/5 一致改善 Δ≈0.029):
63+
// rule3 8s → 12s(8s 硬切中长句;12s 贴合自然语流);用户裁决定案
64+
rule3_min_utterance_secs: 12.0,
6265
}
6366
}
6467
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,13 @@ fn silence_blocks_counter_counts_all_silent_blocks() {
6262
assert_eq!(blocks, 10);
6363
}
6464

65-
// ── rule3 配置(ADR-012 F3-1)──
65+
// ── rule3 配置(ADR-012 F3-1;REQ-265 首轮标定定案 2026-09-05)──
6666

6767
#[test]
68-
fn default_rule3_is_8_seconds() {
69-
// 默认 8s(5s 过短致句中硬切,取证 ADR-012)
70-
assert_eq!(StreamingAsrConfig::default().rule3_min_utterance_secs, 8.0);
68+
fn default_rule3_is_12_seconds_after_calibration() {
69+
// REQ-265 首轮标定(弱参考 5 样本 5/5 一致改善 Δ≈0.029):8s 硬切中长句
70+
// 致句碎,12s 贴合自然语流——用户裁决(2026-09-05)默认 8s → 12s
71+
assert_eq!(StreamingAsrConfig::default().rule3_min_utterance_secs, 12.0);
7172
}
7273

7374
// ── 热词 tokens 过滤(2026-08-21:领域热词含 tokens 表外字 → 解码 abort)──

0 commit comments

Comments
 (0)