From d6a11613cd9b901bf3d0a604b8be5b1e277610a4 Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Mon, 23 Feb 2026 11:00:39 -0800 Subject: [PATCH 01/10] Add hybrid SDK sample --- app/build.gradle.kts | 1 + .../ai/catalog/domain/SampleCatalog.kt | 12 + app/src/main/res/values/strings.xml | 2 + gradle/libs.versions.toml | 8 +- samples/gemini-hybrid/.gitignore | 1 + samples/gemini-hybrid/README.md | 30 + samples/gemini-hybrid/build.gradle.kts | 77 +++ samples/gemini-hybrid/consumer-rules.pro | 1 + samples/gemini-hybrid/proguard-rules.pro | 21 + .../geminihybrid/GeminiHybridScreen.kt | 511 ++++++++++++++++++ .../geminihybrid/GeminiHybridViewModel.kt | 231 ++++++++ .../src/main/res/values/strings.xml | 34 ++ settings.gradle.kts | 1 + 13 files changed, 927 insertions(+), 3 deletions(-) create mode 100644 samples/gemini-hybrid/.gitignore create mode 100644 samples/gemini-hybrid/README.md create mode 100644 samples/gemini-hybrid/build.gradle.kts create mode 100644 samples/gemini-hybrid/consumer-rules.pro create mode 100644 samples/gemini-hybrid/proguard-rules.pro create mode 100644 samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt create mode 100644 samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt create mode 100644 samples/gemini-hybrid/src/main/res/values/strings.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cb0cef6c..8cdfcf69 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -93,6 +93,7 @@ dependencies { implementation(project(":samples:gemini-live-todo")) implementation(project(":samples:gemini-video-metadata-creation")) implementation(project(":samples:gemini-image-chat")) + implementation(project(":samples:gemini-hybrid")) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) diff --git a/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt b/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt index c4b10287..18089d35 100644 --- a/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt +++ b/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt @@ -31,11 +31,14 @@ import com.android.ai.samples.geminivideosummary.ui.VideoSummarizationScreen import com.android.ai.samples.genai_image_description.GenAIImageDescriptionScreen import com.android.ai.samples.genai_summarization.GenAISummarizationScreen import com.android.ai.samples.genai_writing_assistance.GenAIWritingAssistanceScreen +import com.android.ai.samples.geminihybrid.GeminiHybridScreen import com.android.ai.samples.imagen.ui.ImagenScreen import com.android.ai.samples.imagenediting.ui.ImagenEditingScreen import com.android.ai.samples.magicselfie.ui.MagicSelfieScreen import com.android.ai.theme.extendedColorScheme +import com.google.firebase.ai.type.PublicPreviewAPI +@OptIn(PublicPreviewAPI::class) @RequiresPermission(Manifest.permission.RECORD_AUDIO) val sampleCatalog = listOf( SampleCatalogItem( @@ -146,6 +149,15 @@ val sampleCatalog = listOf( needsFirebase = true, keyArt = R.drawable.img_keyart_todo, ), + SampleCatalogItem( + title = R.string.gemini_hybrid_sample_list_title, + description = R.string.gemini_hybrid_sample_list_description, + route = "GeminiHybridScreen", + sampleEntryScreen = { GeminiHybridScreen() }, + tags = listOf(SampleTags.GEMINI_NANO, SampleTags.GEMINI_FLASH, SampleTags.ML_KIT, SampleTags.FIREBASE), + needsFirebase = true, + keyArt = R.drawable.img_keyart_chatbot, + ), // To create a new sample entry, add a new SampleCatalogItem here. ) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5b0fad8b..37c8270b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,6 +27,8 @@ "Simple to-do app using the Gemini Live API to interact with the items in the list" Chat with Nano Banana Pro Conversational Image generation with Gemini 3 Pro Image + Gemini Hybrid + Inference with Firebase Hybrid SDK using either Gemini Nano on-device or Gemini Flash in the Cloud. Firebase Required This feature requires Firebase to be initialized. Close diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 19f57495..b228c7a0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,8 @@ [versions] agp = "8.8.2" coilCompose = "3.1.0" -firebaseBom = "34.5.0" +firebaseAiOndevice = "16.0.0-beta01" +firebaseBom = "34.10.0" lifecycleRuntimeCompose = "2.9.1" mlkitGenAi = "1.0.0-beta1" kotlin = "2.1.0" @@ -40,8 +41,9 @@ richtext = "1.0.0-alpha02" androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycleRuntimeCompose" } coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coilCompose" } +firebase-ai-ondevice = { module = "com.google.firebase:firebase-ai-ondevice", version.ref = "firebaseAiOndevice" } firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" } -firebase-ai = { group = "com.google.firebase", name = "firebase-ai" } +firebase-ai = { module = "com.google.firebase:firebase-ai"} firebase-common-ktx = { group = "com.google.firebase", name = "firebase-common-ktx", version.ref = "firebaseCommonKtx" } genai-image-description = { module = "com.google.mlkit:genai-image-description", version.ref = "mlkitGenAi" } genai-proofreading = { module = "com.google.mlkit:genai-proofreading", version.ref = "mlkitGenAi" } @@ -94,4 +96,4 @@ google-gms-google-services = { id = "com.google.gms.google-services", version.re hilt-plugin = { id = "com.google.dagger.hilt.android", version.ref = "hilt"} ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } -spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } \ No newline at end of file +spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } diff --git a/samples/gemini-hybrid/.gitignore b/samples/gemini-hybrid/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/samples/gemini-hybrid/.gitignore @@ -0,0 +1 @@ +/build diff --git a/samples/gemini-hybrid/README.md b/samples/gemini-hybrid/README.md new file mode 100644 index 00000000..4e95b184 --- /dev/null +++ b/samples/gemini-hybrid/README.md @@ -0,0 +1,30 @@ +# Gemini Hybrid Sample + +This sample is part of the [AI Sample Catalog](../../). To build and run this sample, you should clone the entire repository. + +## Description + +This sample demonstrates a hybrid approach to generative AI, utilizing both on-device (Gemini Nano via ML Kit) and cloud-based (Gemini via Firebase AI SDK) models. It showcases how to fallback to the cloud when on-device capabilities are unavailable or when more complex reasoning is required. + +## How it works + +The application first attempts to perform a task (e.g., summarization) using the on-device Gemini Nano model through the ML Kit GenAI API. If the model is not supported on the device or fails to download, it seamlessly falls back to the Gemini Flash model in the cloud using the Firebase AI SDK. + +### Key Snippets + +#### On-Device Inference (ML Kit) +```kotlin +val summarizer = Summarization.getClient(options) +val featureStatus = summarizer.checkFeatureStatus().await() +if (featureStatus == FeatureStatus.READY) { + summarizer.runInference(request) { ... }.await() +} +``` + +#### Cloud Inference (Firebase AI) +```kotlin +val generativeModel = Firebase.ai.generativeModel("gemini-1.5-flash") +val response = generativeModel.generateContent(prompt) +``` + +Read more about [Gemini on Android](https://developer.android.com/ai/gemini) in the official documentation. diff --git a/samples/gemini-hybrid/build.gradle.kts b/samples/gemini-hybrid/build.gradle.kts new file mode 100644 index 00000000..e1ee7f76 --- /dev/null +++ b/samples/gemini-hybrid/build.gradle.kts @@ -0,0 +1,77 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.jetbrains.kotlin.android) + alias(libs.plugins.ksp) + alias(libs.plugins.compose.compiler) +} + +android { + namespace = "com.android.ai.samples.geminihybrid" + compileSdk = 35 + + buildFeatures { + compose = true + } + + defaultConfig { + minSdk = 26 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro", + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.androidx.material3) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.material.icons.extended) + implementation(libs.hilt.android) + implementation(libs.hilt.navigation.compose) + implementation(libs.androidx.runtime.livedata) + implementation(libs.genai.summarization) + implementation(libs.kotlinx.coroutines.guava) + implementation(libs.androidx.lifecycle.runtime.compose) + implementation(platform(libs.firebase.bom)) + implementation(libs.firebase.ai) + implementation(libs.firebase.ai.ondevice) + + implementation(project(":ui-component")) + debugImplementation(libs.ui.tooling) + ksp(libs.hilt.compiler) +} diff --git a/samples/gemini-hybrid/consumer-rules.pro b/samples/gemini-hybrid/consumer-rules.pro new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/samples/gemini-hybrid/consumer-rules.pro @@ -0,0 +1 @@ + diff --git a/samples/gemini-hybrid/proguard-rules.pro b/samples/gemini-hybrid/proguard-rules.pro new file mode 100644 index 00000000..f1b42451 --- /dev/null +++ b/samples/gemini-hybrid/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt new file mode 100644 index 00000000..e70fef28 --- /dev/null +++ b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt @@ -0,0 +1,511 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:OptIn(PublicPreviewAPI::class, ExperimentalMaterial3ExpressiveApi::class) + +package com.android.ai.samples.geminihybrid + +import androidx.activity.compose.LocalOnBackPressedDispatcherOwner +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedToggleButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SplitButtonDefaults +import androidx.compose.material3.SplitButtonLayout +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.material3.ToggleButtonDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.core.content.ContextCompat +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.android.ai.theme.AISampleCatalogTheme +import com.android.ai.theme.surfaceContainerHighestLight +import com.android.ai.uicomponent.GenerateButton +import com.android.ai.uicomponent.SampleDetailTopAppBar +import com.android.ai.uicomponent.UndoButton +import com.google.firebase.ai.InferenceMode +import com.google.firebase.ai.type.PublicPreviewAPI + + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) +@Composable +fun GeminiHybridScreen(viewModel: GeminiHybridViewModel = hiltViewModel()) { + + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val selectedMode by viewModel.inferenceMode.collectAsStateWithLifecycle() + val selectedTags by viewModel.selectedTags.collectAsStateWithLifecycle() + val reviewText by viewModel.reviewText.collectAsStateWithLifecycle() + val reviewInferenceStatus by viewModel.reviewInferenceStatus.collectAsStateWithLifecycle() + val selectedLanguage by viewModel.selectedLanguage.collectAsStateWithLifecycle() + + val context = LocalContext.current + val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher + + AISampleCatalogTheme { + Scaffold( + modifier = Modifier.fillMaxSize(), + topBar = { + SampleDetailTopAppBar( + sampleName = stringResource(R.string.gemini_hybrid_title), + sampleDescription = stringResource(R.string.gemini_hybrid_description), + sourceCodeUrl = "https://github.com/android/ai-samples/tree/main/samples/gemini-hybrid", + onBackClick = { backDispatcher?.onBackPressed() }, + ) + }, + ) { innerPadding -> + Box( + Modifier + .padding(innerPadding) + .fillMaxSize() + .clip(RoundedCornerShape(40.dp)) + .background(color = surfaceContainerHighestLight) + .padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 32.dp), + contentAlignment = Alignment.Center, + ) { + val scrollState = rememberScrollState() + + Column( + Modifier + .padding(top = 16.dp) + .imePadding() + .widthIn(max = 646.dp) + .fillMaxHeight() + .verticalScroll(scrollState), + ) { + Text( + text = stringResource(R.string.gemini_hotel_review), + style = MaterialTheme.typography.titleLarge, + modifier = Modifier.padding(8.dp), + ) + + when (val state = uiState) { + is GeminiHybridUiState.Initial -> { + InitialReviewUi( + tags = viewModel.tags, + selectedTags = selectedTags, + onTagToggle = viewModel::toggleTag, + selectedMode = selectedMode, + onModeSelected = viewModel::setInferenceMode, + onGenerate = { + val tagStrings = + selectedTags.map { ContextCompat.getString(context, it) } + viewModel.generateReview(tagStrings) + }, + ) + } + + is GeminiHybridUiState.CheckingOnDeviceStatus -> { + StatusText(stringResource(R.string.gemini_hybrid_status_checking)) + } + + is GeminiHybridUiState.Generating -> { + if (!state.isTranslation) { + GeneratingUi(state) + } else { + SuccessReviewUi( + reviewText = reviewText, + reviewInferenceStatus = reviewInferenceStatus, + onReviewTextChanged = viewModel::updateReviewText, + languageKeys = viewModel.languageMap.keys.toList(), + languageMap = viewModel.languageMap, + selectedLanguage = selectedLanguage, + onLanguageSelected = viewModel::setSelectedLanguage, + onTranslate = { viewModel.translate(reviewText, selectedLanguage) }, + onReset = viewModel::reset, + translationState = state, + ) + } + } + + is GeminiHybridUiState.Success -> { + SuccessReviewUi( + reviewText = reviewText, + reviewInferenceStatus = reviewInferenceStatus, + onReviewTextChanged = viewModel::updateReviewText, + languageKeys = viewModel.languageMap.keys.toList(), + languageMap = viewModel.languageMap, + selectedLanguage = selectedLanguage, + onLanguageSelected = viewModel::setSelectedLanguage, + onTranslate = { viewModel.translate(reviewText, selectedLanguage) }, + onReset = viewModel::reset, + translationState = state, + ) + } + + is GeminiHybridUiState.Error -> { + ErrorUi(state.message, onReset = viewModel::reset) + } + } + } + } + } + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +fun InitialReviewUi( + tags: List, + selectedTags: List, + onTagToggle: (Int) -> Unit, + selectedMode: InferenceMode, + onModeSelected: (InferenceMode) -> Unit, + onGenerate: () -> Unit, +) { + Text( + stringResource(R.string.select_topics_for_your_review), + modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp), + style = MaterialTheme.typography.titleMedium, + ) + FlowRow( + modifier = Modifier + .padding(8.dp), + ) { + tags.forEach { tagResId -> + val isSelected = selectedTags.contains(tagResId) + OutlinedToggleButton( + checked = isSelected, + onCheckedChange = { onTagToggle(tagResId) }, + colors = ToggleButtonDefaults.outlinedToggleButtonColors( + contentColor = MaterialTheme.colorScheme.tertiary, + ), + modifier = Modifier.padding(horizontal = 6.dp), + ) { + Text( + stringResource(tagResId), + style = MaterialTheme.typography.labelLarge, + fontWeight = FontWeight.Bold, + ) + } + } + } + Spacer(Modifier.height(50.dp)) + InferenceModeDropdown( + selectedMode = selectedMode, + onModeSelected = onModeSelected, + ) + + GenerateButton( + text = stringResource(R.string.gemini_hybrid_generate_btn), + icon = painterResource(id = com.android.ai.uicomponent.R.drawable.ic_ai_text), + modifier = Modifier + .fillMaxWidth() + .padding(top = 12.dp, start = 8.dp, end = 8.dp), + enabled = selectedTags.isNotEmpty(), + onClick = onGenerate, + ) +} + +@Composable +fun GeneratingUi(state: GeminiHybridUiState.Generating) { + val status = if (state.isCloud) { + stringResource(R.string.gemini_hybrid_status_generating_cloud) + } else { + stringResource(R.string.gemini_hybrid_status_generating_on_device) + } + Column(modifier = Modifier.fillMaxWidth()) { + StatusText(status) + if (state.partialOutput.isNotEmpty()) { + OutputText(state.partialOutput) + } + } +} + +@Composable +fun SuccessReviewUi( + reviewText: String, + reviewInferenceStatus: Int?, + onReviewTextChanged: (String) -> Unit, + languageKeys: List, + languageMap: Map, + selectedLanguage: String, + onLanguageSelected: (String) -> Unit, + onTranslate: () -> Unit, + onReset: () -> Unit, + translationState: GeminiHybridUiState, +) { + Column(modifier = Modifier.fillMaxWidth()) { + reviewInferenceStatus?.let { + StatusText(stringResource(it)) + } + TextField( + value = reviewText, + onValueChange = onReviewTextChanged, + colors = TextFieldDefaults.colors( + focusedContainerColor = Color.Transparent, + unfocusedContainerColor = Color.Transparent, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent, + disabledTextColor = MaterialTheme.colorScheme.onSurface, + ), + modifier = Modifier + .padding(4.dp) + .fillMaxWidth() + .heightIn(max = 200.dp), + ) + + Spacer(modifier = Modifier.height(20.dp)) + + Box(modifier = Modifier.padding(start = 8.dp, top = 12.dp)) { + LanguageDropdown( + languageKeys = languageKeys, + languageMap = languageMap, + selectedLanguage = selectedLanguage, + onLanguageSelected = onLanguageSelected, + ) + } + + GenerateButton( + text = stringResource(R.string.gemini_hybrid_translate_btn), + icon = painterResource(id = com.android.ai.uicomponent.R.drawable.ic_ai_text), + modifier = Modifier + .fillMaxWidth() + .padding(top = 12.dp, start = 8.dp, end = 8.dp), + enabled = reviewText.isNotBlank() && translationState !is GeminiHybridUiState.Generating, + onClick = onTranslate, + ) + + Spacer(modifier = Modifier.height(20.dp)) + when (translationState) { + is GeminiHybridUiState.Generating -> { + if (translationState.isTranslation) { + val status = if (translationState.isCloud) { + stringResource(R.string.gemini_hybrid_status_generating_cloud) + } else { + stringResource(R.string.gemini_hybrid_status_generating_on_device) + } + StatusText(status) + if (translationState.partialOutput.isNotEmpty()) { + OutputText(translationState.partialOutput) + } + } + } + + is GeminiHybridUiState.Success -> { + if (translationState.isTranslation) { + val inferenceStatus = if (translationState.isCloud) { + R.string.gemini_hybrid_generated_cloud + } else { + R.string.gemini_hybrid_generated_on_device + } + + StatusText(stringResource(inferenceStatus)) + OutputText(translationState.output) + } + } + + else -> {} + } + + UndoButton( + modifier = Modifier.padding(start = 8.dp, top = 8.dp), + onClick = onReset, + ) + } +} + +@Composable +fun ErrorUi(message: String, onReset: () -> Unit) { + Column { + StatusText(message) + UndoButton( + modifier = Modifier.padding(start = 8.dp, top = 8.dp), + onClick = onReset, + ) + } +} + +@Composable +fun LanguageDropdown( + languageKeys: List, + languageMap: Map, + selectedLanguage: String, + onLanguageSelected: (String) -> Unit, +) { + var expanded by remember { mutableStateOf(false) } + + Box { + SplitButtonLayout( + leadingButton = { + SplitButtonDefaults.LeadingButton( + onClick = { expanded = true }, + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.tertiaryContainer, + contentColor = MaterialTheme.colorScheme.onTertiaryContainer, + ), + ) { + Text(stringResource(languageMap[selectedLanguage] ?: R.string.gemini_hybrid_lang_korean).uppercase()) + } + }, + trailingButton = { + SplitButtonDefaults.TrailingButton( + onClick = { expanded = true }, + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.tertiaryContainer, + contentColor = MaterialTheme.colorScheme.onTertiaryContainer, + ), + ) { + Icon( + imageVector = Icons.Default.ArrowDropDown, + contentDescription = null, + ) + } + }, + ) + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + ) { + languageKeys.forEach { key -> + DropdownMenuItem( + text = { Text(stringResource(languageMap[key]!!)) }, + onClick = { + onLanguageSelected(key) + expanded = false + }, + ) + } + } + } +} + +@PublicPreviewAPI +@Composable +fun InferenceModeDropdown( + selectedMode: InferenceMode, + onModeSelected: (InferenceMode) -> Unit, +) { + var expanded by remember { mutableStateOf(false) } + val modes = listOf( + InferenceMode.ONLY_ON_DEVICE to stringResource(R.string.gemini_hybrid_mode_only_on_device), + InferenceMode.ONLY_IN_CLOUD to stringResource(R.string.gemini_hybrid_mode_only_cloud), + InferenceMode.PREFER_ON_DEVICE to stringResource(R.string.gemini_hybrid_mode_prefer_on_device), + InferenceMode.PREFER_IN_CLOUD to stringResource(R.string.gemini_hybrid_mode_prefer_cloud), + ) + val selectedText = modes.find { it.first == selectedMode }?.second ?: "" + + Box(modifier = Modifier.padding(start = 8.dp, top = 12.dp)) { + SplitButtonLayout( + leadingButton = { + SplitButtonDefaults.LeadingButton( + onClick = { expanded = true }, + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.tertiaryContainer, + contentColor = MaterialTheme.colorScheme.onTertiaryContainer, + ), + ) { + Text(selectedText) + } + }, + trailingButton = { + SplitButtonDefaults.TrailingButton( + onClick = { expanded = true }, + colors = ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.tertiaryContainer, + contentColor = MaterialTheme.colorScheme.onTertiaryContainer, + ), + ) { + Icon( + imageVector = Icons.Default.ArrowDropDown, + contentDescription = null, + ) + } + }, + ) + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + ) { + modes.forEach { (mode, label) -> + DropdownMenuItem( + text = { Text(label) }, + onClick = { + onModeSelected(mode) + expanded = false + }, + ) + } + } + } +} + +@Composable +fun StatusText(text: String) { + Text( + text = text, + style = MaterialTheme.typography.bodySmall, + modifier = Modifier.padding(8.dp), + ) +} + +@Composable +fun OutputText(text: String, modifier: Modifier = Modifier) { + TextField( + value = text, + onValueChange = {}, + readOnly = true, + colors = TextFieldDefaults.colors( + focusedContainerColor = Color.Transparent, + unfocusedContainerColor = Color.Transparent, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + disabledIndicatorColor = Color.Transparent, + disabledTextColor = MaterialTheme.colorScheme.onSurface, + ), + modifier = modifier.fillMaxWidth(), + textStyle = MaterialTheme.typography.bodyLarge.copy(fontSize = 16.sp), + ) +} diff --git a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt new file mode 100644 index 00000000..aae00633 --- /dev/null +++ b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt @@ -0,0 +1,231 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ai.samples.geminihybrid + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.google.firebase.Firebase +import com.google.firebase.ai.InferenceMode +import com.google.firebase.ai.InferenceSource +import com.google.firebase.ai.OnDeviceConfig +import com.google.firebase.ai.ai +import com.google.firebase.ai.type.GenerativeBackend +import com.google.firebase.ai.type.PublicPreviewAPI +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch + +sealed interface GeminiHybridUiState { + data object Initial : GeminiHybridUiState + data object CheckingOnDeviceStatus : GeminiHybridUiState + data class Generating( + val isCloud: Boolean, + val partialOutput: String = "", + val isTranslation: Boolean = false + ) : GeminiHybridUiState + + data class Success( + val output: String, + val isCloud: Boolean, + val isTranslation: Boolean = false + ) : GeminiHybridUiState + + data class Error(val message: String) : GeminiHybridUiState +} + +@PublicPreviewAPI +@HiltViewModel +class GeminiHybridViewModel @Inject constructor() : ViewModel() { + private val _uiState = MutableStateFlow(GeminiHybridUiState.Initial) + val uiState: StateFlow = _uiState.asStateFlow() + + private val _inferenceMode = MutableStateFlow(InferenceMode.ONLY_ON_DEVICE) + val inferenceMode: StateFlow = _inferenceMode.asStateFlow() + + private val _selectedTags = MutableStateFlow>(emptyList()) + val selectedTags: StateFlow> = _selectedTags.asStateFlow() + + private val _reviewText = MutableStateFlow("") + val reviewText: StateFlow = _reviewText.asStateFlow() + + private val _reviewInferenceStatus = MutableStateFlow(null) + val reviewInferenceStatus: StateFlow = _reviewInferenceStatus.asStateFlow() + + private val _selectedLanguage = MutableStateFlow("Korean") + val selectedLanguage: StateFlow = _selectedLanguage.asStateFlow() + + val tags = listOf( + R.string.location, + R.string.view, + R.string.service, + R.string.comfort, + R.string.food, + R.string.spacious, + R.string.natural_light, + ) + + val languageMap = mapOf( + "Korean" to R.string.gemini_hybrid_lang_korean, + "Spanish" to R.string.gemini_hybrid_lang_spanish, + "French" to R.string.gemini_hybrid_lang_french, + "German" to R.string.gemini_hybrid_lang_german + ) + + fun setInferenceMode(mode: InferenceMode) { + _inferenceMode.value = mode + } + + fun toggleTag(tagResId: Int) { + _selectedTags.update { current -> + if (current.contains(tagResId)) current - tagResId else current + tagResId + } + } + + fun updateReviewText(text: String) { + _reviewText.value = text + } + + fun setSelectedLanguage(language: String) { + _selectedLanguage.value = language + } + + fun generateReview(tagStrings: List) { + if (tagStrings.isEmpty()) { + _uiState.value = GeminiHybridUiState.Error("Please select at least one tag") + return + } + + viewModelScope.launch { + _uiState.value = GeminiHybridUiState.Generating( + isCloud = _inferenceMode.value == InferenceMode.ONLY_IN_CLOUD, + isTranslation = false + ) + try { + val prompt = + "Write a simple, short and generic hotel review positively covering the following themes: ${ + tagStrings.joinToString(", ") + }. Generate a generic review strictly from themes, don't hallucinate a hotel name or a location. Return only the review text." + + val model = Firebase.ai(backend = GenerativeBackend.googleAI()) + .generativeModel( + "gemini-2.5-flash-lite", + onDeviceConfig = OnDeviceConfig(mode = _inferenceMode.value) + ) + model.generateContentStream(prompt).collect { chunk -> + val isCloud = chunk.inferenceSource == InferenceSource.IN_CLOUD + _uiState.update { state -> + if (state is GeminiHybridUiState.Generating) { + state.copy( + isCloud = isCloud, + partialOutput = state.partialOutput + (chunk.text ?: "") + ) + } else { + GeminiHybridUiState.Generating( + isCloud = isCloud, + partialOutput = chunk.text ?: "", + isTranslation = false + ) + } + } + } + + val finalState = uiState.value + if (finalState is GeminiHybridUiState.Generating) { + val output = finalState.partialOutput.trimEnd() + _reviewText.value = output + _reviewInferenceStatus.value = if (finalState.isCloud) { + R.string.gemini_hybrid_generated_cloud + } else { + R.string.gemini_hybrid_generated_on_device + } + _uiState.value = + GeminiHybridUiState.Success(output, finalState.isCloud, isTranslation = false) + } + } catch (e: Exception) { + Log.e("GeminiHybrid", "Inference failed", e) + _uiState.value = + GeminiHybridUiState.Error(e.localizedMessage ?: "Unknown error occurred") + } + } + } + + fun translate(text: String, language: String) { + if (text.isBlank()) { + _uiState.value = GeminiHybridUiState.Error("Text to translate cannot be empty") + return + } + + viewModelScope.launch { + _uiState.value = GeminiHybridUiState.Generating( + isCloud = _inferenceMode.value == InferenceMode.ONLY_IN_CLOUD, + isTranslation = true + ) + try { + val prompt = + "Translate the following text to $language. Return ONLY the translated text, no explanations:\n\n$text" + + val model = Firebase.ai(backend = GenerativeBackend.googleAI()) + .generativeModel( + "gemini-2.5-flash-lite", + onDeviceConfig = OnDeviceConfig(mode = _inferenceMode.value) + ) + + model.generateContentStream(prompt).collect { chunk -> + val isCloud = chunk.inferenceSource == InferenceSource.IN_CLOUD + _uiState.update { state -> + if (state is GeminiHybridUiState.Generating) { + state.copy( + isCloud = isCloud, + partialOutput = state.partialOutput + (chunk.text ?: "") + ) + } else { + GeminiHybridUiState.Generating( + isCloud = isCloud, + partialOutput = chunk.text ?: "", + isTranslation = true + ) + } + } + } + + val finalState = uiState.value + if (finalState is GeminiHybridUiState.Generating) { + _uiState.value = GeminiHybridUiState.Success( + finalState.partialOutput, + finalState.isCloud, + isTranslation = true + ) + } + } catch (e: Exception) { + Log.e("GeminiHybrid", "Inference failed", e) + _uiState.value = + GeminiHybridUiState.Error(e.localizedMessage ?: "Unknown error occurred") + } + } + } + + fun reset() { + _uiState.value = GeminiHybridUiState.Initial + _selectedTags.value = emptyList() + _reviewText.value = "" + _reviewInferenceStatus.value = null + } +} diff --git a/samples/gemini-hybrid/src/main/res/values/strings.xml b/samples/gemini-hybrid/src/main/res/values/strings.xml new file mode 100644 index 00000000..16e6413e --- /dev/null +++ b/samples/gemini-hybrid/src/main/res/values/strings.xml @@ -0,0 +1,34 @@ + + + Hybrid Inference + Inference with Firebase Hybrid SDK using either Gemini Nano on-device or Gemini Flash in the Cloud. + Hotel review generation + Generate Review + Translate + Korean + Spanish + French + German + Checking on-device status… + Downloading on-device model: %1$d / %2$d + Generating on-device… + Generating in cloud… + Please enter some text. + Something went wrong. + Cloud + On-device + Generated in the cloud + Generated on device + PREFER ON-DEVICE + PREFER CLOUD + ONLY ON-DEVICE + ONLY CLOUD + LOCATION + VIEW + SERVICE + COMFORT + FOOD + SPACIOUS + NATURAL LIGHT + Select topics for your review: + diff --git a/settings.gradle.kts b/settings.gradle.kts index 977e9376..74adde7f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -50,4 +50,5 @@ include(":samples:gemini-video-summarization") include(":samples:gemini-live-todo") include(":samples:gemini-video-metadata-creation") include(":samples:gemini-image-chat") +include(":samples:gemini-hybrid") include(":ui-component") From 608ae56ea336d1bfa2e2bb82434f80c2f44d4469 Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Mon, 2 Mar 2026 09:40:28 -0800 Subject: [PATCH 02/10] Update ReadMe --- samples/gemini-hybrid/README.md | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/samples/gemini-hybrid/README.md b/samples/gemini-hybrid/README.md index 4e95b184..5572e8f9 100644 --- a/samples/gemini-hybrid/README.md +++ b/samples/gemini-hybrid/README.md @@ -4,27 +4,18 @@ This sample is part of the [AI Sample Catalog](../../). To build and run this sa ## Description -This sample demonstrates a hybrid approach to generative AI, utilizing both on-device (Gemini Nano via ML Kit) and cloud-based (Gemini via Firebase AI SDK) models. It showcases how to fallback to the cloud when on-device capabilities are unavailable or when more complex reasoning is required. - -## How it works - -The application first attempts to perform a task (e.g., summarization) using the on-device Gemini Nano model through the ML Kit GenAI API. If the model is not supported on the device or fails to download, it seamlessly falls back to the Gemini Flash model in the cloud using the Firebase AI SDK. +This sample demonstrates how to use the Firebase Hybrid SDK, utilizing both on-device (Gemini Nano via [ML Kit Prompt API](https://developers.google.com/ml-kit/genai/prompt/android)) and cloud-based models via the [Firebase AI Logic SDK](https://firebase.google.com/docs/ai-logic). ### Key Snippets -#### On-Device Inference (ML Kit) ```kotlin -val summarizer = Summarization.getClient(options) -val featureStatus = summarizer.checkFeatureStatus().await() -if (featureStatus == FeatureStatus.READY) { - summarizer.runInference(request) { ... }.await() -} -``` +val model = Firebase.ai(backend = GenerativeBackend.googleAI()) + .generativeModel( + "gemini-2.5-flash-lite", + onDeviceConfig = OnDeviceConfig(mode = InferenceMode.PREFER_ON_DEVICE) + ) -#### Cloud Inference (Firebase AI) -```kotlin -val generativeModel = Firebase.ai.generativeModel("gemini-1.5-flash") -val response = generativeModel.generateContent(prompt) +val response = model.generateContent(prompt) ``` -Read more about [Gemini on Android](https://developer.android.com/ai/gemini) in the official documentation. +Read more about the [Firebase Hybrid SDK](https://firebase.google.com/docs/ai-logic/hybrid/android/get-started?api=dev) in the Firebase documentation. From e1ad5b9a69f881d2f283c56dc451c04d5a90fb4a Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Mon, 2 Mar 2026 09:46:16 -0800 Subject: [PATCH 03/10] Update README.md --- README.md | 4 +++- samples/gemini-hybrid/gemini_hybrid.png | Bin 0 -> 157515 bytes 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 samples/gemini-hybrid/gemini_hybrid.png diff --git a/README.md b/README.md index 4997ce29..8a618df3 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,9 @@ Here is the list of samples you can find in the `/samples` folder: | | | | Gemini Nano Image description | ✨📱🔍 **On-device Image Description**:
A sample letting you generate image descriptions using Gemini Nano via the [GenAI Image Description API](https://developers.google.com/ml-kit/genai/image-description/android).



**[> Browse code](samples/genai-image-description)**

| | | | -| Gemini Nano Rewrite | ✨📱🖋️ **On-device Writing Assistance**:
A sample letting you proofread and rewrite text using Gemini Nano via the [GenAI Rewriting API](https://developers.google.com/ml-kit/genai/rewriting/android).



**[> Browse code](samples/genai-writing-assistance)**

| +| Gemini Nano Rewrite | ✨📱🖋️ **On-device Writing Assistance**:
A sample letting you proofread and rewrite text using Gemini Nano via the [GenAI Rewriting API](https://developers.google.com/ml-kit/genai/rewriting/android).



**[> Browse code](samples/genai-writing-assistance)**

| +| | | +| Gemini Hybrid sample | ✨📱☁️ **Hybrid Inference**:
A sample demonstrating a hybrid approach to generative AI, utilizing both on-device (Gemini Nano via ML Kit) and cloud-based (Gemini via Firebase AI SDK) models. It showcases how to fallback to the cloud when on-device capabilities are unavailable.



**[> Browse code](samples/gemini-hybrid)**

| | | | | Imagen sample | 🖼️ **Image Generation with Imagen**:
A sample using [Imagen to generate images](https://developer.android.com/ai/imagen#generate-image) of landscapes, objects and people in various artistic style.



**[> Browse code](samples/imagen)**

| | | | diff --git a/samples/gemini-hybrid/gemini_hybrid.png b/samples/gemini-hybrid/gemini_hybrid.png new file mode 100644 index 0000000000000000000000000000000000000000..1324a668e703775e38c1b23b99c29a35df871735 GIT binary patch literal 157515 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

HObiT&EAMJ|BZh-zL@xXoBG8 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 pTD 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 Date: Mon, 2 Mar 2026 09:52:39 -0800 Subject: [PATCH 04/10] Address Gemini code assist feedback --- samples/gemini-hybrid/build.gradle.kts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/samples/gemini-hybrid/build.gradle.kts b/samples/gemini-hybrid/build.gradle.kts index e1ee7f76..fa698ae1 100644 --- a/samples/gemini-hybrid/build.gradle.kts +++ b/samples/gemini-hybrid/build.gradle.kts @@ -23,7 +23,7 @@ plugins { android { namespace = "com.android.ai.samples.geminihybrid" - compileSdk = 35 + compileSdk = 36 buildFeatures { compose = true @@ -64,8 +64,6 @@ dependencies { implementation(libs.hilt.android) implementation(libs.hilt.navigation.compose) implementation(libs.androidx.runtime.livedata) - implementation(libs.genai.summarization) - implementation(libs.kotlinx.coroutines.guava) implementation(libs.androidx.lifecycle.runtime.compose) implementation(platform(libs.firebase.bom)) implementation(libs.firebase.ai) From e63778f55f78a9d1492b68e3e12e91b7044220f7 Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Tue, 3 Mar 2026 10:13:07 -0800 Subject: [PATCH 05/10] Address comments --- .../geminihybrid/GeminiHybridScreen.kt | 98 +++++------ .../geminihybrid/GeminiHybridViewModel.kt | 161 ++++++++++-------- 2 files changed, 134 insertions(+), 125 deletions(-) diff --git a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt index e70fef28..17b669ff 100644 --- a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt +++ b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt @@ -44,6 +44,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedToggleButton import androidx.compose.material3.Scaffold import androidx.compose.material3.SplitButtonDefaults @@ -84,11 +85,6 @@ import com.google.firebase.ai.type.PublicPreviewAPI fun GeminiHybridScreen(viewModel: GeminiHybridViewModel = hiltViewModel()) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val selectedMode by viewModel.inferenceMode.collectAsStateWithLifecycle() - val selectedTags by viewModel.selectedTags.collectAsStateWithLifecycle() - val reviewText by viewModel.reviewText.collectAsStateWithLifecycle() - val reviewInferenceStatus by viewModel.reviewInferenceStatus.collectAsStateWithLifecycle() - val selectedLanguage by viewModel.selectedLanguage.collectAsStateWithLifecycle() val context = LocalContext.current val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher @@ -130,62 +126,62 @@ fun GeminiHybridScreen(viewModel: GeminiHybridViewModel = hiltViewModel()) { modifier = Modifier.padding(8.dp), ) - when (val state = uiState) { - is GeminiHybridUiState.Initial -> { + when (val status = uiState.status) { + is GeminiStatus.Initial -> { InitialReviewUi( tags = viewModel.tags, - selectedTags = selectedTags, + selectedTags = uiState.selectedTags, onTagToggle = viewModel::toggleTag, - selectedMode = selectedMode, + selectedMode = uiState.selectedMode, onModeSelected = viewModel::setInferenceMode, onGenerate = { val tagStrings = - selectedTags.map { ContextCompat.getString(context, it) } + uiState.selectedTags.map { ContextCompat.getString(context, it) } viewModel.generateReview(tagStrings) }, ) } - is GeminiHybridUiState.CheckingOnDeviceStatus -> { + is GeminiStatus.CheckingOnDeviceStatus -> { StatusText(stringResource(R.string.gemini_hybrid_status_checking)) } - is GeminiHybridUiState.Generating -> { - if (!state.isTranslation) { - GeneratingUi(state) + is GeminiStatus.Generating -> { + if (!status.isTranslation) { + GeneratingUi(status) } else { SuccessReviewUi( - reviewText = reviewText, - reviewInferenceStatus = reviewInferenceStatus, + reviewText = uiState.reviewText, + reviewInferenceStatus = uiState.reviewInferenceStatus, onReviewTextChanged = viewModel::updateReviewText, languageKeys = viewModel.languageMap.keys.toList(), languageMap = viewModel.languageMap, - selectedLanguage = selectedLanguage, + selectedLanguage = uiState.selectedLanguage, onLanguageSelected = viewModel::setSelectedLanguage, - onTranslate = { viewModel.translate(reviewText, selectedLanguage) }, + onTranslate = { viewModel.translate(uiState.reviewText, uiState.selectedLanguage) }, onReset = viewModel::reset, - translationState = state, + generationStatus = status, ) } } - is GeminiHybridUiState.Success -> { + is GeminiStatus.Success -> { SuccessReviewUi( - reviewText = reviewText, - reviewInferenceStatus = reviewInferenceStatus, + reviewText = uiState.reviewText, + reviewInferenceStatus = uiState.reviewInferenceStatus, onReviewTextChanged = viewModel::updateReviewText, languageKeys = viewModel.languageMap.keys.toList(), languageMap = viewModel.languageMap, - selectedLanguage = selectedLanguage, + selectedLanguage = uiState.selectedLanguage, onLanguageSelected = viewModel::setSelectedLanguage, - onTranslate = { viewModel.translate(reviewText, selectedLanguage) }, + onTranslate = { viewModel.translate(uiState.reviewText, uiState.selectedLanguage) }, onReset = viewModel::reset, - translationState = state, + generationStatus = status, ) } - is GeminiHybridUiState.Error -> { - ErrorUi(state.message, onReset = viewModel::reset) + is GeminiStatus.Error -> { + ErrorUi(status.message, onReset = viewModel::reset) } } } @@ -205,7 +201,7 @@ fun InitialReviewUi( onGenerate: () -> Unit, ) { Text( - stringResource(R.string.select_topics_for_your_review), + "Select topics for your review:", modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp), style = MaterialTheme.typography.titleMedium, ) @@ -249,16 +245,16 @@ fun InitialReviewUi( } @Composable -fun GeneratingUi(state: GeminiHybridUiState.Generating) { - val status = if (state.isCloud) { +fun GeneratingUi(status: GeminiStatus.Generating) { + val statusText = if (status.isCloud) { stringResource(R.string.gemini_hybrid_status_generating_cloud) } else { stringResource(R.string.gemini_hybrid_status_generating_on_device) } Column(modifier = Modifier.fillMaxWidth()) { - StatusText(status) - if (state.partialOutput.isNotEmpty()) { - OutputText(state.partialOutput) + StatusText(statusText) + if (status.partialOutput.isNotEmpty()) { + OutputText(status.partialOutput) } } } @@ -274,23 +270,15 @@ fun SuccessReviewUi( onLanguageSelected: (String) -> Unit, onTranslate: () -> Unit, onReset: () -> Unit, - translationState: GeminiHybridUiState, + generationStatus: GeminiStatus, ) { Column(modifier = Modifier.fillMaxWidth()) { reviewInferenceStatus?.let { StatusText(stringResource(it)) } - TextField( + OutlinedTextField( value = reviewText, onValueChange = onReviewTextChanged, - colors = TextFieldDefaults.colors( - focusedContainerColor = Color.Transparent, - unfocusedContainerColor = Color.Transparent, - focusedIndicatorColor = Color.Transparent, - unfocusedIndicatorColor = Color.Transparent, - disabledIndicatorColor = Color.Transparent, - disabledTextColor = MaterialTheme.colorScheme.onSurface, - ), modifier = Modifier .padding(4.dp) .fillMaxWidth() @@ -314,36 +302,36 @@ fun SuccessReviewUi( modifier = Modifier .fillMaxWidth() .padding(top = 12.dp, start = 8.dp, end = 8.dp), - enabled = reviewText.isNotBlank() && translationState !is GeminiHybridUiState.Generating, + enabled = reviewText.isNotBlank() && generationStatus !is GeminiStatus.Generating, onClick = onTranslate, ) Spacer(modifier = Modifier.height(20.dp)) - when (translationState) { - is GeminiHybridUiState.Generating -> { - if (translationState.isTranslation) { - val status = if (translationState.isCloud) { + when (generationStatus) { + is GeminiStatus.Generating -> { + if (generationStatus.isTranslation) { + val statusText = if (generationStatus.isCloud) { stringResource(R.string.gemini_hybrid_status_generating_cloud) } else { stringResource(R.string.gemini_hybrid_status_generating_on_device) } - StatusText(status) - if (translationState.partialOutput.isNotEmpty()) { - OutputText(translationState.partialOutput) + StatusText(statusText) + if (generationStatus.partialOutput.isNotEmpty()) { + OutputText(generationStatus.partialOutput) } } } - is GeminiHybridUiState.Success -> { - if (translationState.isTranslation) { - val inferenceStatus = if (translationState.isCloud) { + is GeminiStatus.Success -> { + if (generationStatus.isTranslation) { + val inferenceStatus = if (generationStatus.isCloud) { R.string.gemini_hybrid_generated_cloud } else { R.string.gemini_hybrid_generated_on_device } StatusText(stringResource(inferenceStatus)) - OutputText(translationState.output) + OutputText(generationStatus.output) } } diff --git a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt index aae00633..9545e8de 100644 --- a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt +++ b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt @@ -33,44 +33,39 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -sealed interface GeminiHybridUiState { - data object Initial : GeminiHybridUiState - data object CheckingOnDeviceStatus : GeminiHybridUiState +sealed interface GeminiStatus { + data object Initial : GeminiStatus + data object CheckingOnDeviceStatus : GeminiStatus data class Generating( val isCloud: Boolean, val partialOutput: String = "", val isTranslation: Boolean = false - ) : GeminiHybridUiState + ) : GeminiStatus data class Success( val output: String, val isCloud: Boolean, val isTranslation: Boolean = false - ) : GeminiHybridUiState + ) : GeminiStatus - data class Error(val message: String) : GeminiHybridUiState + data class Error(val message: String) : GeminiStatus } +@OptIn(PublicPreviewAPI::class) +data class UiState( + val selectedMode: InferenceMode = InferenceMode.ONLY_ON_DEVICE, + val selectedTags: List = emptyList(), + val reviewText: String = "", + val reviewInferenceStatus: Int? = null, + val selectedLanguage: String = "Korean", + val status: GeminiStatus = GeminiStatus.Initial +) + @PublicPreviewAPI @HiltViewModel class GeminiHybridViewModel @Inject constructor() : ViewModel() { - private val _uiState = MutableStateFlow(GeminiHybridUiState.Initial) - val uiState: StateFlow = _uiState.asStateFlow() - - private val _inferenceMode = MutableStateFlow(InferenceMode.ONLY_ON_DEVICE) - val inferenceMode: StateFlow = _inferenceMode.asStateFlow() - - private val _selectedTags = MutableStateFlow>(emptyList()) - val selectedTags: StateFlow> = _selectedTags.asStateFlow() - - private val _reviewText = MutableStateFlow("") - val reviewText: StateFlow = _reviewText.asStateFlow() - - private val _reviewInferenceStatus = MutableStateFlow(null) - val reviewInferenceStatus: StateFlow = _reviewInferenceStatus.asStateFlow() - - private val _selectedLanguage = MutableStateFlow("Korean") - val selectedLanguage: StateFlow = _selectedLanguage.asStateFlow() + private val _uiState = MutableStateFlow(UiState()) + val uiState: StateFlow = _uiState.asStateFlow() val tags = listOf( R.string.location, @@ -90,34 +85,43 @@ class GeminiHybridViewModel @Inject constructor() : ViewModel() { ) fun setInferenceMode(mode: InferenceMode) { - _inferenceMode.value = mode + _uiState.update { it.copy(selectedMode = mode) } } fun toggleTag(tagResId: Int) { - _selectedTags.update { current -> - if (current.contains(tagResId)) current - tagResId else current + tagResId + _uiState.update { state -> + val newTags = if (state.selectedTags.contains(tagResId)) { + state.selectedTags - tagResId + } else { + state.selectedTags + tagResId + } + state.copy(selectedTags = newTags) } } fun updateReviewText(text: String) { - _reviewText.value = text + _uiState.update { it.copy(reviewText = text) } } fun setSelectedLanguage(language: String) { - _selectedLanguage.value = language + _uiState.update { it.copy(selectedLanguage = language) } } fun generateReview(tagStrings: List) { if (tagStrings.isEmpty()) { - _uiState.value = GeminiHybridUiState.Error("Please select at least one tag") + _uiState.update { it.copy(status = GeminiStatus.Error("Please select at least one tag")) } return } viewModelScope.launch { - _uiState.value = GeminiHybridUiState.Generating( - isCloud = _inferenceMode.value == InferenceMode.ONLY_IN_CLOUD, - isTranslation = false - ) + _uiState.update { + it.copy( + status = GeminiStatus.Generating( + isCloud = it.selectedMode == InferenceMode.ONLY_IN_CLOUD, + isTranslation = false + ) + ) + } try { val prompt = "Write a simple, short and generic hotel review positively covering the following themes: ${ @@ -127,57 +131,69 @@ class GeminiHybridViewModel @Inject constructor() : ViewModel() { val model = Firebase.ai(backend = GenerativeBackend.googleAI()) .generativeModel( "gemini-2.5-flash-lite", - onDeviceConfig = OnDeviceConfig(mode = _inferenceMode.value) + onDeviceConfig = OnDeviceConfig(mode = _uiState.value.selectedMode) ) model.generateContentStream(prompt).collect { chunk -> val isCloud = chunk.inferenceSource == InferenceSource.IN_CLOUD _uiState.update { state -> - if (state is GeminiHybridUiState.Generating) { - state.copy( + val currentStatus = state.status + val newStatus = if (currentStatus is GeminiStatus.Generating) { + currentStatus.copy( isCloud = isCloud, - partialOutput = state.partialOutput + (chunk.text ?: "") + partialOutput = currentStatus.partialOutput + (chunk.text ?: "") ) } else { - GeminiHybridUiState.Generating( + GeminiStatus.Generating( isCloud = isCloud, partialOutput = chunk.text ?: "", isTranslation = false ) } + state.copy(status = newStatus) } } - val finalState = uiState.value - if (finalState is GeminiHybridUiState.Generating) { - val output = finalState.partialOutput.trimEnd() - _reviewText.value = output - _reviewInferenceStatus.value = if (finalState.isCloud) { + val finalState = _uiState.value + val finalStatus = finalState.status + if (finalStatus is GeminiStatus.Generating) { + val output = finalStatus.partialOutput.trimEnd() + val inferenceStatusResId = if (finalStatus.isCloud) { R.string.gemini_hybrid_generated_cloud } else { R.string.gemini_hybrid_generated_on_device } - _uiState.value = - GeminiHybridUiState.Success(output, finalState.isCloud, isTranslation = false) + _uiState.update { + it.copy( + reviewText = output, + reviewInferenceStatus = inferenceStatusResId, + status = GeminiStatus.Success(output, finalStatus.isCloud, isTranslation = false) + ) + } } } catch (e: Exception) { Log.e("GeminiHybrid", "Inference failed", e) - _uiState.value = - GeminiHybridUiState.Error(e.localizedMessage ?: "Unknown error occurred") + _uiState.update { + it.copy(status = GeminiStatus.Error(e.localizedMessage ?: "Unknown error occurred")) + } } } } fun translate(text: String, language: String) { if (text.isBlank()) { - _uiState.value = GeminiHybridUiState.Error("Text to translate cannot be empty") + _uiState.update { it.copy(status = GeminiStatus.Error("Text to translate cannot be empty")) } return } viewModelScope.launch { - _uiState.value = GeminiHybridUiState.Generating( - isCloud = _inferenceMode.value == InferenceMode.ONLY_IN_CLOUD, - isTranslation = true - ) + _uiState.update { + it.copy( + status = GeminiStatus.Generating( + isCloud = it.selectedMode == InferenceMode.ONLY_IN_CLOUD, + isTranslation = true + ) + ) + } try { val prompt = "Translate the following text to $language. Return ONLY the translated text, no explanations:\n\n$text" @@ -185,47 +201,52 @@ class GeminiHybridViewModel @Inject constructor() : ViewModel() { val model = Firebase.ai(backend = GenerativeBackend.googleAI()) .generativeModel( "gemini-2.5-flash-lite", - onDeviceConfig = OnDeviceConfig(mode = _inferenceMode.value) + onDeviceConfig = OnDeviceConfig(mode = _uiState.value.selectedMode) ) model.generateContentStream(prompt).collect { chunk -> val isCloud = chunk.inferenceSource == InferenceSource.IN_CLOUD _uiState.update { state -> - if (state is GeminiHybridUiState.Generating) { - state.copy( + val currentStatus = state.status + val newStatus = if (currentStatus is GeminiStatus.Generating) { + currentStatus.copy( isCloud = isCloud, - partialOutput = state.partialOutput + (chunk.text ?: "") + partialOutput = currentStatus.partialOutput + (chunk.text ?: "") ) } else { - GeminiHybridUiState.Generating( + GeminiStatus.Generating( isCloud = isCloud, partialOutput = chunk.text ?: "", isTranslation = true ) } + state.copy(status = newStatus) } } - val finalState = uiState.value - if (finalState is GeminiHybridUiState.Generating) { - _uiState.value = GeminiHybridUiState.Success( - finalState.partialOutput, - finalState.isCloud, - isTranslation = true - ) + val finalState = _uiState.value + val finalStatus = finalState.status + if (finalStatus is GeminiStatus.Generating) { + _uiState.update { + it.copy( + status = GeminiStatus.Success( + finalStatus.partialOutput, + finalStatus.isCloud, + isTranslation = true + ) + ) + } } } catch (e: Exception) { Log.e("GeminiHybrid", "Inference failed", e) - _uiState.value = - GeminiHybridUiState.Error(e.localizedMessage ?: "Unknown error occurred") + _uiState.update { + it.copy(status = GeminiStatus.Error(e.localizedMessage ?: "Unknown error occurred")) + } } } } fun reset() { - _uiState.value = GeminiHybridUiState.Initial - _selectedTags.value = emptyList() - _reviewText.value = "" - _reviewInferenceStatus.value = null + _uiState.value = UiState() } } From cb0ebc3822fbebf053002879520eab92a7357d27 Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Tue, 3 Mar 2026 10:26:36 -0800 Subject: [PATCH 06/10] Simplify UI logic to address comments --- .../geminihybrid/GeminiHybridScreen.kt | 43 ++++++++----------- .../geminihybrid/GeminiHybridViewModel.kt | 8 ++-- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt index 17b669ff..b78c5c55 100644 --- a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt +++ b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt @@ -126,8 +126,9 @@ fun GeminiHybridScreen(viewModel: GeminiHybridViewModel = hiltViewModel()) { modifier = Modifier.padding(8.dp), ) - when (val status = uiState.status) { - is GeminiStatus.Initial -> { + val status = uiState.status + when { + status is GeminiStatus.Initial -> { InitialReviewUi( tags = viewModel.tags, selectedTags = uiState.selectedTags, @@ -142,30 +143,19 @@ fun GeminiHybridScreen(viewModel: GeminiHybridViewModel = hiltViewModel()) { ) } - is GeminiStatus.CheckingOnDeviceStatus -> { + status is GeminiStatus.CheckingOnDeviceStatus -> { StatusText(stringResource(R.string.gemini_hybrid_status_checking)) } - is GeminiStatus.Generating -> { - if (!status.isTranslation) { - GeneratingUi(status) - } else { - SuccessReviewUi( - reviewText = uiState.reviewText, - reviewInferenceStatus = uiState.reviewInferenceStatus, - onReviewTextChanged = viewModel::updateReviewText, - languageKeys = viewModel.languageMap.keys.toList(), - languageMap = viewModel.languageMap, - selectedLanguage = uiState.selectedLanguage, - onLanguageSelected = viewModel::setSelectedLanguage, - onTranslate = { viewModel.translate(uiState.reviewText, uiState.selectedLanguage) }, - onReset = viewModel::reset, - generationStatus = status, - ) - } + status is GeminiStatus.Generating && !status.isTranslation -> { + GeneratingUi(status) } - is GeminiStatus.Success -> { + status is GeminiStatus.Error -> { + ErrorUi(status.message, onReset = viewModel::reset) + } + + else -> { SuccessReviewUi( reviewText = uiState.reviewText, reviewInferenceStatus = uiState.reviewInferenceStatus, @@ -174,15 +164,16 @@ fun GeminiHybridScreen(viewModel: GeminiHybridViewModel = hiltViewModel()) { languageMap = viewModel.languageMap, selectedLanguage = uiState.selectedLanguage, onLanguageSelected = viewModel::setSelectedLanguage, - onTranslate = { viewModel.translate(uiState.reviewText, uiState.selectedLanguage) }, + onTranslate = { + viewModel.translate( + uiState.reviewText, + uiState.selectedLanguage + ) + }, onReset = viewModel::reset, generationStatus = status, ) } - - is GeminiStatus.Error -> { - ErrorUi(status.message, onReset = viewModel::reset) - } } } } diff --git a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt index 9545e8de..253642d2 100644 --- a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt +++ b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt @@ -52,7 +52,7 @@ sealed interface GeminiStatus { } @OptIn(PublicPreviewAPI::class) -data class UiState( +data class GeminiHybridUiState( val selectedMode: InferenceMode = InferenceMode.ONLY_ON_DEVICE, val selectedTags: List = emptyList(), val reviewText: String = "", @@ -64,8 +64,8 @@ data class UiState( @PublicPreviewAPI @HiltViewModel class GeminiHybridViewModel @Inject constructor() : ViewModel() { - private val _uiState = MutableStateFlow(UiState()) - val uiState: StateFlow = _uiState.asStateFlow() + private val _uiState = MutableStateFlow(GeminiHybridUiState()) + val uiState: StateFlow = _uiState.asStateFlow() val tags = listOf( R.string.location, @@ -247,6 +247,6 @@ class GeminiHybridViewModel @Inject constructor() : ViewModel() { } fun reset() { - _uiState.value = UiState() + _uiState.value = GeminiHybridUiState() } } From a5191cee4845252e7fa4fea42c39bf70d011d304 Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Tue, 3 Mar 2026 10:50:07 -0800 Subject: [PATCH 07/10] Address comments --- .../com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt | 4 ---- .../android/ai/samples/geminihybrid/GeminiHybridViewModel.kt | 1 - samples/gemini-hybrid/src/main/res/values/strings.xml | 3 --- 3 files changed, 8 deletions(-) diff --git a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt index b78c5c55..498bad34 100644 --- a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt +++ b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt @@ -143,10 +143,6 @@ fun GeminiHybridScreen(viewModel: GeminiHybridViewModel = hiltViewModel()) { ) } - status is GeminiStatus.CheckingOnDeviceStatus -> { - StatusText(stringResource(R.string.gemini_hybrid_status_checking)) - } - status is GeminiStatus.Generating && !status.isTranslation -> { GeneratingUi(status) } diff --git a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt index 253642d2..684b76a1 100644 --- a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt +++ b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridViewModel.kt @@ -35,7 +35,6 @@ import kotlinx.coroutines.launch sealed interface GeminiStatus { data object Initial : GeminiStatus - data object CheckingOnDeviceStatus : GeminiStatus data class Generating( val isCloud: Boolean, val partialOutput: String = "", diff --git a/samples/gemini-hybrid/src/main/res/values/strings.xml b/samples/gemini-hybrid/src/main/res/values/strings.xml index 16e6413e..5faa69c9 100644 --- a/samples/gemini-hybrid/src/main/res/values/strings.xml +++ b/samples/gemini-hybrid/src/main/res/values/strings.xml @@ -9,12 +9,9 @@ Spanish French German - Checking on-device status… - Downloading on-device model: %1$d / %2$d Generating on-device… Generating in cloud… Please enter some text. - Something went wrong. Cloud On-device Generated in the cloud From bcdb7ddd8a8ca40143146051d0a53792568108a1 Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Tue, 3 Mar 2026 10:55:17 -0800 Subject: [PATCH 08/10] Fix strings --- .../com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt | 2 +- samples/gemini-hybrid/src/main/res/values/strings.xml | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt index 498bad34..a15fb129 100644 --- a/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt +++ b/samples/gemini-hybrid/src/main/java/com/android/ai/samples/geminihybrid/GeminiHybridScreen.kt @@ -188,7 +188,7 @@ fun InitialReviewUi( onGenerate: () -> Unit, ) { Text( - "Select topics for your review:", + stringResource(R.string.select_topics_for_your_review), modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp), style = MaterialTheme.typography.titleMedium, ) diff --git a/samples/gemini-hybrid/src/main/res/values/strings.xml b/samples/gemini-hybrid/src/main/res/values/strings.xml index 5faa69c9..82a3fc9e 100644 --- a/samples/gemini-hybrid/src/main/res/values/strings.xml +++ b/samples/gemini-hybrid/src/main/res/values/strings.xml @@ -11,9 +11,6 @@ German Generating on-device… Generating in cloud… - Please enter some text. - Cloud - On-device Generated in the cloud Generated on device PREFER ON-DEVICE From cbbcc5bfdd03f26a7f58efa50c04e48d146c52ab Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Tue, 3 Mar 2026 11:01:44 -0800 Subject: [PATCH 09/10] Move hybrid sample to the top of the list --- README.md | 4 ++-- .../ai/catalog/domain/SampleCatalog.kt | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 8a618df3..dbf33cb6 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ Here is the list of samples you can find in the `/samples` folder: | Samples | | |:----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Gemini Hybrid sample | ✨📱☁️ **Hybrid Inference**:
A sample demonstrating a hybrid approach to generative AI, utilizing both on-device (Gemini Nano via ML Kit) and cloud-based (Gemini via Firebase AI SDK) models. It showcases how to fallback to the cloud when on-device capabilities are unavailable.



**[> Browse code](samples/gemini-hybrid)**

| +| | | | Gemini Image Chat sample | ✨🖼️🍌 **Gemini Image Chat**:
A chatbot app using the new [Gemini 3 Pro Image model](https://deepmind.google/models/gemini-image/pro/) (a.k.a. "Nano Banana Pro") enabling image generation and iterations via conversation with the Gemini model. Ask the model to generate an image and ask for tweaks in the chat.



**[> Browse code](samples/gemini-image-chat)**

| | | | | Gemini Chatbot sample | ✨🗣️ **Gemini Chatbot**:
A chatbot app using the Gemini Flash model. You can tweak the [system instructions](https://firebase.google.com/docs/ai-logic/system-instructions) in the model configuration to change the tone or the persona of the model.



**[> Browse code](samples/gemini-chatbot)**

| @@ -44,8 +46,6 @@ Here is the list of samples you can find in the `/samples` folder: | | | | Gemini Nano Rewrite | ✨📱🖋️ **On-device Writing Assistance**:
A sample letting you proofread and rewrite text using Gemini Nano via the [GenAI Rewriting API](https://developers.google.com/ml-kit/genai/rewriting/android).



**[> Browse code](samples/genai-writing-assistance)**

| | | | -| Gemini Hybrid sample | ✨📱☁️ **Hybrid Inference**:
A sample demonstrating a hybrid approach to generative AI, utilizing both on-device (Gemini Nano via ML Kit) and cloud-based (Gemini via Firebase AI SDK) models. It showcases how to fallback to the cloud when on-device capabilities are unavailable.



**[> Browse code](samples/gemini-hybrid)**

| -| | | | Imagen sample | 🖼️ **Image Generation with Imagen**:
A sample using [Imagen to generate images](https://developer.android.com/ai/imagen#generate-image) of landscapes, objects and people in various artistic style.



**[> Browse code](samples/imagen)**

| | | | | Magic Selfie sample | 🖼️📸 **Magic Selfie**:
A sample using [ML Kit subject Segmentation SDK](https://developers.google.com/ml-kit/vision/subject-segmentation/android) to remove the background behind a person, and [Imagen](https://developer.android.com/ai/imagen#generate-image) to generate new background.



**[> Browse code](samples/magic-selfie)**

| diff --git a/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt b/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt index 18089d35..b16cafff 100644 --- a/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt +++ b/app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt @@ -41,6 +41,16 @@ import com.google.firebase.ai.type.PublicPreviewAPI @OptIn(PublicPreviewAPI::class) @RequiresPermission(Manifest.permission.RECORD_AUDIO) val sampleCatalog = listOf( + SampleCatalogItem( + title = R.string.gemini_hybrid_sample_list_title, + description = R.string.gemini_hybrid_sample_list_description, + route = "GeminiHybridScreen", + sampleEntryScreen = { GeminiHybridScreen() }, + tags = listOf(SampleTags.GEMINI_NANO, SampleTags.GEMINI_FLASH, SampleTags.ML_KIT, SampleTags.FIREBASE), + needsFirebase = true, + keyArt = R.drawable.img_keyart_text, + isFeatured = true, + ), SampleCatalogItem( title = R.string.gemini_image_chat_list_title, description = R.string.gemini_image_chat_list_description, @@ -59,7 +69,6 @@ val sampleCatalog = listOf( tags = listOf(SampleTags.IMAGEN, SampleTags.FIREBASE), needsFirebase = true, keyArt = R.drawable.img_keyart_imagen, - isFeatured = true, ), SampleCatalogItem( title = R.string.gemini_multimodal_sample_list_title, @@ -149,15 +158,6 @@ val sampleCatalog = listOf( needsFirebase = true, keyArt = R.drawable.img_keyart_todo, ), - SampleCatalogItem( - title = R.string.gemini_hybrid_sample_list_title, - description = R.string.gemini_hybrid_sample_list_description, - route = "GeminiHybridScreen", - sampleEntryScreen = { GeminiHybridScreen() }, - tags = listOf(SampleTags.GEMINI_NANO, SampleTags.GEMINI_FLASH, SampleTags.ML_KIT, SampleTags.FIREBASE), - needsFirebase = true, - keyArt = R.drawable.img_keyart_chatbot, - ), // To create a new sample entry, add a new SampleCatalogItem here. ) From c25c963cc4867de00a53ca969cf0c7634a16064b Mon Sep 17 00:00:00 2001 From: Thomas Ezan Date: Tue, 3 Mar 2026 11:27:35 -0800 Subject: [PATCH 10/10] Update hybrid sample readme --- samples/gemini-hybrid/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/samples/gemini-hybrid/README.md b/samples/gemini-hybrid/README.md index 5572e8f9..650cc640 100644 --- a/samples/gemini-hybrid/README.md +++ b/samples/gemini-hybrid/README.md @@ -6,8 +6,15 @@ This sample is part of the [AI Sample Catalog](../../). To build and run this sa This sample demonstrates how to use the Firebase Hybrid SDK, utilizing both on-device (Gemini Nano via [ML Kit Prompt API](https://developers.google.com/ml-kit/genai/prompt/android)) and cloud-based models via the [Firebase AI Logic SDK](https://firebase.google.com/docs/ai-logic). -### Key Snippets +The sample lets users generate generic user reviews for a hotel based on a few selected topics. +

+Gemini Hybrid SDK in action +
+ +## How it works + +Here is how the model is instantiated to leverage hybrid inference: ```kotlin val model = Firebase.ai(backend = GenerativeBackend.googleAI()) .generativeModel(