Skip to content

Commit fee369b

Browse files
Add hybrid SDK sample (#153)
1 parent 8e6dacb commit fee369b

15 files changed

Lines changed: 916 additions & 5 deletions

File tree

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ Here is the list of samples you can find in the `/samples` folder:
3232

3333
| Samples | |
3434
|:----------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
35+
| <img src="samples/gemini-hybrid/gemini_hybrid.png" width="150" alt="Gemini Hybrid sample"> | ✨📱☁️ **Hybrid Inference**: <br>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.<br><br><br><br> **[> Browse code](samples/gemini-hybrid)**<br><br> |
36+
| | |
3537
| <img src="samples/gemini-image-chat/android_nano_banana.png" width="150" alt="Gemini Image Chat sample"> | ✨🖼️🍌 **Gemini Image Chat**:<br>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.<br><br><br><br> **[> Browse code](samples/gemini-image-chat)**<br><br> |
3638
| | |
3739
| <img src="samples/gemini-chatbot/gemini_chatbot.png" width="150" alt="Gemini Chatbot sample"> | ✨🗣️ **Gemini Chatbot**:<br>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.<br><br><br><br> **[> Browse code](samples/gemini-chatbot)**<br><br> |
@@ -42,7 +44,7 @@ Here is the list of samples you can find in the `/samples` folder:
4244
| | |
4345
| <img src="samples/genai-image-description/nano_image_description.png" width="150" alt="Gemini Nano Image description"> | ✨📱🔍 **On-device Image Description**: <br>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).<br><br><br><br> **[> Browse code](samples/genai-image-description)**<br><br> |
4446
| | |
45-
| <img src="samples/genai-writing-assistance/nano_rewrite.png" width="150" alt="Gemini Nano Rewrite"> | ✨📱🖋️ **On-device Writing Assistance**: <br>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).<br><br><br><br> **[> Browse code](samples/genai-writing-assistance)**<br><br> |
47+
| <img src="samples/genai-writing-assistance/nano_rewrite.png" width="150" alt="Gemini Nano Rewrite"> | ✨📱🖋️ **On-device Writing Assistance**: <br>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).<br><br><br><br> **[> Browse code](samples/genai-writing-assistance)**<br><br> |
4648
| | |
4749
| <img src="samples/imagen/imagen_image_generation.png" width="150" alt="Imagen sample"> | 🖼️ **Image Generation with Imagen**: <br>A sample using [Imagen to generate images](https://developer.android.com/ai/imagen#generate-image) of landscapes, objects and people in various artistic style.<br><br><br><br> **[> Browse code](samples/imagen)**<br><br> |
4850
| | |

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ dependencies {
9393
implementation(project(":samples:gemini-live-todo"))
9494
implementation(project(":samples:gemini-video-metadata-creation"))
9595
implementation(project(":samples:gemini-image-chat"))
96+
implementation(project(":samples:gemini-hybrid"))
9697

9798
testImplementation(libs.junit)
9899
androidTestImplementation(libs.androidx.junit)

app/src/main/java/com/android/ai/catalog/domain/SampleCatalog.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,26 @@ import com.android.ai.samples.geminivideosummary.ui.VideoSummarizationScreen
3131
import com.android.ai.samples.genai_image_description.GenAIImageDescriptionScreen
3232
import com.android.ai.samples.genai_summarization.GenAISummarizationScreen
3333
import com.android.ai.samples.genai_writing_assistance.GenAIWritingAssistanceScreen
34+
import com.android.ai.samples.geminihybrid.GeminiHybridScreen
3435
import com.android.ai.samples.imagen.ui.ImagenScreen
3536
import com.android.ai.samples.imagenediting.ui.ImagenEditingScreen
3637
import com.android.ai.samples.magicselfie.ui.MagicSelfieScreen
3738
import com.android.ai.theme.extendedColorScheme
39+
import com.google.firebase.ai.type.PublicPreviewAPI
3840

41+
@OptIn(PublicPreviewAPI::class)
3942
@RequiresPermission(Manifest.permission.RECORD_AUDIO)
4043
val sampleCatalog = listOf(
44+
SampleCatalogItem(
45+
title = R.string.gemini_hybrid_sample_list_title,
46+
description = R.string.gemini_hybrid_sample_list_description,
47+
route = "GeminiHybridScreen",
48+
sampleEntryScreen = { GeminiHybridScreen() },
49+
tags = listOf(SampleTags.GEMINI_NANO, SampleTags.GEMINI_FLASH, SampleTags.ML_KIT, SampleTags.FIREBASE),
50+
needsFirebase = true,
51+
keyArt = R.drawable.img_keyart_text,
52+
isFeatured = true,
53+
),
4154
SampleCatalogItem(
4255
title = R.string.gemini_image_chat_list_title,
4356
description = R.string.gemini_image_chat_list_description,
@@ -56,7 +69,6 @@ val sampleCatalog = listOf(
5669
tags = listOf(SampleTags.IMAGEN, SampleTags.FIREBASE),
5770
needsFirebase = true,
5871
keyArt = R.drawable.img_keyart_imagen,
59-
isFeatured = true,
6072
),
6173
SampleCatalogItem(
6274
title = R.string.gemini_multimodal_sample_list_title,

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
<string name="gemini_live_todo_list_description">"Simple to-do app using the Gemini Live API to interact with the items in the list"</string>
2828
<string name="gemini_image_chat_list_title">Chat with Nano Banana Pro</string>
2929
<string name="gemini_image_chat_list_description">Conversational Image generation with Gemini 3 Pro Image</string>
30+
<string name="gemini_hybrid_sample_list_title">Gemini Hybrid</string>
31+
<string name="gemini_hybrid_sample_list_description">Inference with Firebase Hybrid SDK using either Gemini Nano on-device or Gemini Flash in the Cloud.</string>
3032
<string name="firebase_required">Firebase Required</string>
3133
<string name="firebase_required_description">This feature requires Firebase to be initialized.</string>
3234
<string name="close">Close</string>

gradle/libs.versions.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
[versions]
22
agp = "8.8.2"
33
coilCompose = "3.1.0"
4-
firebaseBom = "34.5.0"
4+
firebaseAiOndevice = "16.0.0-beta01"
5+
firebaseBom = "34.10.0"
56
lifecycleRuntimeCompose = "2.9.1"
67
mlkitGenAi = "1.0.0-beta1"
78
kotlin = "2.1.0"
@@ -40,8 +41,9 @@ richtext = "1.0.0-alpha02"
4041
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
4142
androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycleRuntimeCompose" }
4243
coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coilCompose" }
44+
firebase-ai-ondevice = { module = "com.google.firebase:firebase-ai-ondevice", version.ref = "firebaseAiOndevice" }
4345
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
44-
firebase-ai = { group = "com.google.firebase", name = "firebase-ai" }
46+
firebase-ai = { module = "com.google.firebase:firebase-ai"}
4547
firebase-common-ktx = { group = "com.google.firebase", name = "firebase-common-ktx", version.ref = "firebaseCommonKtx" }
4648
genai-image-description = { module = "com.google.mlkit:genai-image-description", version.ref = "mlkitGenAi" }
4749
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
9496
hilt-plugin = { id = "com.google.dagger.hilt.android", version.ref = "hilt"}
9597
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
9698
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
97-
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
99+
spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }

samples/gemini-hybrid/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

samples/gemini-hybrid/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Gemini Hybrid Sample
2+
3+
This sample is part of the [AI Sample Catalog](../../). To build and run this sample, you should clone the entire repository.
4+
5+
## Description
6+
7+
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).
8+
9+
The sample lets users generate generic user reviews for a hotel based on a few selected topics.
10+
11+
<div style="text-align: center;">
12+
<img width="320" alt="Gemini Hybrid SDK in action" src="gemini_hybrid.png" />
13+
</div>
14+
15+
## How it works
16+
17+
Here is how the model is instantiated to leverage hybrid inference:
18+
```kotlin
19+
val model = Firebase.ai(backend = GenerativeBackend.googleAI())
20+
.generativeModel(
21+
"gemini-2.5-flash-lite",
22+
onDeviceConfig = OnDeviceConfig(mode = InferenceMode.PREFER_ON_DEVICE)
23+
)
24+
25+
val response = model.generateContent(prompt)
26+
```
27+
28+
Read more about the [Firebase Hybrid SDK](https://firebase.google.com/docs/ai-logic/hybrid/android/get-started?api=dev) in the Firebase documentation.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
plugins {
18+
alias(libs.plugins.android.library)
19+
alias(libs.plugins.jetbrains.kotlin.android)
20+
alias(libs.plugins.ksp)
21+
alias(libs.plugins.compose.compiler)
22+
}
23+
24+
android {
25+
namespace = "com.android.ai.samples.geminihybrid"
26+
compileSdk = 36
27+
28+
buildFeatures {
29+
compose = true
30+
}
31+
32+
defaultConfig {
33+
minSdk = 26
34+
35+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
36+
consumerProguardFiles("consumer-rules.pro")
37+
}
38+
39+
buildTypes {
40+
release {
41+
isMinifyEnabled = false
42+
proguardFiles(
43+
getDefaultProguardFile("proguard-android-optimize.txt"),
44+
"proguard-rules.pro",
45+
)
46+
}
47+
}
48+
compileOptions {
49+
sourceCompatibility = JavaVersion.VERSION_17
50+
targetCompatibility = JavaVersion.VERSION_17
51+
}
52+
kotlinOptions {
53+
jvmTarget = "17"
54+
}
55+
}
56+
57+
dependencies {
58+
implementation(libs.androidx.core.ktx)
59+
implementation(libs.androidx.appcompat)
60+
implementation(libs.androidx.material3)
61+
implementation(libs.androidx.activity.compose)
62+
implementation(platform(libs.androidx.compose.bom))
63+
implementation(libs.androidx.material.icons.extended)
64+
implementation(libs.hilt.android)
65+
implementation(libs.hilt.navigation.compose)
66+
implementation(libs.androidx.runtime.livedata)
67+
implementation(libs.androidx.lifecycle.runtime.compose)
68+
implementation(platform(libs.firebase.bom))
69+
implementation(libs.firebase.ai)
70+
implementation(libs.firebase.ai.ondevice)
71+
72+
implementation(project(":ui-component"))
73+
debugImplementation(libs.ui.tooling)
74+
ksp(libs.hilt.compiler)
75+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
154 KB
Loading

0 commit comments

Comments
 (0)