diff --git a/app/src/main/java/io/legado/app/constant/PreferKey.kt b/app/src/main/java/io/legado/app/constant/PreferKey.kt index b6c86ee0e..f23b90e75 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -331,6 +331,7 @@ object PreferKey { const val llmMaxCharsPerChunk = "llmMaxCharsPerChunk" const val llmConcurrentChunks = "llmConcurrentChunks" const val llmRetryCount = "llmRetryCount" + const val llmTemperature = "llmTemperature" const val llmPrompt = "llmPrompt" const val homepageModuleOrder = "homepageModuleOrder" diff --git a/app/src/main/java/io/legado/app/data/repository/LlmTranslateRepositoryImpl.kt b/app/src/main/java/io/legado/app/data/repository/LlmTranslateRepositoryImpl.kt index 0761172c3..96da23e12 100644 --- a/app/src/main/java/io/legado/app/data/repository/LlmTranslateRepositoryImpl.kt +++ b/app/src/main/java/io/legado/app/data/repository/LlmTranslateRepositoryImpl.kt @@ -31,6 +31,7 @@ class LlmTranslateRepositoryImpl : LlmGateway { apiKey: String, model: String, prompt: String, + temperature: Float, dictionaries: List, onUpdate: ((List) -> Unit)?, retryReason: RetryReason? @@ -55,6 +56,7 @@ class LlmTranslateRepositoryImpl : LlmGateway { apiKey, model, prompt, + temperature, dictionaries, onUpdate, retryReason @@ -131,6 +133,7 @@ class LlmTranslateRepositoryImpl : LlmGateway { apiKey: String, model: String, prompt: String, + temperature: Float, dictionaries: List, onUpdate: ((List) -> Unit)?, retryReason: RetryReason? @@ -150,7 +153,10 @@ class LlmTranslateRepositoryImpl : LlmGateway { mapOf("role" to "system", "content" to systemPrompt), 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 fullUrl = baseUrl.trimEnd('/') + "/v1/chat/completions" diff --git a/app/src/main/java/io/legado/app/domain/gateway/LlmGateway.kt b/app/src/main/java/io/legado/app/domain/gateway/LlmGateway.kt index 8276c82be..7c3867dc3 100644 --- a/app/src/main/java/io/legado/app/domain/gateway/LlmGateway.kt +++ b/app/src/main/java/io/legado/app/domain/gateway/LlmGateway.kt @@ -2,6 +2,7 @@ package io.legado.app.domain.gateway import io.legado.app.domain.model.DictPair import io.legado.app.domain.model.RetryReason +import io.legado.app.domain.model.TranslationConstants interface LlmGateway { suspend fun translate( @@ -12,6 +13,7 @@ interface LlmGateway { apiKey: String, model: String, prompt: String, + temperature: Float = TranslationConstants.DEFAULT_TEMPERATURE, dictionaries: List = emptyList(), onUpdate: ((List) -> Unit)? = null, retryReason: RetryReason? = null diff --git a/app/src/main/java/io/legado/app/domain/model/TranslationConstants.kt b/app/src/main/java/io/legado/app/domain/model/TranslationConstants.kt index 8adce073a..d962878d1 100644 --- a/app/src/main/java/io/legado/app/domain/model/TranslationConstants.kt +++ b/app/src/main/java/io/legado/app/domain/model/TranslationConstants.kt @@ -4,6 +4,9 @@ object TranslationConstants { const val PROVIDER_OPENAI = "openai" 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 providerValues = listOf(PROVIDER_GOOGLE, PROVIDER_OPENAI) diff --git a/app/src/main/java/io/legado/app/domain/usecase/TranslateChapterUseCase.kt b/app/src/main/java/io/legado/app/domain/usecase/TranslateChapterUseCase.kt index 91a7bb0ef..8459621e3 100644 --- a/app/src/main/java/io/legado/app/domain/usecase/TranslateChapterUseCase.kt +++ b/app/src/main/java/io/legado/app/domain/usecase/TranslateChapterUseCase.kt @@ -34,7 +34,7 @@ class TranslateChapterUseCase( ) companion object { - private const val MAX_DICTIONARY_PAIRS = 50 + private const val MAX_DICTIONARY_PAIRS = 80 } 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) { - 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.addAll(trimmed) changed = true @@ -261,6 +263,7 @@ class TranslateChapterUseCase( apiKey = TranslationConfig.llmApiKey, model = TranslationConfig.llmModel, prompt = TranslationConfig.llmPrompt, + temperature = TranslationConfig.llmTemperature, dictionaries = dictSnapshot, onUpdate = onDictionaryUpdate, retryReason = lastRetryReason @@ -285,4 +288,4 @@ class TranslateChapterUseCase( else -> null } } -} \ No newline at end of file +} diff --git a/app/src/main/java/io/legado/app/ui/config/translation/TranslationConfig.kt b/app/src/main/java/io/legado/app/ui/config/translation/TranslationConfig.kt index aee966290..494a3bae4 100644 --- a/app/src/main/java/io/legado/app/ui/config/translation/TranslationConfig.kt +++ b/app/src/main/java/io/legado/app/ui/config/translation/TranslationConfig.kt @@ -51,6 +51,17 @@ object TranslationConfig { 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( PreferKey.llmPrompt, TranslationConstants.DEFAULT_PROMPT @@ -62,6 +73,9 @@ object TranslationConfig { val providerDisplayNames get() = TranslationConstants.providerDisplayNames val providerValues get() = TranslationConstants.providerValues 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 OUTPUT_FORMAT = TranslationConstants.OUTPUT_FORMAT } diff --git a/app/src/main/java/io/legado/app/ui/config/translation/TranslationConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/translation/TranslationConfigScreen.kt index 565489c11..945c0c07d 100644 --- a/app/src/main/java/io/legado/app/ui/config/translation/TranslationConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/translation/TranslationConfigScreen.kt @@ -109,6 +109,16 @@ fun TranslationConfigScreen( 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( title = stringResource(R.string.llm_prompt), value = tempPrompt, @@ -122,4 +132,4 @@ fun TranslationConfigScreen( } } } -} \ No newline at end of file +} diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 66e0805ec..42929d55e 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1768,6 +1768,8 @@ 每块最大字符数 并发块数 重试次数 + 温度 + 允许值:0-2。越靠近 0 越严谨,越靠近 2 越有创造力。 翻译提示词 提示词 翻译章节 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index daf51a89c..9803ea86f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1709,6 +1709,8 @@ Max Chars Per Chunk Concurrent Chunks Retry Count + Temperature + Allowed range: 0-2. Closer to 0 is stricter; closer to 2 is more creative. Translation Prompt Prompt Translate Chapter