Overview
This topic shows you how to get up and running with the PaLM API on Android. This guide assumes you are familiar with using Android Studio to develop your Android apps in Kotlin.
To get started, you'll need to get an API key.
Install the API Client
These instructions will install the PaLM Java API in your local Maven repository so that you can add it as a dependency to your Gradle project.
- Download the google-cloud-ai-generativelanguage-v1beta3-java.tar.gz file.
Extract the files and install them in mavenLocal:
# Extract the files tar -xzvf google-cloud-ai-generativelanguage-v1beta3-java.tar.gz cd google-cloud-ai-generativelanguage-v1beta3-java # Install to mavenLocal ./gradlew publishToMavenLocal
Set up the Android project
In Android Studio, create a new project (if you run into any trouble, see detailed instructions in Create your first Android app).
- Select “Empty Compose Activity” as the template.
- Set a name (e.g. “Palm App”).
- Set a package name (e.g.
com.example.palm.palmapp
). - Choose Minimum SDK 21 or higher.
Open the
AndroidManifest.xml
file and add the following permissions:<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- Add these permissions --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Open the
<project_root>/settings.gradle
file and addmavenLocal()
to therepositories
block withindependencyResolutionManagement
:pluginManagement { // ... } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() // Add this line mavenLocal() } }
Open your Gradle configuration file (
<project_root>/app/build.gradle
). Be sure to exclude theINDEX.LIST
andDEPENDENCIES
files withinpackagingOptions
, and add the necessary libraries to thedependencies
block:// build.gradle // ... android { // ... packagingOptions { resources { excludes += '/META-INF/{AL2.0,LGPL2.1}' excludes += 'META-INF/INDEX.LIST' // Add this line excludes += 'META-INF/DEPENDENCIES' // And this line } } } dependencies { // ... other androidx dependencies // add these dependencies to use Generative AI implementation("com.google.cloud:gapic-google-cloud-ai-generativelanguage-v1beta3-java:0.0.0-SNAPSHOT") implementation("io.grpc:grpc-okhttp:1.53.0") // this one is needed by Android's Jetpack Compose implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1") }
After adding the dependencies, sync your Android project with Gradle files.
Generate Text
Create a new file named MainViewModel.kt
and create a basic ViewModel
. This
is the file where you'll add all the functions to interact with the API.
class MainViewModel : ViewModel() {
// you'll add the functions below to this class
}
Initialize the Text Service Client
Initialize a TextServiceClient
by passing your API Key (supplied through the
PALM_API_KEY
environment variable) as a header to the
TransportChannelProvider
to be used by TextServiceSettings
:
private fun initializeTextServiceClient(
apiKey: String
): TextServiceClient {
// (This is a workaround because GAPIC java libraries don't yet support API key auth)
val transportChannelProvider = InstantiatingGrpcChannelProvider.newBuilder()
.setHeaderProvider(FixedHeaderProvider.create(hashMapOf("x-goog-api-key" System.getenv("PALM_API_KEY"))))
.build()
// Create TextServiceSettings
val settings = TextServiceSettings.newBuilder()
.setTransportChannelProvider(transportChannelProvider)
.setCredentialsProvider(FixedCredentialsProvider.create(null))
.build()
// Initialize a TextServiceClient
val textServiceClient = TextServiceClient.create(settings)
return textServiceClient
}
Create a Text Prompt
You need to provide a TextPrompt
to the API:
private fun createPrompt(
textContent: String
): TextPrompt {
val textPrompt = TextPrompt.newBuilder()
.setText(textContent)
.build()
return textPrompt
}
Generate Text
Create a GenerateTextRequest
Create a GenerateTextRequest
by passing a model name and prompt to the
GenerateTextRequest.Builder
:
private fun createTextRequest(prompt: TextPrompt): GenerateTextRequest {
return GenerateTextRequest.newBuilder()
.setModel("models/text-bison-001") // Required, which model to use to generate the result
.setPrompt(prompt) // Required
.setTemperature(0.5f) // Optional, controls the randomness of the output
.setCandidateCount(1) // Optional, the number of generated texts to return
.build()
}
Send the request
The API currently only provides blocking synchronous methods, so consider making
this call in a coroutine scope (e.g. viewModelScope
) to suspend its execution:
private fun generateText(
request: GenerateTextRequest
) {
viewModelScope.launch(Dispatchers.IO) {
try {
val response = client.generateText(request)
val returnedText = response.candidatesList.last()
// display the returned text in the UI
} catch (e: Exception) {
// There was an error
}
}
}
Put it all together
In the
MainViewModel
class, create aStateFlow
of generated texts that will be exposed to the UI, and update thegenerateText()
function to emit updates to that flow:class MainViewModel : ViewModel() { // Add the StateFlow private val _output = MutableStateFlow(value = "") val output: StateFlow<String> get() = _output // ... all the functions we created in previous steps private fun generateText( request: GenerateTextRequest ) { viewModelScope.launch(Dispatchers.IO) { try { val response = client.generateText(request) val returnedText = response.candidatesList.last() // display the returned text in the UI _output.update { returnedText.output } } catch (e: Exception) { // There was an error, let's add a new text with the details _output.update { "API Error: ${e.message}" } } } }
Create the
TextServiceClient
, aTextPrompt
and aGenerateTextRequest
to send the request in theMainViewModel
's initializer block. Note that you'll need to pass your own API key below:class MainViewModel : ViewModel() { // state flow declaration omitted for brevity // Add this variable private var client: TextServiceClient init { // Initialize the Text Service Client client = initializeTextServiceClient( apiKey = "<insert your api key>" ) // Create the text prompt val prompt = createPrompt("Repeat after me: one, two") // Send the first request val request = createTextRequest(prompt) generateText(request) } // other functions omitted for brevity }
A sample UI
We have created a sample UI to help you test the API. Open your
MainActivity.kt
file and add the SampleUI
function below:
package com.example.palm.palmapp
// imports at the top of the file
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Button
import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
// ...
@Composable
fun SampleUi(
viewModel: MainViewModel = viewModel()
) {
val (inputText, setInputText) = remember { mutableStateOf("") }
val textOutput: String by viewModel.output.collectAsState()
Column(
modifier = Modifier.padding(all = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = inputText,
onValueChange = setInputText,
label = { Text("Input:") }
)
Button(
onClick = {
viewModel.sendPrompt(inputText)
},
modifier = Modifier.padding(8.dp)
) {
Text("Generate Text")
}
Card(
modifier = Modifier.padding(vertical = 2.dp)
.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(8.dp)
) {
Text(
modifier = Modifier.fillMaxWidth(),
text = textOutput,
style = MaterialTheme.typography.body1
)
}
}
}
}
Call this function from the onCreate
function of your MainActivity
,
replacing the call to Greeting()
inside Surface
:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
PalmAppTheme { // <- this might have a different name in your app
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
SampleUi() // <- Replace Greeting("Android") with this
}
}
}
}
}
Run the app
Hit the ▶️ button to run the app on a physical device or emulator. You should see a UI with an input text field, a "Generate Text" button, and a generated text.