Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import helium314.keyboard.latin.utils.RecapitalizeMode
import helium314.keyboard.latin.utils.RecapitalizeStatus
import helium314.keyboard.latin.utils.ScriptUtils
import helium314.keyboard.latin.utils.StatsUtils
import helium314.keyboard.latin.utils.CustomAIKeyText
import helium314.keyboard.latin.utils.TextExpanderUtils
import helium314.keyboard.latin.utils.TextPlacement
import helium314.keyboard.latin.utils.TextRange
Expand Down Expand Up @@ -2935,7 +2936,7 @@ class InputLogic(
return
}

prompt += systemInstruction
prompt = CustomAIKeyText.withInstructions(prompt, systemInstruction)

var textToProcess: String
val hasSelection = mConnection.hasSelection()
Expand Down Expand Up @@ -3000,7 +3001,10 @@ class InputLogic(
Log.w(TAG, "Target editor changed during custom AI operation, ignoring result")
return@customAsync
}
if (!hasSelection && !shouldAppend) {
if (shouldAppend) {
val textBefore = mConnection.getTextBeforeCursor(2, 0) ?: ""
mLatinIME.onTextInput(CustomAIKeyText.separatorBefore(textBefore) + resultText.trim())
} else if (!hasSelection) {
mConnection.replaceEntireText(resultText)
} else {
mLatinIME.onTextInput(resultText)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.latin.utils

/** Text handling of the custom AI keys that does not need an input connection */
object CustomAIKeyText {
/**
* Instructions of the selected keywords go before the user's prompt, so a prompt that ends
* with an answer start (e.g. "Answer:") or embeds the text with `{text}` keeps its ending.
*/
fun withInstructions(prompt: String, instructions: String): String {
val trimmed = instructions.trim()
return if (trimmed.isEmpty()) prompt else "$trimmed\n\n$prompt"
}

/** Line breaks to put before a result appended after [textBefore], so it starts in a new paragraph */
fun separatorBefore(textBefore: CharSequence): String = when {
textBefore.isBlank() -> ""
textBefore.endsWith("\n\n") -> ""
textBefore.endsWith("\n") -> "\n"
else -> "\n\n"
}
}
2 changes: 1 addition & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2173,7 +2173,7 @@ New dictionary:
<string name="custom_ai_keyword_toneshift_desc">Changes the tone (e.g., professional, casual).</string>
<string name="custom_ai_keyword_generate_desc">Generates new text completely ignoring selected text.</string>
<string name="custom_ai_keyword_outputonly_desc">Returns only the modified text, without conversational fillers.</string>
<string name="custom_ai_keyword_append_desc">Appends the result to the end of the original text.</string>
<string name="custom_ai_keyword_append_desc">Appends the result to the end of the original text, separated by an empty line.</string>
<string name="custom_ai_keyword_showthought_desc">Includes AI\'s reasoning process along with result.</string>

<!-- Text Editing Layout Keys -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.latin.utils

import org.junit.Assert.assertEquals
import org.junit.Test

class CustomAIKeyTextTest {

@Test
fun instructionsGoBeforeThePrompt() {
val prompt = "Message: {text}\nAnswer:"
assertEquals("Output ONLY the result.\n\n$prompt", CustomAIKeyText.withInstructions(prompt, " Output ONLY the result."))
}

@Test
fun noInstructionsKeepThePrompt() {
assertEquals("Summarize.", CustomAIKeyText.withInstructions("Summarize.", ""))
}

@Test
fun appendedResultStartsANewParagraph() {
assertEquals("\n\n", CustomAIKeyText.separatorBefore("Best regards, Sam"))
assertEquals("\n", CustomAIKeyText.separatorBefore("Best regards, Sam\n"))
assertEquals("", CustomAIKeyText.separatorBefore("Best regards, Sam\n\n"))
assertEquals("", CustomAIKeyText.separatorBefore(""))
}
}
Loading