From acc2215b7a5fe73f2dfd000569e789f528f2a0d0 Mon Sep 17 00:00:00 2001 From: Github Executorch Date: Thu, 12 Mar 2026 00:06:48 -0700 Subject: [PATCH 1/3] Title: Cache ParakeetModule across transcription calls to avoid repeated model loading Summary: Currently, runParakeetOnWavFile() creates a new ParakeetModule and calls .close() on every transcription request (L235-251). This means the model is loaded from disk on every single inference call, and the reported latency includes model load time. This change caches the ParakeetModule at the class level and only recreates it when the user changes model settings. --- .../com/example/parakeetapp/MainActivity.kt | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt b/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt index 183a9f90..bc47c9ee 100644 --- a/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt +++ b/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt @@ -82,6 +82,12 @@ class MainActivity : ComponentActivity() { private lateinit var viewModel: ModelSettingsViewModel private lateinit var downloadViewModel: ModelDownloadViewModel + // Cached ParakeetModule: loaded once and reused across transcription calls. + private var parakeetModule: ParakeetModule? = null + private var loadedModelPath: String = "" + private var loadedTokenizerPath: String = "" + private var loadedDataPath: String? = null + enum class Screen { DOWNLOAD, MAIN, @@ -211,6 +217,35 @@ class MainActivity : ComponentActivity() { }.start() } + /** + * Returns the cached ParakeetModule, creating or recreating it only if + * the model settings have changed since the last load. + */ + private fun getOrCreateModule(settings: ModelSettings): ParakeetModule { + val dataPath = settings.dataPath.ifBlank { null } + if (parakeetModule != null && + loadedModelPath == settings.modelPath && + loadedTokenizerPath == settings.tokenizerPath && + loadedDataPath == dataPath + ) { + return parakeetModule!! + } + + // Settings changed or first load — close the old module and create a new one. + parakeetModule?.close() + Log.v(TAG, "Loading model: ${settings.modelPath}") + val module = ParakeetModule( + modelPath = settings.modelPath, + tokenizerPath = settings.tokenizerPath, + dataPath = dataPath + ) + parakeetModule = module + loadedModelPath = settings.modelPath + loadedTokenizerPath = settings.tokenizerPath + loadedDataPath = dataPath + return module + } + /** * Common method to run Parakeet on a WAV file path. */ @@ -232,24 +267,18 @@ class MainActivity : ComponentActivity() { buttonEnabled = false } - val parakeetModule = ParakeetModule( - modelPath = settings.modelPath, - tokenizerPath = settings.tokenizerPath, - dataPath = settings.dataPath.ifBlank { null } - ) + val module = getOrCreateModule(settings) Log.v(TAG, "Starting transcribe for: $wavFilePath") runOnUiThread { statusText = "Transcribing..." } val startTime = System.currentTimeMillis() - val result = parakeetModule.transcribe(wavFilePath) + val result = module.transcribe(wavFilePath) val elapsedTime = System.currentTimeMillis() - startTime val elapsedSeconds = elapsedTime / 1000.0 Log.v(TAG, "Finished transcribe in ${elapsedSeconds}s") - parakeetModule.close() - runOnUiThread { transcriptionOutput = result statusText = "Transcription complete (%.2fs)".format(elapsedSeconds) @@ -468,6 +497,8 @@ class MainActivity : ComponentActivity() { if (isRecording) { stopRecording() } + parakeetModule?.close() + parakeetModule = null } private val requestPermissionLauncher = registerForActivityResult( From 5d31ee7c9e22de20eecb41faf4ea58d2b13b923d Mon Sep 17 00:00:00 2001 From: Siddartha Pothapragada Date: Thu, 12 Mar 2026 00:48:51 -0700 Subject: [PATCH 2/3] Update parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../com/example/parakeetapp/MainActivity.kt | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt b/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt index bc47c9ee..1fd0d05e 100644 --- a/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt +++ b/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt @@ -231,19 +231,38 @@ class MainActivity : ComponentActivity() { return parakeetModule!! } - // Settings changed or first load — close the old module and create a new one. - parakeetModule?.close() + // Settings changed or first load — construct the new module first, + // then swap it in and close the old one only after successful creation. + val oldModule = parakeetModule + + // Clear cached module and paths so a failed load never returns a closed or stale module. + parakeetModule = null + loadedModelPath = null + loadedTokenizerPath = null + loadedDataPath = null + Log.v(TAG, "Loading model: ${settings.modelPath}") - val module = ParakeetModule( - modelPath = settings.modelPath, - tokenizerPath = settings.tokenizerPath, - dataPath = dataPath - ) - parakeetModule = module + val newModule = try { + ParakeetModule( + modelPath = settings.modelPath, + tokenizerPath = settings.tokenizerPath, + dataPath = dataPath + ) + } catch (e: Exception) { + // Leave cache cleared; do not close the old module here since it may still be in use. + throw e + } + + // Successfully created the new module; now it is safe to close the old one + // and update the cached references and paths. + oldModule?.close() + + parakeetModule = newModule loadedModelPath = settings.modelPath loadedTokenizerPath = settings.tokenizerPath loadedDataPath = dataPath - return module + + return newModule } /** From defd144dbb59cf4d944c6da9b2bfb665f644672e Mon Sep 17 00:00:00 2001 From: Siddartha Pothapragada Date: Thu, 12 Mar 2026 00:49:06 -0700 Subject: [PATCH 3/3] Update parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../app/src/main/java/com/example/parakeetapp/MainActivity.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt b/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt index 1fd0d05e..0fafcafb 100644 --- a/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt +++ b/parakeet/android/ParakeetApp/app/src/main/java/com/example/parakeetapp/MainActivity.kt @@ -516,8 +516,6 @@ class MainActivity : ComponentActivity() { if (isRecording) { stopRecording() } - parakeetModule?.close() - parakeetModule = null } private val requestPermissionLauncher = registerForActivityResult(