From 54f07d85e9cb8a59a135086c58df818c87c0efe9 Mon Sep 17 00:00:00 2001 From: aeoform <2790848120@qq.com> Date: Fri, 22 May 2026 20:49:11 +0800 Subject: [PATCH] =?UTF-8?q?fix(bailian):=20=E4=BF=AE=E5=A4=8D=20DashScope?= =?UTF-8?q?=20ASR=20=E9=83=A8=E5=88=86=E8=AF=AD=E5=8F=A5=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两个根因: 1. end_time 判断用 is_some() 而非 > 0:API 对 interim 结果设 end_time:0, 导致所有中间结果被当成 final 推入 segments 2. 累积文本拼接:同一句 API 多次发送("你"→"你好"→"你好吗"), 每次作为新 segment push,join 后变成重复拼接 修复: - end_time 改用 > 0 判断真正的句子结束 - 引入 sentence_id → BTreeMap 按序存储,同一 sentence_id 后到覆盖前到 Co-Authored-By: Claude Opus 4.7 (1M context) --- openless-all/app/src-tauri/src/asr/bailian.rs | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/openless-all/app/src-tauri/src/asr/bailian.rs b/openless-all/app/src-tauri/src/asr/bailian.rs index 484a9125..dba2742a 100644 --- a/openless-all/app/src-tauri/src/asr/bailian.rs +++ b/openless-all/app/src-tauri/src/asr/bailian.rs @@ -5,6 +5,7 @@ //! matches OpenLess' recorder output directly. The Qwen OpenAI Realtime line is //! a different protocol and is intentionally left for a follow-up provider. +use std::collections::BTreeMap; use std::sync::Arc; use std::time::{Duration, Instant}; @@ -94,7 +95,9 @@ struct SyncState { start: Option, final_tx: Option>>, send_tx: Option>, - final_segments: Vec, + /// sentence_id → text,按 sentence_id 排序拼接得到最终文本。 + /// 同一 sentence_id 的后到结果覆盖前一个,消除累积文本导致的重复。 + final_segments: BTreeMap, last_result_text: String, } @@ -367,11 +370,22 @@ impl BailianRealtimeASR { if trimmed.is_empty() { return; } - let is_sentence_final = sentence.get("end_time").is_some(); + // end_time 为 0 或缺失时是 interim 结果;仅正数才是真正完成的句子。 + let end_time = sentence + .get("end_time") + .and_then(Value::as_i64) + .unwrap_or(0); + let is_sentence_final = end_time > 0; + let sentence_id = sentence + .get("sentence_id") + .and_then(Value::as_i64) + .unwrap_or(0); let mut st = self.state.lock(); st.last_result_text = trimmed.to_string(); - if is_sentence_final && st.final_segments.last().map(|s| s.as_str()) != Some(trimmed) { - st.final_segments.push(trimmed.to_string()); + if is_sentence_final && sentence_id > 0 { + // 同一 sentence_id 后到覆盖前到:API 对同一句话的累积更新 + // ("你"→"你好"→"你好吗")只保留最终版本。 + st.final_segments.insert(sentence_id, trimmed.to_string()); } } @@ -386,7 +400,7 @@ impl BailianRealtimeASR { let text = if st.final_segments.is_empty() { st.last_result_text.clone() } else { - st.final_segments.join("") + st.final_segments.values().cloned().collect::>().join("") }; let duration_ms = if st.bytes_received > 0 { st.bytes_received / BYTES_PER_MS