From d66f53225c5601988d6d0ed678667c2815b9901b Mon Sep 17 00:00:00 2001 From: Marina Coelho Date: Wed, 25 Mar 2026 12:06:30 +0000 Subject: [PATCH 1/4] Add Hybrid inference to generate ingredients --- app/build.gradle.kts | 1 + .../data/datasource/AIRemoteDataSource.kt | 62 +++++++++++++++++++ .../data/repository/AIRepository.kt | 8 +++ .../ui/generate/GenerateViewModel.kt | 12 +++- gradle/libs.versions.toml | 5 +- 5 files changed, 86 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a07fc2a..da099ff 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -63,6 +63,7 @@ dependencies { implementation(platform(libs.firebase.bom)) implementation(libs.firebase.ai) + implementation(libs.firebase.ai.ondevice) implementation(libs.firebase.config) implementation(libs.firebase.auth) implementation(libs.firebase.storage) diff --git a/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt b/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt index 1878b28..7bc82e2 100644 --- a/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt +++ b/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt @@ -1,10 +1,18 @@ package com.google.firebase.example.friendlymeals.data.datasource import android.graphics.Bitmap +import android.util.Log +import com.google.firebase.ai.FirebaseAI +import com.google.firebase.ai.InferenceMode +import com.google.firebase.ai.OnDeviceConfig import com.google.firebase.ai.TemplateGenerativeModel import com.google.firebase.ai.TemplateImagenModel +import com.google.firebase.ai.ondevice.DownloadStatus +import com.google.firebase.ai.ondevice.FirebaseAIOnDevice +import com.google.firebase.ai.ondevice.OnDeviceModelStatus import com.google.firebase.ai.type.ImagePart import com.google.firebase.ai.type.PublicPreviewAPI +import com.google.firebase.ai.type.content import com.google.firebase.example.friendlymeals.data.schema.MealSchema import com.google.firebase.example.friendlymeals.data.schema.RecipeSchema import com.google.firebase.remoteconfig.FirebaseRemoteConfig @@ -13,6 +21,7 @@ import javax.inject.Inject @OptIn(PublicPreviewAPI::class) class AIRemoteDataSource @Inject constructor( + private val aiModel: FirebaseAI, private val generativeModel: TemplateGenerativeModel, private val imagenModel: TemplateImagenModel, private val remoteConfig: FirebaseRemoteConfig @@ -31,6 +40,25 @@ class AIRemoteDataSource @Inject constructor( return response.text.orEmpty() } + @OptIn(PublicPreviewAPI::class) + suspend fun generateIngredientsHybrid(image: Bitmap): String { + val hybridGenerativeModel = aiModel.generativeModel( + modelName = "gemini-3-flash-preview", + onDeviceConfig = OnDeviceConfig(mode = InferenceMode.PREFER_IN_CLOUD) + ) + + val prompt = content { + image(image) + text("Please analyze this image and list all visible food ingredients. " + + "Output ONLY a comma-separated list of ingredients. Do not include " + + "any introductory text, headers, or concluding remarks. " + + "Provide the raw list only. Be specific with measurements where possible.") + } + + val response = hybridGenerativeModel.generateContent(prompt) + return response.text.orEmpty() + } + suspend fun generateRecipe(ingredients: String, notes: String): RecipeSchema? { val response = generativeModel.generateContent( templateId = remoteConfig.getString(GENERATE_RECIPE_KEY), @@ -80,6 +108,37 @@ class AIRemoteDataSource @Inject constructor( } } + suspend fun loadOnDeviceModel() { + when (FirebaseAIOnDevice.checkStatus()) { + OnDeviceModelStatus.UNAVAILABLE -> { + Log.w(TAG, "On-device model is unavailable") + } + OnDeviceModelStatus.DOWNLOADABLE -> { + FirebaseAIOnDevice.download().collect { status -> + when (status) { + is DownloadStatus.DownloadStarted -> + Log.w(TAG, "Starting download - ${status.bytesToDownload}") + + is DownloadStatus.DownloadInProgress -> + Log.w(TAG, "Download in progress ${status.totalBytesDownloaded} bytes downloaded") + + is DownloadStatus.DownloadCompleted -> + Log.w(TAG, "On-device model download complete") + + is DownloadStatus.DownloadFailed -> + Log.e(TAG, "Download failed ${status}") + } + } + } + OnDeviceModelStatus.DOWNLOADING -> { + Log.w(TAG, "On-device model is being downloaded") + } + OnDeviceModelStatus.AVAILABLE -> { + Log.w(TAG, "On-device model is available") + } + } + } + companion object { //Remote Config Keys private const val GENERATE_INGREDIENTS_KEY = "generate_ingredients" @@ -97,5 +156,8 @@ class AIRemoteDataSource @Inject constructor( //Template input values private const val MIME_TYPE_VALUE = "image/jpeg" + + //Class TAG + private const val TAG = "AIRemoteDataSource" } } \ No newline at end of file diff --git a/app/src/main/java/com/google/firebase/example/friendlymeals/data/repository/AIRepository.kt b/app/src/main/java/com/google/firebase/example/friendlymeals/data/repository/AIRepository.kt index a85113e..6f642f1 100644 --- a/app/src/main/java/com/google/firebase/example/friendlymeals/data/repository/AIRepository.kt +++ b/app/src/main/java/com/google/firebase/example/friendlymeals/data/repository/AIRepository.kt @@ -13,6 +13,10 @@ class AIRepository @Inject constructor( return aiRemoteDataSource.generateIngredients(imageData) } + suspend fun generateIngredientsHybrid(image: Bitmap): String { + return aiRemoteDataSource.generateIngredientsHybrid(image) + } + suspend fun generateRecipe(ingredients: String, notes: String): RecipeSchema? { return aiRemoteDataSource.generateRecipe(ingredients, notes) } @@ -28,4 +32,8 @@ class AIRepository @Inject constructor( suspend fun scanMeal(imageData: String): MealSchema? { return aiRemoteDataSource.scanMeal(imageData) } + + suspend fun loadOnDeviceModel() { + aiRemoteDataSource.loadOnDeviceModel() + } } \ No newline at end of file diff --git a/app/src/main/java/com/google/firebase/example/friendlymeals/ui/generate/GenerateViewModel.kt b/app/src/main/java/com/google/firebase/example/friendlymeals/ui/generate/GenerateViewModel.kt index e8f8777..714712f 100644 --- a/app/src/main/java/com/google/firebase/example/friendlymeals/ui/generate/GenerateViewModel.kt +++ b/app/src/main/java/com/google/firebase/example/friendlymeals/ui/generate/GenerateViewModel.kt @@ -28,6 +28,7 @@ class GenerateViewModel @Inject constructor( init { loadCurrentUser() + loadOnDeviceModel() } fun loadCurrentUser() { @@ -39,6 +40,12 @@ class GenerateViewModel @Inject constructor( } } + fun loadOnDeviceModel() { + launchCatching { + aiRepository.loadOnDeviceModel() + } + } + fun onIngredientsUpdated(ingredients: String) { _viewState.value = _viewState.value.copy( ingredients = ingredients @@ -62,7 +69,10 @@ class GenerateViewModel @Inject constructor( ingredientsLoading = true ) - val ingredients = aiRepository.generateIngredients(image.toBase64()) + //The following line of code uses hybrid inference to generate ingredients. + //To use the cloud-hosted model only, comment line 74 and uncomment line 75. + val ingredients = aiRepository.generateIngredientsHybrid(image) + //val ingredients = aiRepository.generateIngredients(image.toBase64()) _viewState.value = _viewState.value.copy( ingredientsLoading = false, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b115e5a..0a951a2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,6 +2,8 @@ agp = "8.13.1" coilCompose = "2.7.0" exifinterface = "1.4.2" +firebaseAi = "17.10.1" +firebaseAiOndevice = "16.0.0-beta01" firebaseBom = "34.8.0" kotlin = "2.2.21" coreKtx = "1.17.0" @@ -26,9 +28,10 @@ richtextCommonmark = "1.0.0-alpha03" androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-exifinterface = { module = "androidx.exifinterface:exifinterface", version.ref = "exifinterface" } coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coilCompose" } +firebase-ai = { module = "com.google.firebase:firebase-ai", version.ref = "firebaseAi" } +firebase-ai-ondevice = { module = "com.google.firebase:firebase-ai-ondevice", version.ref = "firebaseAiOndevice" } firebase-auth = { module = "com.google.firebase:firebase-auth" } firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" } -firebase-ai = { module = "com.google.firebase:firebase-ai" } firebase-config = { module = "com.google.firebase:firebase-config" } firebase-firestore = { module = "com.google.firebase:firebase-firestore" } firebase-storage = { module = "com.google.firebase:firebase-storage" } From dd0ae8d17a04dc844f60c3e3dc5b013dbd6f9686 Mon Sep 17 00:00:00 2001 From: Marina Coelho Date: Wed, 25 Mar 2026 14:04:49 +0000 Subject: [PATCH 2/4] Add Performance Monitoring custom trace to monitor on performance on device and in cloud --- app/build.gradle.kts | 2 + .../data/datasource/AIRemoteDataSource.kt | 55 ++++++++++++------- build.gradle.kts | 1 + gradle/libs.versions.toml | 5 +- 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index da099ff..2189d6f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -6,6 +6,7 @@ plugins { alias(libs.plugins.google.ksp) alias(libs.plugins.google.hilt) alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.firebase.perf) } android { @@ -68,6 +69,7 @@ dependencies { implementation(libs.firebase.auth) implementation(libs.firebase.storage) implementation(libs.firebase.firestore) + implementation(libs.firebase.perf) //Library to handle Markdown in Compose implementation(libs.richtext.commonmark) diff --git a/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt b/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt index 7bc82e2..d424723 100644 --- a/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt +++ b/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt @@ -2,8 +2,10 @@ package com.google.firebase.example.friendlymeals.data.datasource import android.graphics.Bitmap import android.util.Log +import com.google.firebase.Firebase import com.google.firebase.ai.FirebaseAI import com.google.firebase.ai.InferenceMode +import com.google.firebase.ai.InferenceSource import com.google.firebase.ai.OnDeviceConfig import com.google.firebase.ai.TemplateGenerativeModel import com.google.firebase.ai.TemplateImagenModel @@ -15,6 +17,8 @@ import com.google.firebase.ai.type.PublicPreviewAPI import com.google.firebase.ai.type.content import com.google.firebase.example.friendlymeals.data.schema.MealSchema import com.google.firebase.example.friendlymeals.data.schema.RecipeSchema +import com.google.firebase.perf.performance +import com.google.firebase.perf.trace import com.google.firebase.remoteconfig.FirebaseRemoteConfig import kotlinx.serialization.json.Json import javax.inject.Inject @@ -42,21 +46,34 @@ class AIRemoteDataSource @Inject constructor( @OptIn(PublicPreviewAPI::class) suspend fun generateIngredientsHybrid(image: Bitmap): String { - val hybridGenerativeModel = aiModel.generativeModel( - modelName = "gemini-3-flash-preview", - onDeviceConfig = OnDeviceConfig(mode = InferenceMode.PREFER_IN_CLOUD) - ) + Firebase.performance.newTrace("hybrid-inference").trace { + val hybridGenerativeModel = aiModel.generativeModel( + modelName = "gemini-3-flash-preview", + onDeviceConfig = OnDeviceConfig(mode = InferenceMode.PREFER_IN_CLOUD) + ) - val prompt = content { - image(image) - text("Please analyze this image and list all visible food ingredients. " + - "Output ONLY a comma-separated list of ingredients. Do not include " + - "any introductory text, headers, or concluding remarks. " + - "Provide the raw list only. Be specific with measurements where possible.") - } + val prompt = content { + image(image) + text( + "Please analyze this image and list all visible food ingredients. " + + "Output ONLY a comma-separated list of ingredients. Do not include " + + "any introductory text, headers, or concluding remarks. " + + "Provide the raw list only. Be specific with measurements where possible." + ) + } - val response = hybridGenerativeModel.generateContent(prompt) - return response.text.orEmpty() + val response = hybridGenerativeModel.generateContent(prompt) + + putAttribute( + "inferenceSource", + when (response.inferenceSource) { + InferenceSource.ON_DEVICE -> "On device" + else -> "In cloud" + } + ) + + return response.text.orEmpty() + } } suspend fun generateRecipe(ingredients: String, notes: String): RecipeSchema? { @@ -111,19 +128,19 @@ class AIRemoteDataSource @Inject constructor( suspend fun loadOnDeviceModel() { when (FirebaseAIOnDevice.checkStatus()) { OnDeviceModelStatus.UNAVAILABLE -> { - Log.w(TAG, "On-device model is unavailable") + Log.i(TAG, "On-device model is unavailable") } OnDeviceModelStatus.DOWNLOADABLE -> { FirebaseAIOnDevice.download().collect { status -> when (status) { is DownloadStatus.DownloadStarted -> - Log.w(TAG, "Starting download - ${status.bytesToDownload}") + Log.i(TAG, "Starting download - ${status.bytesToDownload}") is DownloadStatus.DownloadInProgress -> - Log.w(TAG, "Download in progress ${status.totalBytesDownloaded} bytes downloaded") + Log.i(TAG, "Download in progress ${status.totalBytesDownloaded} bytes downloaded") is DownloadStatus.DownloadCompleted -> - Log.w(TAG, "On-device model download complete") + Log.i(TAG, "On-device model download complete") is DownloadStatus.DownloadFailed -> Log.e(TAG, "Download failed ${status}") @@ -131,10 +148,10 @@ class AIRemoteDataSource @Inject constructor( } } OnDeviceModelStatus.DOWNLOADING -> { - Log.w(TAG, "On-device model is being downloaded") + Log.i(TAG, "On-device model is being downloaded") } OnDeviceModelStatus.AVAILABLE -> { - Log.w(TAG, "On-device model is available") + Log.i(TAG, "On-device model is available") } } } diff --git a/build.gradle.kts b/build.gradle.kts index 7db73c4..074ea6b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,4 +6,5 @@ plugins { alias(libs.plugins.google.services) apply false alias(libs.plugins.google.hilt) apply false alias(libs.plugins.google.ksp) apply false + alias(libs.plugins.firebase.perf) apply false } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0a951a2..f3d74d2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,7 @@ coilCompose = "2.7.0" exifinterface = "1.4.2" firebaseAi = "17.10.1" firebaseAiOndevice = "16.0.0-beta01" -firebaseBom = "34.8.0" +firebaseBom = "34.11.0" kotlin = "2.2.21" coreKtx = "1.17.0" junit = "4.13.2" @@ -23,6 +23,7 @@ navigationCompose = "2.9.6" constraintlayoutCompose = "1.1.1" kotlinxSerializationJson = "1.9.0" richtextCommonmark = "1.0.0-alpha03" +firebasePerf = "2.0.2" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -34,6 +35,7 @@ firebase-auth = { module = "com.google.firebase:firebase-auth" } firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" } firebase-config = { module = "com.google.firebase:firebase-config" } firebase-firestore = { module = "com.google.firebase:firebase-firestore" } +firebase-perf = { module = "com.google.firebase:firebase-perf" } firebase-storage = { module = "com.google.firebase:firebase-storage" } junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } @@ -65,4 +67,5 @@ google-services = { id = "com.google.gms.google-services", version.ref = "google google-hilt = { id = "com.google.dagger.hilt.android", version.ref = "googleHilt" } google-ksp = { id = "com.google.devtools.ksp", version.ref ="googleKotlinKsp" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +firebase-perf = { id = "com.google.firebase.firebase-perf", version.ref = "firebasePerf" } From 0ce4adba97344c1d7b4beb05acaaae589185c50a Mon Sep 17 00:00:00 2001 From: Marina Coelho Date: Tue, 31 Mar 2026 11:54:39 +0100 Subject: [PATCH 3/4] Add Remote Config keys --- .../data/datasource/AIRemoteDataSource.kt | 13 +++++------- .../main/res/xml/remote_config_defaults.xml | 20 +++++++++++++------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt b/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt index d424723..7e9d022 100644 --- a/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt +++ b/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt @@ -48,18 +48,13 @@ class AIRemoteDataSource @Inject constructor( suspend fun generateIngredientsHybrid(image: Bitmap): String { Firebase.performance.newTrace("hybrid-inference").trace { val hybridGenerativeModel = aiModel.generativeModel( - modelName = "gemini-3-flash-preview", + modelName = remoteConfig.getString(HYBRID_CLOUD_MODEL_KEY), onDeviceConfig = OnDeviceConfig(mode = InferenceMode.PREFER_IN_CLOUD) ) val prompt = content { image(image) - text( - "Please analyze this image and list all visible food ingredients. " + - "Output ONLY a comma-separated list of ingredients. Do not include " + - "any introductory text, headers, or concluding remarks. " + - "Provide the raw list only. Be specific with measurements where possible." - ) + text(remoteConfig.getString(HYBRID_INGREDIENTS_PROMPT_KEY)) } val response = hybridGenerativeModel.generateContent(prompt) @@ -71,7 +66,7 @@ class AIRemoteDataSource @Inject constructor( else -> "In cloud" } ) - + return response.text.orEmpty() } } @@ -163,6 +158,8 @@ class AIRemoteDataSource @Inject constructor( private const val GENERATE_RECIPE_PHOTO_GEMINI_KEY = "generate_recipe_photo_gemini" private const val GENERATE_RECIPE_PHOTO_IMAGEN_KEY = "generate_recipe_photo_imagen" private const val SCAN_MEAL_KEY = "scan_meal" + private const val HYBRID_CLOUD_MODEL_KEY = "hybrid_cloud_model" + private const val HYBRID_INGREDIENTS_PROMPT_KEY = "hybrid_ingredients_prompt" //Template input fields private const val IMAGE_DATA_FIELD = "imageData" diff --git a/app/src/main/res/xml/remote_config_defaults.xml b/app/src/main/res/xml/remote_config_defaults.xml index cf28b0b..0a61a5e 100644 --- a/app/src/main/res/xml/remote_config_defaults.xml +++ b/app/src/main/res/xml/remote_config_defaults.xml @@ -1,11 +1,19 @@ - generate_ingredients - generate-ingredients-template-v1-0-0 + hybrid_cloud_model + gemini-3.1-flash-lite-preview - generate_recipe - generate-recipe-template-v1-0-0 + hybrid_ingredients_prompt + Please analyze this image and list all visible food ingredients. Output ONLY a comma-separated list of ingredients. Do not include any introductory text, headers, or concluding remarks. Provide the raw list only. Be specific with measurements where possible. + + + scan_meal + scan-meal-template-v1-0-0 + + + generate_ingredients + generate-ingredients-template-v1-0-0 generate_recipe_photo_gemini @@ -16,7 +24,7 @@ generate-recipe-photo-imagen-template-v1-0-0 - scan_meal - scan-meal-template-v1-0-0 + generate_recipe + generate-recipe-template-v1-0-0 \ No newline at end of file From 5eb25f92b67b60d690a4b896faa2839d01cb2d61 Mon Sep 17 00:00:00 2001 From: Marina Coelho Date: Wed, 1 Apr 2026 11:19:59 +0100 Subject: [PATCH 4/4] Work on comments on PR --- .../data/datasource/AIRemoteDataSource.kt | 30 +++++++------------ .../data/repository/AIRepository.kt | 8 ++--- .../ui/generate/GenerateViewModel.kt | 6 +--- .../main/res/xml/remote_config_defaults.xml | 4 --- 4 files changed, 13 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt b/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt index 7e9d022..ac3e97a 100644 --- a/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt +++ b/app/src/main/java/com/google/firebase/example/friendlymeals/data/datasource/AIRemoteDataSource.kt @@ -31,27 +31,16 @@ class AIRemoteDataSource @Inject constructor( private val remoteConfig: FirebaseRemoteConfig ) { private val json = Json { ignoreUnknownKeys = true } - - suspend fun generateIngredients(imageData: String): String { - val response = generativeModel.generateContent( - templateId = remoteConfig.getString(GENERATE_INGREDIENTS_KEY), - inputs = mapOf( - MIME_TYPE_FIELD to MIME_TYPE_VALUE, - IMAGE_DATA_FIELD to imageData - ) - ) - - return response.text.orEmpty() - } + private val hybridGenerativeModel = aiModel.generativeModel( + modelName = remoteConfig.getString(HYBRID_CLOUD_MODEL_KEY), + onDeviceConfig = OnDeviceConfig(mode = InferenceMode.PREFER_IN_CLOUD) + ) @OptIn(PublicPreviewAPI::class) - suspend fun generateIngredientsHybrid(image: Bitmap): String { + suspend fun generateIngredients(image: Bitmap): String { + // Adding a Performance Monitoring trace is completely optional. Traces can help you + // measure how long it takes to generate ingredients on device and in cloud. Firebase.performance.newTrace("hybrid-inference").trace { - val hybridGenerativeModel = aiModel.generativeModel( - modelName = remoteConfig.getString(HYBRID_CLOUD_MODEL_KEY), - onDeviceConfig = OnDeviceConfig(mode = InferenceMode.PREFER_IN_CLOUD) - ) - val prompt = content { image(image) text(remoteConfig.getString(HYBRID_INGREDIENTS_PROMPT_KEY)) @@ -59,6 +48,8 @@ class AIRemoteDataSource @Inject constructor( val response = hybridGenerativeModel.generateContent(prompt) + // This is an optional function that adds an attribute to the Performance Monitoring + // trace. It helps you identify the source of the inference. putAttribute( "inferenceSource", when (response.inferenceSource) { @@ -138,7 +129,7 @@ class AIRemoteDataSource @Inject constructor( Log.i(TAG, "On-device model download complete") is DownloadStatus.DownloadFailed -> - Log.e(TAG, "Download failed ${status}") + Log.e(TAG, "Download failed $status") } } } @@ -153,7 +144,6 @@ class AIRemoteDataSource @Inject constructor( companion object { //Remote Config Keys - private const val GENERATE_INGREDIENTS_KEY = "generate_ingredients" private const val GENERATE_RECIPE_KEY = "generate_recipe" private const val GENERATE_RECIPE_PHOTO_GEMINI_KEY = "generate_recipe_photo_gemini" private const val GENERATE_RECIPE_PHOTO_IMAGEN_KEY = "generate_recipe_photo_imagen" diff --git a/app/src/main/java/com/google/firebase/example/friendlymeals/data/repository/AIRepository.kt b/app/src/main/java/com/google/firebase/example/friendlymeals/data/repository/AIRepository.kt index 6f642f1..c1a6253 100644 --- a/app/src/main/java/com/google/firebase/example/friendlymeals/data/repository/AIRepository.kt +++ b/app/src/main/java/com/google/firebase/example/friendlymeals/data/repository/AIRepository.kt @@ -9,12 +9,8 @@ import javax.inject.Inject class AIRepository @Inject constructor( private val aiRemoteDataSource: AIRemoteDataSource ) { - suspend fun generateIngredients(imageData: String): String { - return aiRemoteDataSource.generateIngredients(imageData) - } - - suspend fun generateIngredientsHybrid(image: Bitmap): String { - return aiRemoteDataSource.generateIngredientsHybrid(image) + suspend fun generateIngredients(image: Bitmap): String { + return aiRemoteDataSource.generateIngredients(image) } suspend fun generateRecipe(ingredients: String, notes: String): RecipeSchema? { diff --git a/app/src/main/java/com/google/firebase/example/friendlymeals/ui/generate/GenerateViewModel.kt b/app/src/main/java/com/google/firebase/example/friendlymeals/ui/generate/GenerateViewModel.kt index 714712f..178333b 100644 --- a/app/src/main/java/com/google/firebase/example/friendlymeals/ui/generate/GenerateViewModel.kt +++ b/app/src/main/java/com/google/firebase/example/friendlymeals/ui/generate/GenerateViewModel.kt @@ -8,7 +8,6 @@ import com.google.firebase.example.friendlymeals.data.repository.AuthRepository import com.google.firebase.example.friendlymeals.data.repository.DatabaseRepository import com.google.firebase.example.friendlymeals.data.repository.StorageRepository import com.google.firebase.example.friendlymeals.data.schema.RecipeSchema -import com.google.firebase.example.friendlymeals.ui.shared.toBase64 import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -69,10 +68,7 @@ class GenerateViewModel @Inject constructor( ingredientsLoading = true ) - //The following line of code uses hybrid inference to generate ingredients. - //To use the cloud-hosted model only, comment line 74 and uncomment line 75. - val ingredients = aiRepository.generateIngredientsHybrid(image) - //val ingredients = aiRepository.generateIngredients(image.toBase64()) + val ingredients = aiRepository.generateIngredients(image) _viewState.value = _viewState.value.copy( ingredientsLoading = false, diff --git a/app/src/main/res/xml/remote_config_defaults.xml b/app/src/main/res/xml/remote_config_defaults.xml index 0a61a5e..1175602 100644 --- a/app/src/main/res/xml/remote_config_defaults.xml +++ b/app/src/main/res/xml/remote_config_defaults.xml @@ -11,10 +11,6 @@ scan_meal scan-meal-template-v1-0-0 - - generate_ingredients - generate-ingredients-template-v1-0-0 - generate_recipe_photo_gemini generate-recipe-photo-gemini-template-v1-0-0