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:

Cat chatbot starter project 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:

Google AI Studio 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:

Google AI Studio Get API Key button

You’ll get the following screen if you haven’t created an API key earlier:

Google AI Studio Create API Key button

Click Create API key. You’ll get the Create API Key dialog as shown below:

Google AI Studio Create API Key for new project dialog

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:

  1. User messages
  2. Replies from the model
  3. 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 the temperature 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:

  1. Start a new chat with the startChat method.
  2. Specify the history argument as a list of messages.
  3. 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.