Skip to content

Commit

Permalink
fix: better getWordCount logic
Browse files Browse the repository at this point in the history
  • Loading branch information
plateaukao committed Sep 22, 2024
1 parent 5a5f9d2 commit eb9de3b
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 21 deletions.
12 changes: 12 additions & 0 deletions app/src/main/java/info/plateaukao/einkbro/tts/ETts.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package info.plateaukao.einkbro.tts

import android.util.Log
import info.plateaukao.einkbro.EinkBroApplication
import info.plateaukao.einkbro.tts.entity.VoiceItem
import okhttp3.Headers.Companion.toHeaders
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import okio.ByteString
Expand Down Expand Up @@ -154,12 +156,22 @@ class ETts {
private open class TTSWebSocketListener : WebSocketListener() {
var byteArray: ByteArray = ByteArray(0)

override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
super.onClosing(webSocket, code, reason)
webSocket.close(1000, null)
}
override fun onMessage(webSocket: WebSocket, text: String) {
if (text.contains("Path:turn.end")) {
webSocket.close(1000, null)
}
}

override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
super.onFailure(webSocket, t, response)
response?.close()
Log.d("TTSWebSocketListener", "onFailure: ${t.message}")
}

override fun onMessage(webSocket: WebSocket, bytes: ByteString) =
fixHeadHook(bytes.toByteArray())

Expand Down
11 changes: 10 additions & 1 deletion app/src/main/java/info/plateaukao/einkbro/unit/HelperUnit.kt
Original file line number Diff line number Diff line change
Expand Up @@ -702,9 +702,18 @@ fun String.getWordCount(): Int {
val trimmedInput = trim()
if (trimmedInput.isEmpty()) return 0

// CJ
if (endsWith("") || endsWith("") || endsWith("")) {
return trimmedInput.length
}
// korean
val hangulRegex = "[가-힣]+".toRegex() // Matches any Hangul syllable
// Find all matches and return the count
val hangulCount = hangulRegex.findAll(trimmedInput).sumOf { it.value.length }
if (hangulCount > 3) return hangulCount

// Use regex to match words based on Unicode word boundaries
val wordRegex = "\\p{L}+".toRegex()

// Find all matches and return the count
return wordRegex.findAll(trimmedInput).count()
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class TtsSettingDialogFragment : ComposeDialogFragment() {
val ettsVoice = remember { mutableStateOf(config.ettsVoice) }
val gptVoice = remember { mutableStateOf(config.gptVoiceOption) }
val readProgress = ttsViewModel.readProgress.collectAsState()
val readingState = ttsViewModel.isReading.collectAsState()

Column(
modifier = Modifier
Expand Down Expand Up @@ -87,8 +88,8 @@ class TtsSettingDialogFragment : ComposeDialogFragment() {
onVoiceSelected = { config.ettsVoice = it; dismiss() },
)
TtsDialogButtonBar(
isPlaying = ttsViewModel.isReading(),
isVoiceReading = ttsViewModel.isVoicePlaying(),
readingState = readingState.value,
isVoicePlaying = ttsViewModel.isVoicePlaying(),
showSystemSetting = ttsType.value == TtsType.SYSTEM,
readProgress = readProgress.value,
gotoSettingAction = { IntentUnit.gotoSystemTtsSettings(requireActivity()) },
Expand Down Expand Up @@ -277,8 +278,8 @@ private fun MainTtsSettingDialog(

@Composable
fun TtsDialogButtonBar(
isPlaying: Boolean,
isVoiceReading: Boolean,
readingState: Boolean,
isVoicePlaying: Boolean,
showSystemSetting: Boolean,
readProgress: String,
stopAction: () -> Unit,
Expand Down Expand Up @@ -307,7 +308,7 @@ fun TtsDialogButtonBar(
)
}
} else {
if (isPlaying) {
if (readingState) {
Text(
readProgress,
modifier = Modifier.padding(horizontal = 8.dp),
Expand All @@ -329,7 +330,7 @@ fun TtsDialogButtonBar(
modifier = Modifier.wrapContentWidth()
) {
Icon(
if (isVoiceReading) Icons.Default.Pause else Icons.Default.PlayArrow,
if (isVoicePlaying) Icons.Default.Pause else Icons.Default.PlayArrow,
"pause or resume",
tint = MaterialTheme.colors.onBackground
)
Expand Down
41 changes: 27 additions & 14 deletions app/src/main/java/info/plateaukao/einkbro/viewmodel/TtsViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@ class TtsViewModel : ViewModel(), KoinComponent {
private val mediaPlayer by lazy { MediaPlayer() }
private var byteArrayChannel: Channel<ByteArray>? = null

// for showing play controls state
private val _speakingState = MutableStateFlow(false)
val speakingState: StateFlow<Boolean> = _speakingState.asStateFlow()

private val _isReading = MutableStateFlow(false)
val isReading: StateFlow<Boolean> = _isReading.asStateFlow()

private val _readProgress = MutableStateFlow("")
val readProgress: StateFlow<String> = _readProgress.asStateFlow()

Expand All @@ -53,6 +57,8 @@ class TtsViewModel : ViewModel(), KoinComponent {
private val articlesToBeRead: MutableList<String> = mutableListOf()

fun readArticle(text: String) {
_isReading.value = true

articlesToBeRead.add(text)
if (isReading()) {
return
Expand Down Expand Up @@ -94,25 +100,19 @@ class TtsViewModel : ViewModel(), KoinComponent {
delay(2000)
}
_speakingState.value = false
_isReading.value = false
}

private suspend fun readByEngine(ttsType: TtsType, text: String) {
byteArrayChannel = Channel(1)
val chunks = processedTextToChunks(text)

viewModelScope.launch(Dispatchers.IO) {
_speakingState.value = true

val chunks = processedTextToChunks(text)
chunks.forEachIndexed { index, chunk ->
if (byteArrayChannel == null) return@launch

_readProgress.value =
"${index + 1}/${chunks.size} " + if (articlesToBeRead.isNotEmpty()) {
"(${articlesToBeRead.size})"
} else {
""
}

fetchSemaphore.withPermit {
Log.d("TtsViewModel", "tts sentence fetch: $chunk")
val byteArray = if (ttsType == TtsType.ETTS) {
Expand All @@ -122,9 +122,9 @@ class TtsViewModel : ViewModel(), KoinComponent {
}

if (byteArray != null) {
Log.d("TtsViewModel", "tts sentence send: $chunk")
Log.d("TtsViewModel", "tts sentence send ($index) : $chunk")
byteArrayChannel?.send(byteArray)
Log.d("TtsViewModel", "tts sentence sent: $chunk")
Log.d("TtsViewModel", "tts sentence sent ($index) : $chunk")
}
}
}
Expand All @@ -134,22 +134,34 @@ class TtsViewModel : ViewModel(), KoinComponent {
var index = 0
for (byteArray in byteArrayChannel!!) {
Log.d("TtsViewModel", "play audio $index")
_readProgress.value =
"${index + 1}/${chunks.size} " +
if (articlesToBeRead.isNotEmpty()) {
"(${articlesToBeRead.size})"
} else {
""
}

playAudioByteArray(byteArray)
index++
if (byteArrayChannel?.isClosedForSend == true && byteArrayChannel?.isEmpty == true
) break
if (byteArrayChannel?.isClosedForSend == true &&
byteArrayChannel?.isEmpty == true) break
}

_speakingState.value = false
byteArrayChannel = null

if (articlesToBeRead.isEmpty()) {
_isReading.value = false
}
}

private fun processedTextToChunks(text: String): MutableList<String> {
val processedText = text.replace("\\n", " ").replace("\\\"", "").replace("\\t", "")
val processedText = text.replace("\\n", " ").replace("\\\"", "").replace("\\t", "").replace("\\", "")
val sentences = processedText.split("(?<=\\.)(?!\\d)|(?<=。)|(?<=?)|(?<=\\?)".toRegex())
val chunks = sentences.fold(mutableListOf<String>()) { acc, sentence ->
Log.d("TtsViewModel", "sentence: $sentence")
if (acc.isEmpty() || (acc.last() + sentence).getWordCount() > 80) {
if (acc.isEmpty() || (acc.last() + sentence).getWordCount() > 60) {
acc.add(sentence.trim())
} else {
val last = acc.last()
Expand Down Expand Up @@ -195,6 +207,7 @@ class TtsViewModel : ViewModel(), KoinComponent {
articlesToBeRead.clear()

_speakingState.value = false
_isReading.value = false
}

fun isReading(): Boolean {
Expand Down

0 comments on commit eb9de3b

Please sign in to comment.