Skip to content

Commit 7877afb

Browse files
committed
fix(offline): implement dynamic target-language-specific few-shot examples for GGUF translation
1 parent 05fb5b9 commit 7877afb

1 file changed

Lines changed: 65 additions & 3 deletions

File tree

app/src/offline/java/helium314/keyboard/latin/utils/ProofreadService.kt

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,13 +332,18 @@ class ProofreadService(private val context: Context) {
332332
val target = sharedPrefs.getString(Settings.PREF_OFFLINE_TRANSLATE_TARGET_LANGUAGE, Defaults.PREF_OFFLINE_TRANSLATE_TARGET_LANGUAGE) ?: Defaults.PREF_OFFLINE_TRANSLATE_TARGET_LANGUAGE
333333
val systemPromptTemplate = getTranslateSystemPrompt().takeIf { it.isNotBlank() } ?: Defaults.PREF_OFFLINE_TRANSLATE_SYSTEM_PROMPT
334334
val prompt = systemPromptTemplate.replace("{lang}", target)
335-
return proofread(text, overridePrompt = prompt)
335+
return proofread(text, overridePrompt = prompt, targetLanguage = target)
336336
}
337337

338338
/**
339339
* Run llamacpp inference for proofreading/text correction.
340340
*/
341-
suspend fun proofread(text: String, overridePrompt: String? = null, showThinking: Boolean? = null): Result<String> = withContext(Dispatchers.IO) {
341+
suspend fun proofread(
342+
text: String,
343+
overridePrompt: String? = null,
344+
showThinking: Boolean? = null,
345+
targetLanguage: String? = null
346+
): Result<String> = withContext(Dispatchers.IO) {
342347
val modelPath = getModelPath()
343348
if (modelPath.isNullOrBlank()) {
344349
return@withContext Result.failure(ProofreadException("Model not loaded. Please select a GGUF model file."))
@@ -367,7 +372,17 @@ class ProofreadService(private val context: Context) {
367372
systemPrompt.replace("{text}", text)
368373
} else if (overridePrompt != null) {
369374
// Translation or specific override
370-
"Instruction: ${systemPrompt.trim()}\nInput: $text\nOutput:"
375+
val examples = targetLanguage?.let { getTranslationFewShot(it) } ?: emptyList()
376+
if (examples.isNotEmpty()) {
377+
var builder = "Instruction: ${systemPrompt.trim()}\n\n"
378+
for (ex in examples) {
379+
builder += "Input: ${ex.first}\nOutput: ${ex.second}\n\n"
380+
}
381+
builder += "Input: $text\nOutput:"
382+
builder
383+
} else {
384+
"Instruction: ${systemPrompt.trim()}\nInput: $text\nOutput:"
385+
}
371386
} else {
372387
// Default proofreading with few-shot examples for better local model guidance
373388
val instruction = systemPrompt.ifBlank { "Correct the grammar and spelling of the input text. Output only the corrected text, nothing else." }
@@ -572,6 +587,53 @@ class ProofreadService(private val context: Context) {
572587
.trim()
573588
}
574589

590+
private fun getTranslationFewShot(targetLanguage: String): List<Pair<String, String>> {
591+
val lang = targetLanguage.trim().lowercase()
592+
return when {
593+
lang.contains("french") || lang.contains("français") -> listOf(
594+
"Hello, how are you?" to "Bonjour, comment allez-vous?",
595+
"My name is Alex." to "Je m'appelle Alex."
596+
)
597+
lang.contains("spanish") || lang.contains("español") -> listOf(
598+
"Hello, how are you?" to "Hola, ¿cómo estás?",
599+
"My name is Alex." to "Mi nombre es Alex."
600+
)
601+
lang.contains("german") || lang.contains("deutsch") -> listOf(
602+
"Hello, how are you?" to "Hallo, wie geht es dir?",
603+
"My name is Alex." to "Mein Name ist Alex."
604+
)
605+
lang.contains("italian") || lang.contains("italiano") -> listOf(
606+
"Hello, how are you?" to "Ciao, come stai?",
607+
"My name is Alex." to "Il mio nome è Alex."
608+
)
609+
lang.contains("portuguese") || lang.contains("português") -> listOf(
610+
"Hello, how are you?" to "Olá, como você está?",
611+
"My name is Alex." to "Meu nome é Alex."
612+
)
613+
lang.contains("dutch") || lang.contains("nederlands") -> listOf(
614+
"Hello, how are you?" to "Hallo, hoe gaat het met je?",
615+
"My name is Alex." to "Mijn naam is Alex."
616+
)
617+
lang.contains("russian") || lang.contains("русский") -> listOf(
618+
"Hello, how are you?" to "Привет, как дела?",
619+
"My name is Alex." to "Меня зовут Алекс."
620+
)
621+
lang.contains("chinese") || lang.contains("中文") || lang.contains("汉语") -> listOf(
622+
"Hello, how are you?" to "你好,你好吗?",
623+
"My name is Alex." to "我的名字是亚历克斯。"
624+
)
625+
lang.contains("japanese") || lang.contains("日本語") -> listOf(
626+
"Hello, how are you?" to "こんにちは、お元気ですか?",
627+
"My name is Alex." to "私の名前はアレックスです。"
628+
)
629+
lang.contains("hindi") || lang.contains("हिन्दी") -> listOf(
630+
"Hello, how are you?" to "नमस्ते, आप कैसे हैं?",
631+
"My name is Alex." to "मेरा नाम एलेक्स है।"
632+
)
633+
else -> emptyList()
634+
}
635+
}
636+
575637
class ProofreadException(message: String) : Exception(message)
576638
class TranslateException(message: String) : Exception(message)
577639

0 commit comments

Comments
 (0)