@@ -48,6 +48,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager
4848import kotlinx.coroutines.delay
4949import kotlinx.coroutines.launch
5050import kotlinx.coroutines.withContext
51+ import java.io.File
5152import java.io.IOException
5253import java.util.concurrent.atomic.AtomicBoolean
5354
@@ -331,8 +332,8 @@ class PhotoReasoningViewModel(
331332 if (missingFiles.isNotEmpty()) {
332333 return " Offline model files missing: ${missingFiles.joinToString(" , " )} . Please redownload the model package."
333334 }
334- val modelFile = ModelDownloadManager .getModelFile(context, currentModel)
335- if (modelFile != null && modelFile .exists()) {
335+ val selectedModelFile = ModelDownloadManager .getModelFile(context, currentModel)
336+ if (selectedModelFile != null && selectedModelFile .exists()) {
336337 // Load backend preference
337338 GenerativeAiViewModelFactory .loadBackendPreference(context)
338339 val backend = GenerativeAiViewModelFactory .getBackend()
@@ -342,41 +343,77 @@ class PhotoReasoningViewModel(
342343 if (! isLiteRtAbiSupported()) {
343344 return " Offline LiteRT models are only supported on arm64-v8a or x86_64 devices."
344345 }
346+
347+ val externalFilesDir = context.getExternalFilesDir(null )
348+ val candidateNames = linkedSetOf<String >().apply {
349+ add(selectedModelFile.name)
350+ currentModel.offlineModelFilename?.let { add(it) }
351+ addAll(currentModel.offlineAlternateModelFilenames)
352+ }
353+ val candidateFiles = candidateNames
354+ .mapNotNull { name -> externalFilesDir?.let { File (it, name) } }
355+ .filter { it.exists() && it.length() > 0L }
356+
345357 Log .i(
346358 TAG ,
347359 " Initializing LiteRT engine for ${currentModel.displayName} . preferredBackend=$backend , " +
348360 " abis=${Build .SUPPORTED_ABIS ?.joinToString() ? : " unknown" } , " +
349- " modelPath =${modelFile.absolutePath} , modelSizeBytes= ${modelFile. length()}"
361+ " candidateFiles =${candidateFiles.joinToString { " ${it.name} ( ${it. length()} B) " } } "
350362 )
363+
351364 if (liteRtEngine == null ) {
352365 val preferredBackend = if (backend == InferenceBackend .GPU ) Backend .GPU () else Backend .CPU ()
353- val useVisionBackend = currentModel.requiresVisionBackend &&
354- modelFile.name.contains(" multimodal" , ignoreCase = true )
355- val preferredVisionBackend = if (useVisionBackend) {
356- if (backend == InferenceBackend .GPU ) Backend .GPU () else Backend .CPU ()
357- } else {
358- null
359- }
360- val audioBackend = null
361- val cacheDir =
362- if (modelFile.absolutePath.startsWith(" /data/local/tmp" )) {
363- context.getExternalFilesDir(null )?.absolutePath
364- } else {
365- null
366+
367+ val attempts = if (candidateFiles.isNotEmpty()) candidateFiles else listOf (selectedModelFile)
368+ val failureDetails = StringBuilder ()
369+
370+ attempts.forEachIndexed { index, modelFile ->
371+ try {
372+ val useVisionBackend = currentModel.requiresVisionBackend &&
373+ modelFile.name.contains(" multimodal" , ignoreCase = true )
374+ val preferredVisionBackend = if (useVisionBackend) {
375+ if (backend == InferenceBackend .GPU ) Backend .GPU () else Backend .CPU ()
376+ } else {
377+ null
378+ }
379+ val audioBackend = null
380+ val cacheDir =
381+ if (modelFile.absolutePath.startsWith(" /data/local/tmp" )) {
382+ context.getExternalFilesDir(null )?.absolutePath
383+ } else {
384+ null
385+ }
386+
387+ Log .i(
388+ TAG ,
389+ " LiteRT model file attempt ${index + 1 } /${attempts.size} : " +
390+ " modelFile=${modelFile.absolutePath} , size=${modelFile.length()} , useVision=$useVisionBackend "
391+ )
392+
393+ liteRtEngine = createLiteRtEngineWithFallbacks(
394+ modelPath = modelFile.absolutePath,
395+ preferredBackend = preferredBackend,
396+ preferredVisionBackend = preferredVisionBackend,
397+ audioBackend = audioBackend,
398+ cacheDir = cacheDir
399+ )
400+ Log .d(TAG , " Offline model initialized with LiteRT-LM Engine using ${modelFile.name} " )
401+ return null
402+ } catch (e: Exception ) {
403+ val msg = e.message ? : e.toString()
404+ failureDetails.append(" ${modelFile.name} : $msg \n " )
405+ Log .e(TAG , " LiteRT file attempt failed for ${modelFile.name} " , e)
366406 }
367- liteRtEngine = createLiteRtEngineWithFallbacks(
368- modelPath = modelFile.absolutePath,
369- preferredBackend = preferredBackend,
370- preferredVisionBackend = preferredVisionBackend,
371- audioBackend = audioBackend,
372- cacheDir = cacheDir
407+ }
408+
409+ throw IllegalStateException (
410+ " All model-file attempts failed for ${currentModel.displayName} .\n $failureDetails "
373411 )
374- Log .d(TAG , " Offline model initialized with LiteRT-LM Engine" )
375412 }
376413 } else {
377414 if (llmInference == null ) {
378415 val optionsBuilder = LlmInference .LlmInferenceOptions .builder()
379- .setModelPath(modelFile .absolutePath)
416+ .setModelPath(selectedModelFile .absolutePath)
380417 .setMaxTokens(4096 )
381418
382419 // Set preferred backend (CPU or GPU)
0 commit comments