fix: 翻译功能的一些小优化和修复 (#1225)

1. llm温度是可调的,对于ds而言,翻译1.3最佳,默认值调整成该值
2. 翻译字典,最多允许从50增加到80,取头尾各一半,因为小说出场最早和最近的人最重要

Co-authored-by: duanhl <duanhl7749@gmail.com>
This commit is contained in:
Duanhl
2026-05-30 03:50:34 +08:00
committed by GitHub
co-authored by duanhl
parent f8f19f7379
commit 978d6d2840
9 changed files with 49 additions and 6 deletions
@@ -331,6 +331,7 @@ object PreferKey {
const val llmMaxCharsPerChunk = "llmMaxCharsPerChunk" const val llmMaxCharsPerChunk = "llmMaxCharsPerChunk"
const val llmConcurrentChunks = "llmConcurrentChunks" const val llmConcurrentChunks = "llmConcurrentChunks"
const val llmRetryCount = "llmRetryCount" const val llmRetryCount = "llmRetryCount"
const val llmTemperature = "llmTemperature"
const val llmPrompt = "llmPrompt" const val llmPrompt = "llmPrompt"
const val homepageModuleOrder = "homepageModuleOrder" const val homepageModuleOrder = "homepageModuleOrder"
@@ -31,6 +31,7 @@ class LlmTranslateRepositoryImpl : LlmGateway {
apiKey: String, apiKey: String,
model: String, model: String,
prompt: String, prompt: String,
temperature: Float,
dictionaries: List<DictPair>, dictionaries: List<DictPair>,
onUpdate: ((List<DictPair>) -> Unit)?, onUpdate: ((List<DictPair>) -> Unit)?,
retryReason: RetryReason? retryReason: RetryReason?
@@ -55,6 +56,7 @@ class LlmTranslateRepositoryImpl : LlmGateway {
apiKey, apiKey,
model, model,
prompt, prompt,
temperature,
dictionaries, dictionaries,
onUpdate, onUpdate,
retryReason retryReason
@@ -131,6 +133,7 @@ class LlmTranslateRepositoryImpl : LlmGateway {
apiKey: String, apiKey: String,
model: String, model: String,
prompt: String, prompt: String,
temperature: Float,
dictionaries: List<DictPair>, dictionaries: List<DictPair>,
onUpdate: ((List<DictPair>) -> Unit)?, onUpdate: ((List<DictPair>) -> Unit)?,
retryReason: RetryReason? retryReason: RetryReason?
@@ -150,7 +153,10 @@ class LlmTranslateRepositoryImpl : LlmGateway {
mapOf("role" to "system", "content" to systemPrompt), mapOf("role" to "system", "content" to systemPrompt),
mapOf("role" to "user", "content" to "Translate the following text:\n\n$text") mapOf("role" to "user", "content" to "Translate the following text:\n\n$text")
), ),
"temperature" to 0.8 "temperature" to temperature.coerceIn(
TranslationConstants.MIN_TEMPERATURE,
TranslationConstants.MAX_TEMPERATURE
)
) )
val jsonBody = GSON.toJson(requestBody) val jsonBody = GSON.toJson(requestBody)
val fullUrl = baseUrl.trimEnd('/') + "/v1/chat/completions" val fullUrl = baseUrl.trimEnd('/') + "/v1/chat/completions"
@@ -2,6 +2,7 @@ package io.legado.app.domain.gateway
import io.legado.app.domain.model.DictPair import io.legado.app.domain.model.DictPair
import io.legado.app.domain.model.RetryReason import io.legado.app.domain.model.RetryReason
import io.legado.app.domain.model.TranslationConstants
interface LlmGateway { interface LlmGateway {
suspend fun translate( suspend fun translate(
@@ -12,6 +13,7 @@ interface LlmGateway {
apiKey: String, apiKey: String,
model: String, model: String,
prompt: String, prompt: String,
temperature: Float = TranslationConstants.DEFAULT_TEMPERATURE,
dictionaries: List<DictPair> = emptyList(), dictionaries: List<DictPair> = emptyList(),
onUpdate: ((List<DictPair>) -> Unit)? = null, onUpdate: ((List<DictPair>) -> Unit)? = null,
retryReason: RetryReason? = null retryReason: RetryReason? = null
@@ -4,6 +4,9 @@ object TranslationConstants {
const val PROVIDER_OPENAI = "openai" const val PROVIDER_OPENAI = "openai"
const val PROVIDER_GOOGLE = "google" const val PROVIDER_GOOGLE = "google"
const val MIN_TEMPERATURE = 0f
const val MAX_TEMPERATURE = 2f
const val DEFAULT_TEMPERATURE = 1.3f
val providerDisplayNames = listOf("Google Translate", "OpenAI适配接口") val providerDisplayNames = listOf("Google Translate", "OpenAI适配接口")
val providerValues = listOf(PROVIDER_GOOGLE, PROVIDER_OPENAI) val providerValues = listOf(PROVIDER_GOOGLE, PROVIDER_OPENAI)
@@ -34,7 +34,7 @@ class TranslateChapterUseCase(
) )
companion object { companion object {
private const val MAX_DICTIONARY_PAIRS = 50 private const val MAX_DICTIONARY_PAIRS = 80
} }
private val dictionaryLock = Any() private val dictionaryLock = Any()
@@ -198,9 +198,11 @@ class TranslateChapterUseCase(
} }
} }
// Keep only the most recent MAX_DICTIONARY_PAIRS // Keep early important names and the most recently discovered terms.
if (existing.size > MAX_DICTIONARY_PAIRS) { if (existing.size > MAX_DICTIONARY_PAIRS) {
val trimmed = existing.takeLast(MAX_DICTIONARY_PAIRS) val headCount = MAX_DICTIONARY_PAIRS / 2
val tailCount = MAX_DICTIONARY_PAIRS - headCount
val trimmed = existing.take(headCount) + existing.takeLast(tailCount)
existing.clear() existing.clear()
existing.addAll(trimmed) existing.addAll(trimmed)
changed = true changed = true
@@ -261,6 +263,7 @@ class TranslateChapterUseCase(
apiKey = TranslationConfig.llmApiKey, apiKey = TranslationConfig.llmApiKey,
model = TranslationConfig.llmModel, model = TranslationConfig.llmModel,
prompt = TranslationConfig.llmPrompt, prompt = TranslationConfig.llmPrompt,
temperature = TranslationConfig.llmTemperature,
dictionaries = dictSnapshot, dictionaries = dictSnapshot,
onUpdate = onDictionaryUpdate, onUpdate = onDictionaryUpdate,
retryReason = lastRetryReason retryReason = lastRetryReason
@@ -285,4 +288,4 @@ class TranslateChapterUseCase(
else -> null else -> null
} }
} }
} }
@@ -51,6 +51,17 @@ object TranslationConfig {
2 2
) )
private var storedLlmTemperature by prefDelegate(
PreferKey.llmTemperature,
TranslationConstants.DEFAULT_TEMPERATURE
)
var llmTemperature: Float
get() = storedLlmTemperature.coerceIn(MIN_TEMPERATURE, MAX_TEMPERATURE)
set(value) {
storedLlmTemperature = value.coerceIn(MIN_TEMPERATURE, MAX_TEMPERATURE)
}
var llmPrompt by prefDelegate( var llmPrompt by prefDelegate(
PreferKey.llmPrompt, PreferKey.llmPrompt,
TranslationConstants.DEFAULT_PROMPT TranslationConstants.DEFAULT_PROMPT
@@ -62,6 +73,9 @@ object TranslationConfig {
val providerDisplayNames get() = TranslationConstants.providerDisplayNames val providerDisplayNames get() = TranslationConstants.providerDisplayNames
val providerValues get() = TranslationConstants.providerValues val providerValues get() = TranslationConstants.providerValues
val targetLanguages get() = TranslationConstants.targetLanguages val targetLanguages get() = TranslationConstants.targetLanguages
const val MIN_TEMPERATURE = TranslationConstants.MIN_TEMPERATURE
const val MAX_TEMPERATURE = TranslationConstants.MAX_TEMPERATURE
const val DEFAULT_TEMPERATURE = TranslationConstants.DEFAULT_TEMPERATURE
const val DEFAULT_PROMPT = TranslationConstants.DEFAULT_PROMPT const val DEFAULT_PROMPT = TranslationConstants.DEFAULT_PROMPT
const val OUTPUT_FORMAT = TranslationConstants.OUTPUT_FORMAT const val OUTPUT_FORMAT = TranslationConstants.OUTPUT_FORMAT
} }
@@ -109,6 +109,16 @@ fun TranslationConfigScreen(
onConfirm = { TranslationConfig.llmModel = it } onConfirm = { TranslationConfig.llmModel = it }
) )
SliderSettingItem(
title = stringResource(R.string.llm_temperature),
value = TranslationConfig.llmTemperature,
defaultValue = TranslationConfig.DEFAULT_TEMPERATURE,
valueRange = TranslationConfig.MIN_TEMPERATURE..TranslationConfig.MAX_TEMPERATURE,
steps = 19,
description = stringResource(R.string.llm_temperature_description),
onValueChange = { TranslationConfig.llmTemperature = it }
)
InputSettingItem( InputSettingItem(
title = stringResource(R.string.llm_prompt), title = stringResource(R.string.llm_prompt),
value = tempPrompt, value = tempPrompt,
@@ -122,4 +132,4 @@ fun TranslationConfigScreen(
} }
} }
} }
} }
@@ -1768,6 +1768,8 @@
<string name="llm_max_chars_per_chunk">每块最大字符数</string> <string name="llm_max_chars_per_chunk">每块最大字符数</string>
<string name="llm_concurrent_chunks">并发块数</string> <string name="llm_concurrent_chunks">并发块数</string>
<string name="llm_retry_count">重试次数</string> <string name="llm_retry_count">重试次数</string>
<string name="llm_temperature">温度</string>
<string name="llm_temperature_description">允许值:0-2。越靠近 0 越严谨,越靠近 2 越有创造力。</string>
<string name="translation_prompt">翻译提示词</string> <string name="translation_prompt">翻译提示词</string>
<string name="llm_prompt">提示词</string> <string name="llm_prompt">提示词</string>
<string name="translate_chapter">翻译章节</string> <string name="translate_chapter">翻译章节</string>
+2
View File
@@ -1709,6 +1709,8 @@
<string name="llm_max_chars_per_chunk">Max Chars Per Chunk</string> <string name="llm_max_chars_per_chunk">Max Chars Per Chunk</string>
<string name="llm_concurrent_chunks">Concurrent Chunks</string> <string name="llm_concurrent_chunks">Concurrent Chunks</string>
<string name="llm_retry_count">Retry Count</string> <string name="llm_retry_count">Retry Count</string>
<string name="llm_temperature">Temperature</string>
<string name="llm_temperature_description">Allowed range: 0-2. Closer to 0 is stricter; closer to 2 is more creative.</string>
<string name="translation_prompt">Translation Prompt</string> <string name="translation_prompt">Translation Prompt</string>
<string name="llm_prompt">Prompt</string> <string name="llm_prompt">Prompt</string>
<string name="translate_chapter">Translate Chapter</string> <string name="translate_chapter">Translate Chapter</string>