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 09dd300..2336e2c 100644 --- a/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt +++ b/app/src/main/java/com/k2fsa/sherpa/onnx/MainActivity.kt @@ -309,11 +309,12 @@ class MainActivity : AppCompatActivity() { // KV 污染 workaround(2026-09-14,不改 .so):nativeGenerate 不清 KV, // 同引擎连续 generate 会复读上一条 → 每"批"generate 前重建引擎。 // 初译从逐句改为小批量编号翻译(凑 4 句或 2.5s 定时封批)。 - private val initialBatchMax = 2 // 4 句批后期句常退化成抄原文;2 句批明显更稳 + private val initialBatchMax = 1 // 逐句直出:多句JSON批的格式/复读风险一并消除 private val initialBatchDelayMs = 2_500L private val initialPending = ArrayList>() private var initialBatchTimer: Runnable? = null private val translatedSids = HashSet() // 每槽只翻一次 + private val retriedSids = HashSet() // 失败仅重试一次 companion object { private val SUMMARY_THREADS = 6 // 空闲时:大核全用 @@ -1939,10 +1940,13 @@ class MainActivity : AppCompatActivity() { uiHandler.post { val touched = HashSet() refs.forEach { s2 -> - map[s2.id.toString()]?.takeIf { - it.isNotBlank() && !isEcho(s2.text, it) - }?.let { tr -> - if (s2.trans != tr) { + val tr = map[s2.id.toString()] + when { + tr == null || tr.isBlank() -> + Log.i(TAG, "MISS sid=${$}s2.id}'} reason=seg-empty") + isEcho(s2.text, tr, echoJaccardTh(s2.text)) -> + Log.i(TAG, "MISS sid=${$}s2.id}'} reason=seg-echo") + else -> if (s2.trans != tr) { s2.trans = tr s2.line?.let { touched.add(it) } } @@ -2020,14 +2024,29 @@ class MainActivity : AppCompatActivity() { val map = translateNumbered(batch.map { Pair(it.first.toString(), it.second) }) - if (map == null || !plausibleTranslations(map.values)) return@post + if (map == null || !plausibleTranslations(map.values)) { + Log.i(TAG, "MISS reason=genfail sids=" + + batch.joinToString(",") { it.first.toString() }) + // 失败自动重试一次(仅一次;判重在主线程做,避免竞态) + uiHandler.post { + val retry = batch.filter { retriedSids.add(it.first) } + if (retry.isNotEmpty()) { + initialPending.addAll(retry) + flushInitialBatch() + } + } + return@post + } uiHandler.post { val touched = HashSet() batch.forEach { (sid, src) -> - map[sid.toString()]?.takeIf { - it.isNotBlank() && !isEcho(src, it) - }?.let { tr -> - findSentence(sid)?.let { s2 -> + val tr = map[sid.toString()] + when { + tr == null || tr.isBlank() -> + Log.i(TAG, "MISS sid=$sid reason=empty") + isEcho(src, tr, echoJaccardTh(src)) -> + Log.i(TAG, "MISS sid=$sid reason=echo") + else -> findSentence(sid)?.let { s2 -> if (s2.trans != tr) { s2.trans = tr s2.line?.let { touched.add(it) } @@ -2107,7 +2126,15 @@ class MainActivity : AppCompatActivity() { private fun normalizeForEcho(x: String): String = x.lowercase().filter { it.isLetterOrDigit() || it.code >= 0x3040 } - private fun isEcho(src: String, tr: String): Boolean { + // 日↔中互译共享汉字,正常译文的二元组重合本来就高 → 该方向阈值放宽到 + // 0.88(只抓真抄写);其他方向维持 0.72。修"isEcho 错杀正常翻译"的漏句。 + private fun echoJaccardTh(srcText: String): Double { + val d = SummarizePipeline.detectLanguage(srcText) + val t = uiLanguage() + return if ((d == "ja" || d == "zh") && (t == "ja" || t == "zh")) 0.88 else 0.72 + } + + private fun isEcho(src: String, tr: String, th: Double = 0.72): Boolean { val a = normalizeForEcho(src) val b = normalizeForEcho(tr) if (a.isEmpty() || b.isEmpty()) return false @@ -2123,7 +2150,7 @@ class MainActivity : AppCompatActivity() { if (ba.isEmpty() || bb.isEmpty()) return false val inter = bb.count { ba.contains(it) } val union = ba.size + bb.size - inter - return union > 0 && inter.toDouble() / union >= 0.72 + return union > 0 && inter.toDouble() / union >= th } private val unloadRunnable = Runnable {