mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-11 00:12:24 +01:00
voice: recommend Canary for the final words, at a third of Parakeet large's size
This commit is contained in:
1 parent
9100dac290
commit
e13b0618db
4 files changed
+10
-8
No files matched your search
@@ -67,7 +67,7 @@ object SpeechEngine {
|
||||
|
||||
private val worker = Executors.newSingleThreadExecutor { Thread(it, "gearslip-speech") }
|
||||
/**
|
||||
* Parakeet large takes seconds to load. On [worker], the first press after connecting
|
||||
* The final model takes seconds to load. On [worker], the first press after connecting
|
||||
* waited behind it before listening at all; here it loads while the driver talks.
|
||||
*/
|
||||
private val finalWorker = Executors.newSingleThreadExecutor { Thread(it, "gearslip-speech-final") }
|
||||
@@ -80,7 +80,7 @@ object SpeechEngine {
|
||||
@Volatile private var loadedFinal: SpeechModels.Model? = null
|
||||
|
||||
/**
|
||||
* Parakeet large holds most of the ~900 MB the two models take, so it goes after a few
|
||||
* The final model holds most of the memory the two models take, so it goes after a few
|
||||
* minutes without a command. Kroko stays: it's small, and keeps listening instant.
|
||||
*/
|
||||
private val idleUnload = Runnable { unloadFinal("after ${IDLE_UNLOAD_MS / 60_000} minutes without use") }
|
||||
|
||||
@@ -51,12 +51,12 @@ object SpeechModels {
|
||||
plainFiles = false,
|
||||
),
|
||||
CANARY(
|
||||
Role.FINAL, "canary-180m-en", "Canary", "In between: better than Parakeet small, quicker than large. NVIDIA NeMo, CC BY 4.0", 198,
|
||||
Role.FINAL, "canary-180m-en", "Canary", "Recommended. Quick, and hears names and places well. NVIDIA NeMo, CC BY 4.0", 198,
|
||||
"sherpa-onnx-nemo-canary-180m-flash-en-es-de-fr-int8",
|
||||
"encoder.int8.onnx", "decoder.int8.onnx", "", modelType = "canary",
|
||||
),
|
||||
PARAKEET_LARGE(
|
||||
Role.FINAL, "parakeet-0.6b-en", "Parakeet large", "Recommended. Hears names and places best. NVIDIA NeMo, CC BY 4.0", 631,
|
||||
Role.FINAL, "parakeet-0.6b-en", "Parakeet large", "Hears names best, but slower and three times the size. NVIDIA NeMo, CC BY 4.0", 631,
|
||||
"sherpa-onnx-nemo-parakeet-tdt-0.6b-v2-int8",
|
||||
"encoder.int8.onnx", "decoder.int8.onnx", "joiner.int8.onnx", modelType = "nemo_transducer",
|
||||
),
|
||||
@@ -82,7 +82,7 @@ object SpeechModels {
|
||||
private val states = Model.entries.associateWith { MutableStateFlow<State>(State.Missing) }
|
||||
private val _selected = MutableStateFlow(Model.KROKO)
|
||||
val selected: StateFlow<Model> = _selected.asStateFlow()
|
||||
private val _final = MutableStateFlow<Model?>(Model.PARAKEET_LARGE)
|
||||
private val _final = MutableStateFlow<Model?>(Model.CANARY)
|
||||
|
||||
/** The model that rereads the whole phrase at the end; null to keep the live model's words. */
|
||||
val final: StateFlow<Model?> = _final.asStateFlow()
|
||||
@@ -91,7 +91,9 @@ object SpeechModels {
|
||||
fun init(context: Context) {
|
||||
val id = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE).getString(KEY_MODEL, null)
|
||||
_selected.value = Model.entries.firstOrNull { it.id == id && it.role == Role.LIVE } ?: Model.KROKO
|
||||
val finalId = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE).getString(KEY_FINAL, Model.PARAKEET_LARGE.id)
|
||||
// Canary is the default. A driver who never chose but already has Parakeet large keeps it.
|
||||
val finalId = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE).getString(KEY_FINAL, null)
|
||||
?: if (isReady(context, Model.PARAKEET_LARGE) && !isReady(context, Model.CANARY)) Model.PARAKEET_LARGE.id else Model.CANARY.id
|
||||
_final.value = Model.entries.firstOrNull { it.id == finalId && it.role == Role.FINAL }
|
||||
Model.entries.forEach { m -> if (isReady(context, m)) states.getValue(m).value = State.Ready }
|
||||
// Models an older build offered and this one doesn't: hundreds of MB nobody can use.
|
||||
|
||||
@@ -402,7 +402,7 @@ private fun BadgeStep(
|
||||
private fun VoiceStep(c: IntroColors, cq: (Float) -> Dp, cqSp: (Float) -> TextUnit, key: IntroStep) {
|
||||
val context = LocalContext.current
|
||||
remember { SpeechModels.init(context) }
|
||||
val needed = listOf(SpeechModels.Model.KROKO, SpeechModels.Model.PARAKEET_LARGE)
|
||||
val needed = listOf(SpeechModels.Model.KROKO, SpeechModels.Model.CANARY)
|
||||
val states = needed.map { SpeechModels.state(it).collectAsState().value }
|
||||
val ready = states.all { it == SpeechModels.State.Ready }
|
||||
val label = when {
|
||||
|
||||
@@ -38,7 +38,7 @@ internal fun VoiceModelSection() {
|
||||
SettingsSection(title = "Voice: live words") {
|
||||
Text(
|
||||
"The voice assistant turns speech into text on this phone, and nothing you say leaves it. " +
|
||||
"It needs two models, about 700 MB together, downloaded once. Use Wi-Fi if you can. " +
|
||||
"It needs two models, about 270 MB together, downloaded once. " +
|
||||
"This one writes your words as you speak.",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
|
||||
Reference in new issue
Block a user