Google I/O 2024: Build a Cat Chatbot using Gemini on Android
Gemini is a family of artificial intelligence (AI) models introduced by Google, with each model specializing in specific use cases. At I/O 2024, Google announced the Gemini 1.5 Pro and Gemini 1.5 Flash models. These models are available via the Google AI Client SDK.
In this tutorial, you’ll create an AI chatbot named CatBot using the Gemini 1.5 Pro model. In this chatbot, you’ll interact with a fun cat named Milo.
During the process, you’ll learn to:
- Setup the Google AI API Key.
- Configure and integrate the Gemini model.
- Create a chat UI.
- Add safety checks.
And with that, it’s time to get started.
Getting Started
Download the materials for this tutorial by clicking the Download Materials button at the top or bottom of the tutorial. Then, open the starter project in Android Studio Jellyfish or later.
You’ll work on CatBot, an AI-based chatbot that lets you chat with a cat named Milo.
The project contains the following files:
- MainActivity: Contains the main Activity and hosts the Composables.
- ChatMessage: A data class representing each message.
- ChatScreen: A Composable describing the chat screen.
- ChatViewModel: A ViewModel representing the state of the chat screen. It’ll contain the logic of handling outgoing and incoming messages.
Build and run the app. You’ll see the following screen:
The screen has an input field for the chat message and a send button. Right now, sending a message doesn’t do anything. You’ll change this throughout the tutorial.
Generating the API key
First, you’ll need an API key to interact with the Gemini APIs. Head over to https://aistudio.google.com/app which will open the Google AI Studio. On the right side of the studio, you’ll see the Model dropdown:
Select the Gemini 1.5 Flash model.
Although the Gemini 1.5 Pro model is more powerful, the Gemini 1.5 Flash is significantly faster, making it more suitable for this chatbot application.
Next, click Get API key on the left navigation panel:
You’ll get the following screen if you haven’t created an API key earlier:
Click Create API key. You’ll get the Create API Key dialog as shown below:
Select Create API key in new project. Once the API key has been generated, you’ll see a dialog with your new API key. Copy the API Key and head back to Android Studio.
Open local.properties and add the following code:
apiKey=your API key here
In the code above, replace your API key here
with the API key you copied earlier.
Note: This method of specifying the API key inside the Android project is only suitable for prototypes. For production apps, the API key should be present on the backend, and access to the model should only be done via an API.
Now that the API key is ready, you can start modeling the chat message.
Modeling the Chat Message
In this chatbot, there can be three types of messages:
- User messages
- Replies from the model
- Error messages
To model the types of messages, create a new class named ChatParticipant
and add the following code:
enum class ChatParticipant {
USER,
AI,
ERROR
}
In the code above, you created an enum class with three possible values, each representing a type of message.
Next, you need to associate each chat message with a particular participant. Open ChatMessage
and add the following attribute to the data class:
val participant: ChatParticipant
The ChatMessage
class will now be as follows:
data class ChatMessage(
val id: String = UUID.randomUUID().toString(),
val message: String,
val participant: ChatParticipant
)
Configuring the Gemini Model
You’ll need the Google AI Client SDK to access the Gemini model on Android. Open the app-module build.gradle and add the following dependency:
implementation("com.google.ai.client.generativeai:generativeai:0.6.0")
Do a Gradle sync and wait for the dependency to finish downloading.
Next, create a new file named Model.kt and add the following code:
internal val model = GenerativeModel(
// 1
modelName = "gemini-1.5-flash-latest",
// 2
apiKey = BuildConfig.apiKey,
// 3
generationConfig = generationConfig {
temperature = 0.7f
},
// 4
systemInstruction = content {
text("You are a fun cat named Milo. " +
"Give mischievous answers in maximum 3 lines. " +
"Try to keep the conversation going")
}
)
The code above creates a new instance of GenerativeModel
with the following arguments:
-
modelName
: Since you’re using Gemini 1.5 Flash, the modelName is gemini-1.5-flash-latest. In the case of Gemini 1.5 Pro, the model name would be gemini-1.5-pro-latest. -
apiKey
: This value is extracted from the local.properties value you set earlier in the tutorial. -
generationConfig
: The model configuration. Here, you set thetemperature
value to 0.7. The temperature can be anything between 0 and 1. A lower temperature will lead to a more predictable response, while a higher temperature will lead to a more creative response. -
systemInstruction
: This is the base prompt for your model, which will determine the persona of your model. For this app, you’re asking the model to act like a fun cat named Milo and providing additional details.
Note: Don’t import the BuildConfig
class from the Google AI Client SDK. When you build the project, the needed BuildConfig
will be generated.
Adding Initial History
When working on a conversation app using the Gemini API, you can add message history along with the system prompt. This lets you provide the model with the context of a previous conversation so the user can continue a conversation across app sessions.
Open ChatViewModel
and change the constructor to:
class ChatViewModel(
generativeModel: GenerativeModel = model
)
ChatViewModel
now takes an instance of GenerativeModel
as a constructor argument, and the default value is set to the instance you created in the previous section.
Next, you’ll need to provide the chat history. Add the following code inside the ChatViewModel
class:
// 1
private val chat = generativeModel.startChat(
// 2
history = listOf(
//3
content("user") {
text("Hello n")
},
content("model") {
text("Meow! What's up, human? Did you bring me any tuna? 😉 n")
}
)
)
In the code above, you:
- Start a new chat with the
startChat
method. - Specify the
history
argument as a list of messages. - Specify that the user sent the first message and the model sent the second.
Now that the model has the context of the message history, the UI should display the messages when you open the app.
Change the initialization of _uiState
:
private val _uiState: MutableStateFlow<List<ChatMessage>> =
MutableStateFlow(
chat.history.map { content ->
ChatMessage(
message = content.parts.first().asTextOrNull() ?: "",
participant = if (content.role == "user")
ChatParticipant.USER
else
ChatParticipant.AI,
)
}
)
In the code above, you iterate over the chat history and map each message to an instance of ChatMessage
. You then set the default value of the state to contain the message history.
Now, every time you run the app, a conversation history will be available, making it easy to continue the conversation.