漏句治理第二轮: 初译逐句直出(batch=1)消灭JSON格式风险、失败自动重试一次、全链路MISS日志(genfail/empty/echo/seg-*)、isEcho日中方向阈值0.88修复错杀型漏句

This commit is contained in:
liwenhao2 2026-09-15 10:25:15 +08:00
parent 6264403b9e
commit 6f5e004351
1 changed files with 39 additions and 12 deletions

View File

@ -309,11 +309,12 @@ class MainActivity : AppCompatActivity() {
// KV 污染 workaround(2026-09-14,不改 .so):nativeGenerate 不清 KV, // KV 污染 workaround(2026-09-14,不改 .so):nativeGenerate 不清 KV,
// 同引擎连续 generate 会复读上一条 → 每"批"generate 前重建引擎。 // 同引擎连续 generate 会复读上一条 → 每"批"generate 前重建引擎。
// 初译从逐句改为小批量编号翻译(凑 4 句或 2.5s 定时封批)。 // 初译从逐句改为小批量编号翻译(凑 4 句或 2.5s 定时封批)。
private val initialBatchMax = 2 // 4 句批后期句常退化成抄原文;2 句批明显更稳 private val initialBatchMax = 1 // 逐句直出:多句JSON批的格式/复读风险一并消除
private val initialBatchDelayMs = 2_500L private val initialBatchDelayMs = 2_500L
private val initialPending = ArrayList<Pair<Long, String>>() private val initialPending = ArrayList<Pair<Long, String>>()
private var initialBatchTimer: Runnable? = null private var initialBatchTimer: Runnable? = null
private val translatedSids = HashSet<Long>() // 每槽只翻一次 private val translatedSids = HashSet<Long>() // 每槽只翻一次
private val retriedSids = HashSet<Long>() // 失败仅重试一次
companion object { companion object {
private val SUMMARY_THREADS = 6 // 空闲时:大核全用 private val SUMMARY_THREADS = 6 // 空闲时:大核全用
@ -1939,10 +1940,13 @@ class MainActivity : AppCompatActivity() {
uiHandler.post { uiHandler.post {
val touched = HashSet<SubtitleLine>() val touched = HashSet<SubtitleLine>()
refs.forEach { s2 -> refs.forEach { s2 ->
map[s2.id.toString()]?.takeIf { val tr = map[s2.id.toString()]
it.isNotBlank() && !isEcho(s2.text, it) when {
}?.let { tr -> tr == null || tr.isBlank() ->
if (s2.trans != tr) { 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.trans = tr
s2.line?.let { touched.add(it) } s2.line?.let { touched.add(it) }
} }
@ -2020,14 +2024,29 @@ class MainActivity : AppCompatActivity() {
val map = translateNumbered(batch.map { val map = translateNumbered(batch.map {
Pair(it.first.toString(), it.second) 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 { uiHandler.post {
val touched = HashSet<SubtitleLine>() val touched = HashSet<SubtitleLine>()
batch.forEach { (sid, src) -> batch.forEach { (sid, src) ->
map[sid.toString()]?.takeIf { val tr = map[sid.toString()]
it.isNotBlank() && !isEcho(src, it) when {
}?.let { tr -> tr == null || tr.isBlank() ->
findSentence(sid)?.let { s2 -> 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) { if (s2.trans != tr) {
s2.trans = tr s2.trans = tr
s2.line?.let { touched.add(it) } s2.line?.let { touched.add(it) }
@ -2107,7 +2126,15 @@ class MainActivity : AppCompatActivity() {
private fun normalizeForEcho(x: String): String = private fun normalizeForEcho(x: String): String =
x.lowercase().filter { it.isLetterOrDigit() || it.code >= 0x3040 } 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 a = normalizeForEcho(src)
val b = normalizeForEcho(tr) val b = normalizeForEcho(tr)
if (a.isEmpty() || b.isEmpty()) return false if (a.isEmpty() || b.isEmpty()) return false
@ -2123,7 +2150,7 @@ class MainActivity : AppCompatActivity() {
if (ba.isEmpty() || bb.isEmpty()) return false if (ba.isEmpty() || bb.isEmpty()) return false
val inter = bb.count { ba.contains(it) } val inter = bb.count { ba.contains(it) }
val union = ba.size + bb.size - inter 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 { private val unloadRunnable = Runnable {