Просмотр исходного кода

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

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

Co-authored-by: duanhl <duanhl7749@gmail.com>
Duanhl 5 месяцев назад
Родитель
Сommit
978d6d2840

+ 1 - 0
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"

+ 7 - 1
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<DictPair>,
         onUpdate: ((List<DictPair>) -> 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<DictPair>,
         onUpdate: ((List<DictPair>) -> 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"

+ 2 - 0
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<DictPair> = emptyList(),
         onUpdate: ((List<DictPair>) -> Unit)? = null,
         retryReason: RetryReason? = null

+ 3 - 0
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)

+ 7 - 4
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
         }
     }
-}
+}

+ 14 - 0
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
 }

+ 11 - 1
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(
             }
         }
     }
-}
+}

+ 2 - 0
app/src/main/res/values-zh-rCN/strings.xml

@@ -1768,6 +1768,8 @@
     <string name="llm_max_chars_per_chunk">每块最大字符数</string>
     <string name="llm_concurrent_chunks">并发块数</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="llm_prompt">提示词</string>
     <string name="translate_chapter">翻译章节</string>

+ 2 - 0
app/src/main/res/values/strings.xml

@@ -1709,6 +1709,8 @@
     <string name="llm_max_chars_per_chunk">Max Chars Per Chunk</string>
     <string name="llm_concurrent_chunks">Concurrent Chunks</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="llm_prompt">Prompt</string>
     <string name="translate_chapter">Translate Chapter</string>