diff --git a/CHANGELOG.md b/CHANGELOG.md index d2af96e..20d4315 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ - automatic download and installation model - batch change language - model list reorder +- engine cache size +- number of threads per engine \ No newline at end of file diff --git a/app/src/main/java/com/k2fsa/sherpa/onnx/Tts.kt b/app/src/main/java/com/k2fsa/sherpa/onnx/Tts.kt index 5e6100c..6c1146f 100644 --- a/app/src/main/java/com/k2fsa/sherpa/onnx/Tts.kt +++ b/app/src/main/java/com/k2fsa/sherpa/onnx/Tts.kt @@ -159,7 +159,7 @@ fun getOfflineTtsConfig( model = "$modelDir/$modelName", lexicon = "$modelDir/$lexicon", tokens = "$modelDir/tokens.txt", - dataDir = "$dataDir" + dataDir = dataDir ), numThreads = 2, debug = true, diff --git a/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/conf/TtsConfig.kt b/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/conf/TtsConfig.kt index e674846..1a825c5 100644 --- a/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/conf/TtsConfig.kt +++ b/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/conf/TtsConfig.kt @@ -16,7 +16,19 @@ object TtsConfig { val timeoutDestruction = mutableDataSaverStateOf( dataSaverInterface = dataSaverPref, key = "timeoutDestruction", - initialValue = 0 + initialValue = 3 + ) + + val cacheSize = mutableDataSaverStateOf( + dataSaverInterface = dataSaverPref, + key = "cacheSize", + initialValue = 3 + ) + + val threadNum = mutableDataSaverStateOf( + dataSaverInterface = dataSaverPref, + key = "threadNum", + initialValue = 2 ) } \ No newline at end of file diff --git a/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/ModelManager.kt b/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/ModelManager.kt index f854c88..61d7c95 100644 --- a/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/ModelManager.kt +++ b/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/ModelManager.kt @@ -135,7 +135,6 @@ object ModelManager { tokens = format(tokens), dataDir = format(dataDir), ), - numThreads = 2, debug = true, provider = "cpu", ), diff --git a/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/SynthesizerCache.kt b/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/SynthesizerCache.kt index 4094633..84e745c 100644 --- a/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/SynthesizerCache.kt +++ b/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/SynthesizerCache.kt @@ -6,6 +6,8 @@ import java.util.concurrent.DelayQueue import java.util.concurrent.Delayed import java.util.concurrent.Executors import java.util.concurrent.TimeUnit +import kotlin.math.max +import kotlin.math.min interface ImplCache { @@ -13,10 +15,13 @@ interface ImplCache { } -class SynthesizerCache { +internal class SynthesizerCache { companion object { private val delayTime: Int - get() = 1000 * 60 * TtsConfig.timeoutDestruction.value + get() = 1000 * 60 * min(1, TtsConfig.timeoutDestruction.value) + + private val maxCacheSize: Int + get() = max(1, TtsConfig.cacheSize.value) } private val delayQueue = DelayQueue() @@ -44,15 +49,31 @@ class SynthesizerCache { } } + private fun limitSize() { + if (queueMap.size > maxCacheSize) { + val oldestEntry = + queueMap.entries.minByOrNull { it.value.getDelay(TimeUnit.MILLISECONDS) } + oldestEntry?.let { + queueMap.remove(it.key) + delayQueue.remove(it.value) + } + } + } + + @Synchronized fun cache(id: String, obj: ImplCache) { - val task = - DelayedDestroyTask(delayTime = delayTime, id, obj) + limitSize() + + val task = DelayedDestroyTask(delayTime = delayTime, id, obj) delayQueue.add(task) queueMap[id] = task ensureTaskRunning() } + @Synchronized fun getById(id: String): ImplCache? { + limitSize() + queueMap[id]?.let { if (it.getDelay(TimeUnit.MILLISECONDS) <= 1000 * 10) { // 小于10s便重置 it.reset() diff --git a/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/SynthesizerManager.kt b/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/SynthesizerManager.kt index 9a0d6bb..60af762 100644 --- a/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/SynthesizerManager.kt +++ b/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/synthesizer/SynthesizerManager.kt @@ -3,6 +3,8 @@ package com.k2fsa.sherpa.onnx.tts.engine.synthesizer import android.util.Log import com.k2fsa.sherpa.onnx.OfflineTts import com.k2fsa.sherpa.onnx.OfflineTtsConfig +import com.k2fsa.sherpa.onnx.tts.engine.conf.TtsConfig +import kotlin.math.max object SynthesizerManager { const val TAG = "SynthesizerManager" @@ -15,9 +17,11 @@ object SynthesizerManager { Log.d(TAG, "getTTS (from cache): ${it.config}") } - return tts ?: OfflineTts( - config = cfg - ).run { + val model = cfg.model.copy( + numThreads = max(1, TtsConfig.threadNum.value) + ) + + return tts ?: OfflineTts(config = cfg.copy(model = model)).run { cacheTTS(cfg.model.vits.model, this) this } diff --git a/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/ui/settings/SettingsScreen.kt b/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/ui/settings/SettingsScreen.kt index 0815825..b8ee527 100644 --- a/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/com/k2fsa/sherpa/onnx/tts/engine/ui/settings/SettingsScreen.kt @@ -17,20 +17,41 @@ fun SettingsScreen() { Scaffold { paddingValues -> Column(Modifier.padding(paddingValues)) { DividerPreference { - Text(stringResource(id = R.string.engine_cache)) + Text(stringResource(id = R.string.engine)) } var timeout by remember { TtsConfig.timeoutDestruction } val timeoutStr = stringResource(id = R.string.minute_format, timeout) SliderPreference( valueRange = 1f..60f, - steps = 60, title = { Text(stringResource(R.string.timeout_destruction)) }, subTitle = { Text(stringResource(R.string.timeout_destruction_summary))}, value = timeout.toFloat(), onValueChange = { timeout = it.toInt() }, label = timeoutStr ) + + var cacheSize by remember { TtsConfig.cacheSize } + val cacheSizeStr = cacheSize.toString() + SliderPreference( + valueRange = 1f..10f, + title = { Text(stringResource(R.string.cache_size)) }, + subTitle = { Text(stringResource(R.string.cache_size_summary))}, + value = cacheSize.toFloat(), + onValueChange = { cacheSize = it.toInt() }, + label = cacheSizeStr + ) + + var threadNum by remember { TtsConfig.threadNum } + val threadNumStr = threadNum.toString() + SliderPreference( + valueRange = 1f..8f, + title = { Text(stringResource(R.string.thread_num)) }, + subTitle = { Text(stringResource(R.string.thread_num_summary))}, + value = threadNum.toFloat(), + onValueChange = { threadNum = it.toInt() }, + label = threadNumStr + ) } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eb3ed08..54cf0e0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,7 +19,7 @@ Seekbar remove Seekbar add Close - Engine cache + Engine Timeout destruction %1$s min The model is automatically destroyed after it has not been used for a specified period of time to save running memory. @@ -53,4 +53,8 @@ Model installation failed ❌ Model installed Timed out + Cache size + Maximum number of engine caches + Number of threads + Maximum number of threads per engine \ No newline at end of file