summaryrefslogtreecommitdiff
path: root/platform-paper
diff options
context:
space:
mode:
Diffstat (limited to 'platform-paper')
-rw-r--r--platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverter.kt75
-rw-r--r--platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverterTest.kt21
2 files changed, 59 insertions, 37 deletions
diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverter.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverter.kt
index c961af8..a50a4aa 100644
--- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverter.kt
+++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverter.kt
@@ -2,6 +2,9 @@ package dev.m1sk9.lunaticChat.paper.converter
import dev.m1sk9.lunaticChat.engine.converter.GoogleIMEClient
import dev.m1sk9.lunaticChat.engine.converter.KanaConverter
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
import java.util.logging.Logger
class RomanjiConverter(
@@ -30,52 +33,50 @@ class RomanjiConverter(
return null
}
- val words = input.split(" ")
- val results = mutableListOf<String>()
+ val words = input.split(" ").filter { it.isNotEmpty() }
- for (word in words) {
- if (word.isEmpty()) {
- continue
+ // The words are independent, and callers convert under a timeout covering the whole
+ // message. Awaiting them one at a time makes an N-word message cost N round trips, so a
+ // long message runs out of budget after the first word or two.
+ val results =
+ coroutineScope {
+ words.map { word -> async { convertWord(word) } }.awaitAll()
}
- // Check cache first
- val cached = cache.get(word)
- if (cached != null) {
- if (debugMode) {
- logger.info("Cache hit for word: $word -> $cached")
- }
- results.add(cached)
- continue
- }
+ return results.joinToString(" ")
+ }
- // Pre-validate: Check if the word is valid romaji before attempting conversion
- // This prevents partial conversion of English words (e.g., "This" -> "てぃs")
- if (!KanaConverter.isValidRomaji(word)) {
- if (debugMode) {
- logger.info("Word is not valid romaji, keeping original: $word")
- }
- results.add(word)
- continue
+ private suspend fun convertWord(word: String): String {
+ cache.get(word)?.let { cached ->
+ if (debugMode) {
+ logger.info("Cache hit for word: $word -> $cached")
}
+ return cached
+ }
- // Step 1: Romanji -> Hiragana
- val hiragana = KanaConverter.toHiragana(word)
+ // Pre-validate: Check if the word is valid romaji before attempting conversion
+ // This prevents partial conversion of English words (e.g., "This" -> "てぃs")
+ if (!KanaConverter.isValidRomaji(word)) {
+ if (debugMode) {
+ logger.info("Word is not valid romaji, keeping original: $word")
+ }
+ return word
+ }
- // Step 2: Hiragana -> Kanji/Kana
- val converted =
- try {
- apiClient.convert(hiragana)
- } catch (e: Exception) {
- logger.warning("Failed to convert $hiragana: ${e.message}")
- hiragana // Use hiragana if API fails
- }
+ // Step 1: Romanji -> Hiragana
+ val hiragana = KanaConverter.toHiragana(word)
- // Cache the word-level conversion
- cache.put(word, converted)
- results.add(converted)
- }
+ // Step 2: Hiragana -> Kanji/Kana
+ val converted =
+ try {
+ apiClient.convert(hiragana)
+ } catch (e: Exception) {
+ logger.warning("Failed to convert $hiragana: ${e.message}")
+ hiragana // Use hiragana if API fails
+ }
- return results.joinToString(" ")
+ cache.put(word, converted)
+ return converted
}
private fun isRomajiOnly(input: String): Boolean =
diff --git a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverterTest.kt b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverterTest.kt
index 1e6d3c0..a7e0a52 100644
--- a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverterTest.kt
+++ b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/converter/RomanjiConverterTest.kt
@@ -7,7 +7,9 @@ import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
+import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
+import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
@@ -298,4 +300,23 @@ class RomanjiConverterTest {
assertEquals("おはよう", result)
verify(exactly = 1) { cache.put("ohayou", "おはよう") }
}
+
+ @Test
+ fun `words in one message are converted concurrently`() =
+ runBlocking {
+ val (converter, _, apiClient) = createConverter()
+ val inFlight = AtomicInteger(0)
+ val peakInFlight = AtomicInteger(0)
+
+ coEvery { apiClient.convert(any()) } coAnswers {
+ peakInFlight.updateAndGet { maxOf(it, inFlight.incrementAndGet()) }
+ delay(50)
+ inFlight.decrementAndGet()
+ "変換"
+ }
+
+ converter.convert("konnichiwa ohayou arigatou")
+
+ assertEquals(3, peakInFlight.get(), "each word should be in flight at the same time")
+ }
}