From 898c5969e36854c90d8f0e027ff57ab1b2098eec Mon Sep 17 00:00:00 2001 From: liwenhao2 Date: Wed, 16 Sep 2026 16:08:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BB=E5=8A=A8=E5=96=84=E5=90=8E(=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=8F=8D=E9=A6=88'=E5=96=84=E5=90=8E=E4=B8=8D?= =?UTF-8?q?=E7=90=86=E6=83=B3'):=E5=87=86=E7=A1=AE=E5=A4=8D=E6=A0=B8?= =?UTF-8?q?=E8=AE=A4=E5=87=BA=E5=90=8C=E4=BA=BA=E5=8D=B3=E6=92=A4=E9=94=80?= =?UTF-8?q?,=E4=B8=8D=E5=86=8D=E8=A2=AB=E5=8A=A8=E7=AD=89=E5=8F=A5?= =?UTF-8?q?=E5=AD=90=E7=BB=93=E6=9D=9F(=E9=95=BF=E5=8F=A5=E9=94=99?= =?UTF-8?q?=E6=A0=87=E6=8C=82=E5=87=A0=E5=8D=81=E7=A7=92):=20-=20SpeakerRe?= =?UTF-8?q?gistry.removeAuto(=E5=8D=A0=E4=BD=8D=E5=8F=B7=E6=B8=85=E7=90=86?= =?UTF-8?q?)=20-=20accurateRecheckAfterSwitch=20=E7=9A=84=20CANCEL-LATE=20?= =?UTF-8?q?=E5=88=86=E6=94=AF=E2=86=92=E4=B8=BB=E7=BA=BF=E7=A8=8B=20revert?= =?UTF-8?q?OnsetSwitch=20-=20revert=20=E4=B8=A4=E5=BD=A2=E6=80=81:?= =?UTF-8?q?=E5=8D=A0=E4=BD=8D=E8=A1=8C=E6=9C=AA=E5=BB=BA=E7=AB=8B(?= =?UTF-8?q?=E5=A4=9A=E6=95=B0)=E2=86=92=E6=8A=B9=E8=BF=B9(=E9=A2=84?= =?UTF-8?q?=E7=BD=AE=E4=BD=9C=E5=BA=9F/=E9=87=8D=E5=BC=80=E6=97=A7?= =?UTF-8?q?=E5=BA=95=E8=A1=8C/=E9=98=B2=E5=9C=A8=E9=80=94=E5=AE=9A?= =?UTF-8?q?=E6=A0=BC=E8=A1=A5=E5=B0=81,=E9=9B=B6=E6=96=AD=E8=A1=8C?= =?UTF-8?q?=E9=9B=B6=E9=97=AA=E7=83=81);=E5=B7=B2=E5=BB=BA=E7=AB=8B?= =?UTF-8?q?=E2=86=92=E5=B0=B1=E5=9C=B0=E6=94=B9=E7=AD=BE+=E5=B9=B6?= =?UTF-8?q?=E5=9B=9E+=E6=8D=A2=E8=89=B2=20-=20=E4=BB=85=E5=BD=93=E5=9C=A8?= =?UTF-8?q?=E9=80=94/=E8=90=BD=E5=9C=B0=E5=88=87=E6=8D=A2=E4=BB=8D?= =?UTF-8?q?=E6=8C=87=E5=90=91=E8=AF=A5=E5=8D=A0=E4=BD=8D=E5=8F=B7=E6=97=B6?= =?UTF-8?q?=E6=92=A4=E9=94=80,=E8=BF=9E=E7=8E=AF=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E4=BA=A4=E8=A2=AB=E5=8A=A8=E9=93=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/k2fsa/sherpa/onnx/MainActivity.kt | 43 ++++++++++++++++++- .../com/k2fsa/sherpa/onnx/SpeakerEmbedding.kt | 6 +++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt b/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt index 7c44163..90358bd 100644 --- a/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt +++ b/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt @@ -1822,14 +1822,53 @@ class MainActivity : AppCompatActivity() { val pre = SpeakerRecognition.registry.search(acc, speakerThreshold) ?: nearestAttribution(acc, SpeakerRecognition.registry, verdictFallbackMin) when { - pre != null && pre == active -> - Log.i(TAG, tag + "-CANCEL-LATE known=$pre(active) revert-via-verdict") + pre != null && pre == active -> { + Log.i(TAG, tag + "-CANCEL-LATE known=$pre(active) active-heal") + // 主动善后:不再被动等句子结束(长句让错标挂几十秒),立即撤销 + uiHandler.post { revertOnsetSwitch(label, pre) } + } pre != null -> Log.i(TAG, tag + "-RECHECK known=$pre label=$label (verdict migrates)") else -> SpeakerRecognition.registry.addAuto(label, acc) } } + /** 乐观切换的主动善后(2026-09-16"善后不理想"整改):准确复核认出同一 + * 人时立即撤销,不等句子结束——覆盖预置标签、还原钉住的标签、占位行 + * 就地改签并与上方同人并回、清理快镜像占位编号。主线程执行。 */ + private fun revertOnsetSwitch(firedLabel: String, prevActive: String?) { + if (prevActive == null) return // 无旧主可还原(会话极早期)→ 被动链 + val bottom = subtitleLines.lastOrNull() + val pending = pendingOnsetLabel + val inFlight = pending == firedLabel || + (bottom != null && bottom.label == firedLabel && bottom.open) + if (!inFlight) return // 状态已走远(连环切换等)→ 交给被动链 + if (pending == firedLabel && bottom != null && + bottom.label != firedLabel + ) { + // 占位行尚未建立(补喂机制下多数如此):抹掉切换痕迹——预置标签 + // 作废、重开旧底行,同人续说零断行,观感上从未切过 + pendingOnsetLabel = null + onsetClosePending = false // 防在途定格回来补封行 + if (!bottom.open) bottom.open = true + lastConfirmedLabel = prevActive + SpeakerRecognition.fastRegistry.removeAuto(firedLabel) + Log.i(TAG, "SWITCH-REVERT(pre-line) $firedLabel -> $prevActive") + return + } + // 占位行已建立:就地改签 + 与上方同人并回 + pendingOnsetLabel = null + lastConfirmedLabel = prevActive + if (bottom != null && bottom.label == firedLabel) { + bottom.label = prevActive + bottom.colorIdx = colorIdxFor(prevActive) + val merged = mergeLineIntoPrevIfSame(bottom, prevActive) + if (!merged) notifyLine(bottom) + } + SpeakerRecognition.fastRegistry.removeAuto(firedLabel) + Log.i(TAG, "SWITCH-REVERT(line) $firedLabel -> $prevActive (active-heal)") + } + private fun appendNewLine(label: String?): SubtitleLine { // 新行出现即封掉之前的开放行,并把其中"未定格的进行中句子"整体迁移 // 过来 —— 硬保证 in-progress 只可能发生在最底行(修复:声纹判定搬家后, diff --git a/app/src/main/java/com/k2fsa/sherpa/onnx/SpeakerEmbedding.kt b/app/src/main/java/com/k2fsa/sherpa/onnx/SpeakerEmbedding.kt index af3a1fa..270c2cf 100644 --- a/app/src/main/java/com/k2fsa/sherpa/onnx/SpeakerEmbedding.kt +++ b/app/src/main/java/com/k2fsa/sherpa/onnx/SpeakerEmbedding.kt @@ -99,6 +99,12 @@ class SpeakerRegistry { auto.add(Pair(name, l2normalize(e))) } + /** 撤销乐观切换时移除占位编号(2026-09-16:防被清掉的号继续被检索命中)。 */ + @Synchronized + fun removeAuto(name: String) { + auto.removeAll { it.first == name } + } + // Enroll (or overwrite) a real name for a given embedding. @Synchronized fun addNamed(name: String, e: FloatArray) {