Apply blacklist filter before bothAlgorithmsCameToSameConclusion,

allow emoji suggestions after typing a word, allow easily disabling emoji suggestions through long-tapping
This commit is contained in:
Aleksandras Kostarevas 2024-03-14 15:40:44 -05:00
parent 65686b39a0
commit 455c3741ae
5 changed files with 51 additions and 17 deletions

View File

@ -39,5 +39,6 @@
<string name="blacklist">Blacklist</string>
<string name="blacklist_from_suggestions">Blacklist \"%1$s\" from being suggested?</string>
<string name="disable_emoji">Disable emoji suggestions</string>
<string name="try_typing">Try typing here…</string>
</resources>

View File

@ -518,6 +518,10 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
uixManager.requestForgetWord(suggestedWordInfo)
}
fun refreshSuggestions() {
latinIMELegacy.mInputLogic.performUpdateSuggestionStripSync(latinIMELegacy.mSettings.current, SuggestedWords.INPUT_STYLE_TYPING)
}
fun forceForgetWord(suggestedWordInfo: SuggestedWordInfo) {
lifecycleScope.launch {
val existingWords = getSetting(SUGGESTION_BLACKLIST).toMutableSet()
@ -530,6 +534,6 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
-1, Constants.NOT_A_CODE
)
latinIMELegacy.mInputLogic.performUpdateSuggestionStripSync(latinIMELegacy.mSettings.current, SuggestedWords.INPUT_STYLE_TYPING)
refreshSuggestions()
}
}

View File

@ -24,6 +24,10 @@ class SuggestionBlacklist(val settings: Settings, val context: Context, val life
}
}
fun isSuggestedWordOk(word: SuggestedWordInfo): Boolean {
return (word.mWord !in currentBlacklist) && (!offensiveWordsAdded || !isFiltered(word.mWord))
}
fun filterBlacklistedSuggestions(suggestions: SuggestedWords): SuggestedWords {
if(settings.current.mBlockPotentiallyOffensive && !offensiveWordsAdded) {
currentBlacklist = currentBlacklist + badWords
@ -35,7 +39,7 @@ class SuggestionBlacklist(val settings: Settings, val context: Context, val life
offensiveWordsAdded = false
}
val filter: (SuggestedWordInfo) -> Boolean = { it -> (it.mWord !in currentBlacklist) && (!offensiveWordsAdded || !isFiltered(it.mWord)) || (it == suggestions.mTypedWordInfo) }
val filter: (SuggestedWordInfo) -> Boolean = { it -> isSuggestedWordOk(it) || (it == suggestions.mTypedWordInfo) }
val shouldStillAutocorrect = suggestions.mWillAutoCorrect && filter(suggestions.getInfo(SuggestedWords.INDEX_OF_AUTO_CORRECTION))

View File

@ -39,10 +39,10 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat.getSystemService
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.futo.inputmethod.latin.LatinIME
import org.futo.inputmethod.latin.R
import org.futo.inputmethod.latin.SuggestedWords
@ -325,6 +325,7 @@ class UixManager(private val latinIME: LatinIME) {
R.string.blacklist_from_suggestions,
wordBeingForgotten.value?.mWord!!
))
Row {
TextButton(
onClick = {
@ -342,6 +343,18 @@ class UixManager(private val latinIME: LatinIME) {
) {
Text(stringResource(R.string.blacklist))
}
if(wordBeingForgotten.value!!.mKindAndFlags == SuggestedWordInfo.KIND_EMOJI_SUGGESTION) {
TextButton(
onClick = {
runBlocking { latinIME.setSetting(SHOW_EMOJI_SUGGESTIONS, false) }
forgetWordDismissed.value = true
latinIME.refreshSuggestions()
}
) {
Text(stringResource(R.string.disable_emoji))
}
}
}
}
}

View File

@ -146,7 +146,7 @@ public class LanguageModelFacilitator(
}
}
} catch(e: TimeoutCancellationException) {
println("Failed to complete prediction within 1000ms!")
Log.d("LanguageModelFacilitator", "Failed to complete prediction within 1000ms!")
}
}
}
@ -207,7 +207,7 @@ public class LanguageModelFacilitator(
if(model != null) {
languageModel = LanguageModel(context, model, locale)
} else {
println("no model for ${locale.language}")
Log.d("LanguageModelFacilitator", "no model for ${locale.language}")
return
}
}
@ -264,10 +264,14 @@ public class LanguageModelFacilitator(
val suggestedWordsDict = holder.get(null, Constants.GET_SUGGESTED_WORDS_TIMEOUT.toLong())
println("LanguageModelFacilitator: suggestedWordsDict = ${suggestedWordsDict?.mSuggestedWordInfoList?.map { "$it ${it.mScore}" }}")
println("LanguageModelFacilitator: lmSuggestions = ${lmSuggestions.map { "$it ${it.mScore}" }}")
val suggestedWordsDictList = suggestedWordsDict?.mSuggestedWordInfoList?.filter {
suggestionBlacklist.isSuggestedWordOk(it)
}
val maxWordDict = suggestedWordsDict?.mSuggestedWordInfoList?.maxByOrNull {
Log.d("LanguageModelFacilitator", "suggestedWordsDict = ${suggestedWordsDictList?.map { "$it ${it.mScore}" }}")
Log.d("LanguageModelFacilitator", "lmSuggestions = ${lmSuggestions.map { "$it ${it.mScore}" }}")
val maxWordDict = suggestedWordsDictList?.maxByOrNull {
if(it == suggestedWordsDict.typedWordInfo) { Int.MIN_VALUE } else { it.mScore }
}
@ -285,7 +289,7 @@ public class LanguageModelFacilitator(
}
if(transformerWeight <= 0.0f) {
if(suggestedWordsDict?.mSuggestedWordInfoList.isNullOrEmpty()) {
if(suggestedWordsDictList.isNullOrEmpty()) {
transformerWeight = 1.0f
}
}
@ -296,9 +300,9 @@ public class LanguageModelFacilitator(
}
if(transformerWeight != Float.POSITIVE_INFINITY) {
suggestedWordsDict?.let { words ->
suggestionResults.addAll(words.mSuggestedWordInfoList.filter {
it != words.typedWordInfo && !filtered.contains(
suggestedWordsDictList?.let { words ->
suggestionResults.addAll(words.filter {
it != suggestedWordsDict.typedWordInfo && !filtered.contains(
it
)
}.take(10))
@ -314,9 +318,17 @@ public class LanguageModelFacilitator(
})?.let {
suggestionResults.add(it)
}
}else if(shouldSuggestEmojis) {
val prevWord =
values.ngramContext.fullContext.split(" ").lastOrNull { it.isNotBlank() }
if(prevWord != null) {
getEmojiCandidate(prevWord.trim())?.let {
suggestionResults.add(it)
}
}
}
println("LanguageModelFacilitator: final suggestionResults = ${suggestionResults.map { "$it ${it.mScore}" }}")
Log.d("LanguageModelFacilitator", "final suggestionResults = ${suggestionResults.map { "$it ${it.mScore}" }}")
val wordComposer = inputLogic.mWordComposer
val suggestedWords = Suggest.obtainNonBatchedInputSuggestedWords(
wordComposer, values.inputStyle, true, -1, locale, suggestionResults, settingsValues.mAutoCorrectionThreshold)
@ -343,7 +355,7 @@ public class LanguageModelFacilitator(
private var trainingEnabled = true
public fun launchProcessor() = lifecycleScope.launch {
println("LatinIME: Starting processor")
Log.d("LanguageModelFacilitator", "Starting processor")
launch {
withContext(Dispatchers.Default) {
TrainingWorkerStatus.lmRequest.collect {
@ -368,7 +380,7 @@ public class LanguageModelFacilitator(
launch {
withContext(Dispatchers.Default) {
sharedFlow.conflate().collect { value ->
println("LatinIME: Collecting")
Log.d("LanguageModelFacilitator", "Collecting")
processUpdateSuggestionStrip(value)
}
}
@ -428,11 +440,11 @@ public class LanguageModelFacilitator(
)
lifecycleScope.launch {
println("LatinIME: Emitting values")
Log.d("LanguageModelFacilitator", "Emitting values")
sharedFlow.emit(values)
}
} catch(e: Exception) {
println("Failed to get context, composed data snapshot, etc: $e")
Log.d("LanguageModelFacilitator", "Failed to get context, composed data snapshot, etc: $e")
e.printStackTrace()
}
}