Skip to content

feat: create Firebase AI quickstart #2667

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 52 commits into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
1e0affd
Initial commit
thatfiredev May 1, 2025
d2c9124
flesh out the sample navigation
thatfiredev May 1, 2025
44dab3b
adaptive grid cells
thatfiredev May 1, 2025
a84da19
add chat screen
thatfiredev May 7, 2025
853b22d
refactor: improve bottom navigation
thatfiredev May 8, 2025
5e57af4
Firebase AI Logic
thatfiredev May 9, 2025
96ec3ee
remove bottom navbar
thatfiredev May 9, 2025
ca9d297
wire up the chat screen
thatfiredev May 9, 2025
ce6f676
placeholder for realtime stream
thatfiredev May 9, 2025
0497b93
add imagen screen from previous sample
thatfiredev May 9, 2025
231d65f
use the vertexai SDK for now
thatfiredev May 9, 2025
b811176
finalize Imagen screen
thatfiredev May 9, 2025
abb4cc5
add chat functionality
thatfiredev May 9, 2025
ab8a9bf
rewire chat history
thatfiredev May 9, 2025
4462a50
add system instructions for chatbot sample
thatfiredev May 9, 2025
b1fd192
add a top app bar
thatfiredev May 9, 2025
7bb7e60
refactor(chat): add loading bar to chat screen
thatfiredev May 9, 2025
7daf0d1
refactor: delete ChatMessage in favor of Content
thatfiredev May 9, 2025
0c870af
create an attach button
thatfiredev May 9, 2025
82d0246
add audio summarization sample
thatfiredev May 9, 2025
18b2b4f
show attached files
thatfiredev May 11, 2025
6efcede
add an indicator to messages with attachments
thatfiredev May 11, 2025
0f829d3
show inline images in messages
thatfiredev May 11, 2025
be253fe
feat: add document comparison sample
thatfiredev May 12, 2025
4402678
feat: add audio translation sample
thatfiredev May 12, 2025
e2fd81b
show file data part attachments in chat
thatfiredev May 12, 2025
4594399
feat: add samples for video input
thatfiredev May 12, 2025
1f7aebe
feat: add blog post creator (image sample)
thatfiredev May 12, 2025
71e1607
update launcher vector drawable (app logo)
thatfiredev May 12, 2025
5394f7b
refactor: use firebaseai SDK instead of vertexai
thatfiredev May 13, 2025
557075d
feat: add native image generation sample
thatfiredev May 14, 2025
91814e7
refactor: use GenerativeBackend.googleAI()
thatfiredev May 14, 2025
40aae91
chore: use new Firebase BoM
thatfiredev May 19, 2025
011dea3
temporarily remove Function calling and Stream realtime
thatfiredev May 19, 2025
86f2ff0
undo vertexai change
thatfiredev May 19, 2025
fa4ab3c
allow override of model name in the imagen quickstart
thatfiredev May 20, 2025
b49a86a
chore: move libs to libs.versions.toml
thatfiredev May 20, 2025
fe775f2
chore: move FirebaseAISamples.kt to top-level dir
thatfiredev May 20, 2025
678f1f8
remove stale comments
thatfiredev May 20, 2025
ee48e2a
create README.md
thatfiredev May 20, 2025
a3518c9
Merge branch 'master' into rpf/firebase-ai
thatfiredev May 20, 2025
c0b1c3b
chore: agp 8.9.1
thatfiredev May 20, 2025
2932ba4
Kotlin 2.1.20
thatfiredev May 20, 2025
0d9f26e
chore: remove allProjects {} from ai/build.gradle.kts
thatfiredev May 20, 2025
3bef700
chore: apply compose plugin
thatfiredev May 20, 2025
f133a0a
lint fix?
thatfiredev May 20, 2025
11bbb87
refactor: ai -> firebase-ai
thatfiredev May 20, 2025
145b05c
lint fix for FirebaseAISamples.kt
thatfiredev May 20, 2025
946f4f7
undo dataconnect changes
thatfiredev May 20, 2025
827565e
one more undo
thatfiredev May 20, 2025
eb387a3
ci: wire up CI for firebase-ai
thatfiredev May 20, 2025
84983b3
remove unintended change
thatfiredev May 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions copy_mock_google_services_json.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ cp mock-google-services.json crash/app/google-services.json
cp mock-google-services.json database/app/google-services.json
cp mock-google-services.json dataconnect/app/google-services.json
cp mock-google-services.json dynamiclinks/app/google-services.json
cp mock-google-services.json firebase-ai/app/google-services.json
cp mock-google-services.json firestore/app/google-services.json
cp mock-google-services.json functions/app/google-services.json
cp mock-google-services.json inappmessaging/app/google-services.json
Expand Down
15 changes: 15 additions & 0 deletions firebase-ai/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
32 changes: 32 additions & 0 deletions firebase-ai/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Firebase AI Logic quickstart sample app

This Android sample app demonstrates how to use state-of-the-art
generative AI models (like Gemini) to build AI-powered features and applications.
For more information about Firebase AI Logic, visit the [documentation](http://firebase.google.com/docs/ai-logic).

## Getting Started

To try out this sample app, you need to use latest stable version of Android Studio.
However, if you want to latest lint checks and AI productivity features in Android
Studio use the latest preview version of [Android Studio](https://developer.android.com/studio/preview).

## Features

There are 2 main files that demonstrate the use of Firebase AI Logic:

- [ChatViewModel.kt](app/src/main/java/com/google/firebase/quickstart/ai/feature/text/ChatViewModel.kt)
which can do things such as:
- [Generate Text](https://firebase.google.com/docs/ai-logic/generate-text)
- [Generate structured output (JSON)](https://firebase.google.com/docs/ai-logic/generate-structured-output)
- [Analyze images](https://firebase.google.com/docs/ai-logic/analyze-images)
- [Analyze video](https://firebase.google.com/docs/ai-logic/analyze-video)
- [Analyze audio](https://firebase.google.com/docs/ai-logic/analyze-audio)
- [Analyze documents (PDFs)](https://firebase.google.com/docs/ai-logic/analyze-documents)
- [Generate images using Gemini 2.0](https://firebase.google.com/docs/ai-logic/generate-images-imagen)
- [ImagenViewModel](app/src/main/java/com/google/firebase/quickstart/ai/feature/media/imagen/ImagenViewModel.kt)
which shows how to [Generate images using Imagen models](https://firebase.google.com/docs/ai-logic/generate-images-imagen)

## All samples

The full list of available samples can be found in the
[FirebaseAISamples.kt file](app/src/main/java/com/google/firebase/quickstart/ai/FirebaseAISamples.kt).
1 change: 1 addition & 0 deletions firebase-ai/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
75 changes: 75 additions & 0 deletions firebase-ai/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.compose")
kotlin("plugin.serialization") version "2.1.20"
id("com.google.gms.google-services")
}

android {
namespace = "com.google.firebase.quickstart.ai"
compileSdk = 35

defaultConfig {
applicationId = "com.google.firebase.quickstart.ai"
minSdk = 23
targetSdk = 35
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
compose = true
}
}

dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)

implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
implementation(libs.androidx.material.icons.extended)
implementation(libs.androidx.material3.adaptive.navigation.suite)
implementation(libs.compose.navigation)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
// ViewModel utilities for Compose
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.lifecycle.viewmodel.savedstate)
implementation(libs.kotlinx.serialization.json)

// Firebase
implementation(platform(libs.firebase.bom))
implementation(libs.firebase.ai)

testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
}
21 changes: 21 additions & 0 deletions firebase-ai/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -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
28 changes: 28 additions & 0 deletions firebase-ai/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.FirebaseAIServices"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.FirebaseAIServices">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package com.google.firebase.quickstart.ai

import com.google.firebase.ai.type.ResponseModality
import com.google.firebase.ai.type.content
import com.google.firebase.ai.type.generationConfig
import com.google.firebase.quickstart.ai.ui.navigation.Category
import com.google.firebase.quickstart.ai.ui.navigation.Sample

val FIREBASE_AI_SAMPLES = listOf(
Sample(
title = "Travel tips",
description = "The user wants the model to help a new traveler" +
" with travel tips",
navRoute = "chat",
categories = listOf(Category.TEXT),
systemInstructions = content {
text(
"You are a Travel assistant. You will answer" +
" questions the user asks based on the information listed" +
" in Relevant Information. Do not hallucinate. Do not use" +
" the internet."
)
},
chatHistory = listOf(
content {
role = "user"
text("I have never traveled before. When should I book a flight?")
},
content {
role = "model"
text(
"You should book flights a couple of months ahead of time." +
" It will be cheaper and more flexible for you."
)
},
content {
role = "user"
text("Do I need a passport?")
},
content {
role = "model"
text(
"If you are traveling outside your own country, make sure" +
" your passport is up-to-date and valid for more" +
" than 6 months during your travel."
)
}
),
initialPrompt = content { text("What else is important when traveling?") }
),
Sample(
title = "Chatbot recommendations for courses",
description = "A chatbot suggests courses for a performing arts program.",
navRoute = "chat",
categories = listOf(Category.TEXT),
systemInstructions = content {
text(
"You are a chatbot for the county's performing and fine arts" +
" program. You help students decide what course they will" +
" take during the summer."
)
},
initialPrompt = content {
text("I am interested in Performing Arts. I have taken Theater 1A.")
}
),
Sample(
title = "Audio Summarization",
description = "Summarize an audio file",
navRoute = "chat",
categories = listOf(Category.AUDIO),
chatHistory = listOf(
content { text("Can you help me summarize an audio file?") },
content("model") {
text(
"Of course! Click on the attach button" +
" below and choose an audio file for me to summarize."
)
}
),
initialPrompt = content {
text(
"I have attached the audio file. Please analyze it and summarize the contents" +
" of the audio as bullet points."
)
}
),
Sample(
title = "Translation from audio",
description = "Translate an audio file",
navRoute = "chat",
categories = listOf(Category.AUDIO),
initialPrompt = content {
fileData(
"https://storage.googleapis.com/cloud-samples-data/generative-ai/audio/" +
"How_to_create_a_My_Map_in_Google_Maps.mp3",
"audio/mpeg"
)
text("Please translate the audio to Mandarin.")
}
),
Sample(
title = "Blog post creator",
description = "Create a blog post from an image file.",
navRoute = "chat",
categories = listOf(Category.IMAGE),
initialPrompt = content {
fileData(
"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/meal-prep.jpeg",
"image/jpeg"
)
text(
"Write a short, engaging blog post based on this picture." +
" It should include a description of the meal in the" +
" photo and talk about my journey meal prepping."
)
}
),
Sample(
title = "Imagen 3 - image generation",
description = "Generate images using Imagen 3",
navRoute = "imagen",
categories = listOf(Category.IMAGE),
initialPrompt = content {
text(
"A photo of a modern building with water in the background"
)
}
),
Sample(
title = "Gemini 2.0 Flash - image generation",
description = "Generate and/or edit images using Gemini 2.0 Flash",
navRoute = "chat",
categories = listOf(Category.IMAGE),
modelName = "gemini-2.0-flash-preview-image-generation",
initialPrompt = content {
text(
"Hi, can you create a 3d rendered image of a pig " +
"with wings and a top hat flying over a happy " +
"futuristic scifi city with lots of greenery?"
)
},
generationConfig = generationConfig {
responseModalities = listOf(ResponseModality.TEXT, ResponseModality.IMAGE)
}
),
Sample(
title = "Document comparison",
description = "Compare the contents of 2 documents",
navRoute = "chat",
categories = listOf(Category.DOCUMENT),
initialPrompt = content {
fileData(
"https://storage.googleapis.com/cloud-samples-data/generative-ai/pdf/form_1040_2013.pdf",
"application/pdf"
)
fileData(
"https://storage.googleapis.com/cloud-samples-data/generative-ai/pdf/form_1040_2023.pdf",
"application/pdf"
)
text(
"The first document is from 2013, and the second document is" +
" from 2023. How did the standard deduction evolve?"
)
}
),
Sample(
title = "Hashtags for a video",
description = "Generate hashtags for a video ad",
navRoute = "chat",
categories = listOf(Category.VIDEO),
initialPrompt = content {
fileData(
"https://storage.googleapis.com/cloud-samples-data/generative-ai/video/google_home_celebrity_ad.mp4",
"video/mpeg"
)
text(
"Generate 5-10 hashtags that relate to the video content." +
" Try to use more popular and engaging terms," +
" e.g. #Viral. Do not add content not related to" +
" the video.\n Start the output with 'Tags:'"
)
}
),
Sample(
title = "Summarize video",
description = "Summarize a video and extract important dialogue.",
navRoute = "chat",
categories = listOf(Category.VIDEO),
chatHistory = listOf(
content { text("Can you help me with the description of a video file?") },
content("model") {
text(
"Sure! Click on the attach button below and choose a" +
" video file for me to describe."
)
}
),
initialPrompt = content {
text(
"I have attached the video file. Provide a description of" +
" the video. The description should also contain" +
" anything important which people say in the video."
)
}
)
)
Loading
Loading