Começar a usar a API Gemini em apps Android (SDK do cliente)

Este tutorial demonstra como acessar a API Gemini diretamente do app Android usando o SDK do cliente da IA do Google para Android. Você pode usar esse SDK do cliente se não quiser trabalhar diretamente com APIs REST ou código do lado do servidor (como Python) para acessar modelos do Gemini no seu app Android.

Neste tutorial, você aprenderá a fazer o seguinte:

Além disso, este tutorial contém seções sobre casos de uso avançados (como contagem de tokens), bem como opções para controlar a geração de conteúdo.

Considere acessar o Gemini no dispositivo

O SDK do cliente para Android descrito neste tutorial permite acessar os modelos Genmini Pro que são executados nos servidores do Google. Para casos de uso que envolvem o processamento de dados confidenciais, a disponibilidade off-line ou a economia de custos para fluxos de usuários usados com frequência, considere acessar o Gemini Nano, que é executado no dispositivo. Para mais detalhes, consulte o tutorial do Android (no dispositivo).

Pré-requisitos

Este tutorial pressupõe que você esteja familiarizado com o uso do Android Studio para desenvolver apps Android.

Para concluir este tutorial, verifique se o ambiente de desenvolvimento e o app Android atendem aos seguintes requisitos:

  • Android Studio (versão mais recente)
  • Seu app Android precisa ser direcionado ao nível 21 da API ou mais recente.

Configurar seu projeto

Antes de chamar a API Gemini, você precisa configurar seu projeto Android, o que inclui configurar sua chave de API, adicionar as dependências do SDK ao projeto Android e inicializar o modelo.

Configurar sua chave de API

Para usar a API Gemini, você precisa de uma chave de API. Se você ainda não tiver uma, crie uma chave no Google AI Studio.

Gerar uma chave de API

Proteger sua chave de API

É altamente recomendável não verificar uma chave de API no sistema de controle de versões. Em vez disso, armazene-a em um arquivo local.properties (localizado no diretório raiz do projeto, mas excluído do controle de versões) e use o plug-in Secrets Gradle para Android (link em inglês) para ler sua chave de API como uma variável de configuração do build.

Kotlin

// Access your API key as a Build Configuration variable
val apiKey = BuildConfig.apiKey

Java

// Access your API key as a Build Configuration variable
String apiKey = BuildConfig.apiKey;

Todos os snippets neste tutorial usam essa prática recomendada. Além disso, se você quiser conferir a implementação do plug-in Secrets Gradle, consulte o app de exemplo (link em inglês) desse SDK ou use a prévia mais recente do Android Studio Iguana, que tem um modelo da Gemini API Starter (que inclui o arquivo local.properties para começar).

Adicionar a dependência do SDK ao seu projeto

  1. No arquivo de configuração Gradle do módulo (nível do app) (como <project>/<app-module>/build.gradle.kts), adicione a dependência do SDK da IA do Google para Android:

    Kotlin

    dependencies {
      // ... other androidx dependencies
    
      // add the dependency for the Google AI client SDK for Android
      implementation("com.google.ai.client.generativeai:generativeai:0.3.0")
    }
    

    Java

    Para Java, é preciso adicionar mais duas bibliotecas.

    dependencies {
        // ... other androidx dependencies
    
        // add the dependency for the Google AI client SDK for Android
        implementation("com.google.ai.client.generativeai:generativeai:0.3.0")
    
        // Required for one-shot operations (to use `ListenableFuture` from Guava Android)
        implementation("com.google.guava:guava:31.0.1-android")
    
        // Required for streaming operations (to use `Publisher` from Reactive Streams)
        implementation("org.reactivestreams:reactive-streams:1.0.4")
    }
    
  2. Sincronize seu projeto do Android com os arquivos Gradle.

Inicializar o modelo generativo

Antes de fazer qualquer chamada de API, você precisa inicializar o objeto GenerativeModel:

Kotlin

val generativeModel = GenerativeModel(
    // Use a model that's applicable for your use case (see "Implement basic use cases" below)
    modelName = "MODEL_NAME",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

Java

Para Java, também é necessário inicializar o objeto GenerativeModelFutures.

// Use a model that's applicable for your use case (see "Implement basic use cases" below)
GenerativeModel gm = new GenerativeModel(/* modelName */ "MODEL_NAME",
// Access your API key as a Build Configuration variable (see "Set up your API key" above)
    /* apiKey */ BuildConfig.apiKey);

// Use the GenerativeModelFutures Java compatibility layer which offers
// support for ListenableFuture and Publisher APIs
GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Ao especificar um modelo, observe o seguinte:

  • Use um modelo específico para seu caso de uso (por exemplo, gemini-pro-vision é para entrada multimodal). Neste guia, as instruções para cada implementação listam o modelo recomendado para cada caso de uso.

Implemente casos de uso comuns

Agora que o projeto está configurado, é possível explorar o uso da API Gemini para implementar diferentes casos de uso:

Gerar texto com base apenas em entradas de texto

Quando a entrada do comando incluir apenas texto, use o modelo gemini-pro com generateContent para gerar a saída de texto:

Kotlin

Observe que generateContent() é uma função de suspensão e precisa ser chamado em um escopo de corrotina. Se você não conhece as corrotinas, leia Corrotinas do Kotlin no Android.

val generativeModel = GenerativeModel(
    // For text-only input, use the gemini-pro model
    modelName = "gemini-pro",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

val prompt = "Write a story about a magic backpack."
val response = generativeModel.generateContent(prompt)
print(response.text)

Java

Observe que generateContent() retorna um ListenableFuture. Se você não conhece essa API, consulte a documentação do Android sobre Como usar um ListenableFuture.

// For text-only input, use the gemini-pro model
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-pro",
// Access your API key as a Build Configuration variable (see "Set up your API key" above)
    /* apiKey */ BuildConfig.apiKey);
GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Content content = new Content.Builder()
    .addText("Write a story about a magic backpack.")
    .build();

Executor executor = // ...

ListenableFuture<GenerateContentResponse> response = model.generateContent(content);
Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
    @Override
    public void onSuccess(GenerateContentResponse result) {
        String resultText = result.getText();
        System.out.println(resultText);
    }

    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

Gerar texto com base em entradas de texto e imagem (multimodal)

O Gemini fornece um modelo multimodal (gemini-pro-vision), para que você possa inserir texto e imagens. Leia os requisitos de imagem para solicitações.

Quando a entrada da solicitação incluir texto e imagens, use o modelo gemini-pro-vision com generateContent para gerar a saída de texto:

Kotlin

Observe que generateContent() é uma função de suspensão e precisa ser chamado em um escopo de corrotina. Se você não conhece as corrotinas, leia Corrotinas do Kotlin no Android.

val generativeModel = GenerativeModel(
    // For text-and-images input (multimodal), use the gemini-pro-vision model
    modelName = "gemini-pro-vision",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

val image1: Bitmap = // ...
val image2: Bitmap = // ...

val inputContent = content {
    image(image1)
    image(image2)
    text("What's different between these pictures?")
}

val response = generativeModel.generateContent(inputContent)
print(response.text)

Java

Observe que generateContent() retorna um ListenableFuture. Se você não conhece essa API, consulte a documentação do Android sobre Como usar um ListenableFuture.

// For text-and-images input (multimodal), use the gemini-pro-vision model
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-pro-vision",
// Access your API key as a Build Configuration variable (see "Set up your API key" above)
    /* apiKey */ BuildConfig.apiKey);
GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Bitmap image1 = // ...
Bitmap image2 = // ...

Content content = new Content.Builder()
    .addText("What's different between these pictures?")
    .addImage(image1)
    .addImage(image2)
    .build();

Executor executor = // ...

ListenableFuture<GenerateContentResponse> response = model.generateContent(content);
Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
    @Override
    public void onSuccess(GenerateContentResponse result) {
        String resultText = result.getText();
        System.out.println(resultText);
    }

    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

Criar conversas com vários turnos (chat)

Com o Gemini, é possível criar conversas livres em vários turnos. O SDK simplifica o processo gerenciando o estado da conversa. Portanto, ao contrário de generateContent, você não precisa armazenar o histórico da conversa.

Para criar uma conversa de várias interações (como um chat), use o modelo gemini-pro e inicialize o chat chamando startChat(). Em seguida, use sendMessage() para enviar uma mensagem de novo usuário, que também vai anexar a mensagem e a resposta ao histórico de chat.

Há duas opções possíveis de role associadas ao conteúdo em uma conversa:

  • user: o papel que fornece as solicitações. Esse valor é o padrão para chamadas sendMessage.

  • model: o papel que fornece as respostas. Esse papel pode ser usado ao chamar startChat() com history.

Kotlin

Observe que generateContent() é uma função de suspensão e precisa ser chamado em um escopo de corrotina. Se você não conhece as corrotinas, leia Corrotinas do Kotlin no Android.

val generativeModel = GenerativeModel(
    // For text-only input, use the gemini-pro model
    modelName = "gemini-pro",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

val chat = generativeModel.startChat(
    history = listOf(
        content(role = "user") { text("Hello, I have 2 dogs in my house.") },
        content(role = "model") { text("Great to meet you. What would you like to know?") }
    )
)

chat.sendMessage("How many paws are in my house?")

Java

Observe que generateContent() retorna um ListenableFuture. Se você não conhece essa API, consulte a documentação do Android sobre Como usar um ListenableFuture.

// For text-only input, use the gemini-pro model
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-pro",
// Access your API key as a Build Configuration variable (see "Set up your API key" above)
    /* apiKey */ BuildConfig.apiKey);
GenerativeModelFutures model = GenerativeModelFutures.from(gm);

// (optional) Create previous chat history for context
Content.Builder userContentBuilder = new Content.Builder();
userContentBuilder.setRole("user");
userContentBuilder.addText("Hello, I have 2 dogs in my house.");
Content userContent = userContentBuilder.build();

Content.Builder modelContentBuilder = new Content.Builder();
modelContentBuilder.setRole("model");
modelContentBuilder.addText("Great to meet you. What would you like to know?");
Content modelContent = userContentBuilder.build();

List<Content> history = Arrays.asList(userContent, modelContent);

// Initialize the chat
ChatFutures chat = model.startChat(history);

// Create a new user message
Content userMessage = new Content.Builder()
    .setRole("user")
    .addText("How many paws are in my house?")
    .build();

Executor executor = // ...

// Send the message
ListenableFuture<GenerateContentResponse> response = chat.sendMessage(userMessage);

Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
    @Override
    public void onSuccess(GenerateContentResponse result) {
        String resultText = result.getText();
        System.out.println(resultText);
    }

    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

Use o streaming para interações mais rápidas

Por padrão, o modelo retorna uma resposta depois de concluir todo o processo de geração. Consiga interações mais rápidas não esperando todo o resultado e, em vez disso, use o streaming para lidar com resultados parciais.

O exemplo abaixo mostra como implementar o streaming com generateContentStream para gerar texto usando um comando de entrada de texto e imagem.

Kotlin

Observe que generateContentStream() é uma função de suspensão e precisa ser chamado em um escopo de corrotina. Se você não conhece as corrotinas, leia Corrotinas do Kotlin no Android.

val generativeModel = GenerativeModel(
    // For text-and-image input (multimodal), use the gemini-pro-vision model
    modelName = "gemini-pro-vision",
    // Access your API key as a Build Configuration variable (see "Set up your API key" above)
    apiKey = BuildConfig.apiKey
)

val image1: Bitmap = // ...
val image2: Bitmap = // ...

val inputContent = content {
    image(image1)
    image(image2)
    text("What's the difference between these pictures?")
}

var fullResponse = ""
generativeModel.generateContentStream(inputContent).collect { chunk ->
    print(chunk.text)
    fullResponse += chunk.text
}

Java

Os métodos de streaming do Java nesse SDK retornam um tipo Publisher da biblioteca Reactive Streams.

// For text-and-images input (multimodal), use the gemini-pro-vision model
GenerativeModel gm = new GenerativeModel(/* modelName */ "gemini-pro-vision",
// Access your API key as a Build Configuration variable (see "Set up your API key" above)
    /* apiKey */ BuildConfig.apiKey);
GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Bitmap image1 = // ...
Bitmap image2 = // ...

Content content = new Content.Builder()
    .addText("What's different between these pictures?")
    .addImage(image1)
    .addImage(image2)
    .build();

Publisher<GenerateContentResponse> streamingResponse =
    model.generateContentStream(content);

final String[] fullResponse = {""};

streamingResponse.subscribe(new Subscriber<GenerateContentResponse>() {
    @Override
    public void onNext(GenerateContentResponse generateContentResponse) {
        String chunk = generateContentResponse.getText();
        fullResponse[0] += chunk;
    }

    @Override
    public void onComplete() {
        System.out.println(fullResponse[0]);
    }

    @Override
    public void onError(Throwable t) {
        t.printStackTrace();
    }

    @Override
    public void onSubscribe(Subscription s) { }
});

É possível usar uma abordagem semelhante para casos de uso de chat e entrada somente de texto:

Kotlin

Observe que generateContentStream() é uma função de suspensão e precisa ser chamado em um escopo de corrotina. Se você não conhece as corrotinas, leia Corrotinas do Kotlin no Android.

// Use streaming with text-only input
generativeModel.generateContentStream(inputContent).collect { chunk ->
    print(chunk.text)
}
// Use streaming with multi-turn conversations (like chat)
val chat = generativeModel.startChat()
chat.sendMessageStream(inputContent).collect { chunk ->
    print(chunk.text)
}

Java

Os métodos de streaming do Java nesse SDK retornam um tipo Publisher da biblioteca Reactive Streams.

// Use streaming with text-only input
Publisher<GenerateContentResponse> streamingResponse =
    model.generateContentStream(inputContent);

final String[] fullResponse = {""};

streamingResponse.subscribe(new Subscriber<GenerateContentResponse>() {
    @Override
    public void onNext(GenerateContentResponse generateContentResponse) {
        String chunk = generateContentResponse.getText();
        fullResponse[0] += chunk;
    }

    @Override
    public void onComplete() {
        System.out.println(fullResponse[0]);
    }

    // ... other methods omitted for brevity
});
// Use streaming with multi-turn conversations (like chat)
ChatFutures chat = model.startChat(history);

Publisher<GenerateContentResponse> streamingResponse =
    chat.sendMessageStream(inputContent);

final String[] fullResponse = {""};

streamingResponse.subscribe(new Subscriber<GenerateContentResponse>() {
    @Override
    public void onNext(GenerateContentResponse generateContentResponse) {
        String chunk = generateContentResponse.getText();
        fullResponse[0] += chunk;
    }

    @Override
    public void onComplete() {
        System.out.println(fullResponse[0]);
    }

    // ... other methods omitted for brevity
});

Implemente casos de uso avançados

Os casos de uso comuns descritos na seção anterior deste tutorial ajudam você a se familiarizar com o uso da API Gemini. Esta seção descreve alguns casos de uso que podem ser considerados mais avançados.

Tokens de contagem

Ao usar prompts longos, pode ser útil contar os tokens antes de enviar qualquer conteúdo ao modelo. Os exemplos abaixo mostram como usar countTokens() para vários casos de uso:

Kotlin

Observe que countTokens() é uma função de suspensão e precisa ser chamado em um escopo de corrotina. Se você não conhece as corrotinas, leia Corrotinas do Kotlin no Android.

// For text-only input
val (totalTokens) = generativeModel.countTokens("Write a story about a magic backpack.")

// For text-and-image input (multi-modal)
val multiModalContent = content {
    image(image1)
    image(image2)
    text("What's the difference between these pictures?")
}

val (totalTokens) = generativeModel.countTokens(multiModalContent)

// For multi-turn conversations (like chat)
val history = chat.history
val messageContent = content { text("This is the message I intend to send")}
val (totalTokens) = generativeModel.countTokens(*history.toTypedArray(), messageContent)

Java

Observe que countTokens() retorna um ListenableFuture. Se você não conhece essa API, consulte a documentação do Android sobre Como usar um ListenableFuture.

Content text = new Content.Builder()
    .addText("Write a story about a magic backpack.")
    .build();

Executor executor = // ...

// For text-only input
ListenableFuture<CountTokensResponse> countTokensResponse = model.countTokens(text);

Futures.addCallback(countTokensResponse, new FutureCallback<CountTokensResponse>() {
    @Override
    public void onSuccess(CountTokensResponse result) {
        int totalTokens = result.getTotalTokens();
        System.out.println("TotalTokens = " + totalTokens);
    }

    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

// For text-and-image input
Bitmap image1 = // ...
Bitmap image2 = // ...

Content multiModalContent = new Content.Builder()
    .addImage(image1)
    .addImage(image2)
    .addText("What's different between these pictures?")
    .build();

ListenableFuture<CountTokensResponse> countTokensResponse = model.countTokens(multiModalContent);

// For multi-turn conversations (like chat)
List<Content> history = chat.getChat().getHistory();

Content messageContent = new Content.Builder()
    .addText("This is the message I intend to send")
    .build();

Collections.addAll(history, messageContent);

ListenableFuture<CountTokensResponse> countTokensResponse = model.countTokens(history.toArray(new Content[0]));

Opções para controlar a geração de conteúdo

É possível controlar a geração de conteúdo definindo parâmetros de modelo e usando as configurações de segurança.

Configurar parâmetros do modelo

Cada comando enviado ao modelo inclui valores de parâmetros que controlam como o modelo gera uma resposta. O modelo pode gerar diferentes resultados para diferentes valores de parâmetros. Saiba mais sobre os parâmetros de modelo.

Kotlin

val config = generationConfig {
    temperature = 0.9f
    topK = 16
    topP = 0.1f
    maxOutputTokens = 200
    stopSequences = listOf("red")
}

val generativeModel = GenerativeModel(
    modelName = "MODEL_NAME",
    apiKey = BuildConfig.apiKey,
    generationConfig = config
)

Java

GenerationConfig.Builder configBuilder = new GenerationConfig.Builder();
configBuilder.temperature = 0.9f;
configBuilder.topK = 16;
configBuilder.topP = 0.1f;
configBuilder.maxOutputTokens = 200;
configBuilder.stopSequences = Arrays.asList("red");

GenerationConfig generationConfig = configBuilder.build();

GenerativeModel gm = new GenerativeModel(
    "MODEL_NAME",
    BuildConfig.apiKey,
    generationConfig
);

GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Usar configurações de segurança

Você pode usar as configurações de segurança para ajustar a probabilidade de receber respostas que podem ser consideradas prejudiciais. Por padrão, as configurações de segurança bloqueiam conteúdo com probabilidade média e/ou alta de não ser seguro em todas as dimensões. Saiba mais sobre as Configurações de segurança.

Veja como definir uma configuração de segurança:

Kotlin

val generativeModel = GenerativeModel(
    modelName = "MODEL_NAME",
    apiKey = BuildConfig.apiKey,
    safetySettings = listOf(
        SafetySetting(HarmCategory.HARASSMENT, BlockThreshold.ONLY_HIGH)
    )
)

Java

SafetySetting harassmentSafety = new SafetySetting(HarmCategory.HARASSMENT,
    BlockThreshold.ONLY_HIGH);

GenerativeModel gm = new GenerativeModel(
    "MODEL_NAME",
    BuildConfig.apiKey,
    null, // generation config is optional
    Collections.singletonList(harassmentSafety)
);

GenerativeModelFutures model = GenerativeModelFutures.from(gm);

Também é possível definir mais de uma configuração de segurança:

Kotlin

val harassmentSafety = SafetySetting(HarmCategory.HARASSMENT, BlockThreshold.ONLY_HIGH)

val hateSpeechSafety = SafetySetting(HarmCategory.HATE_SPEECH, BlockThreshold.MEDIUM_AND_ABOVE)

val generativeModel = GenerativeModel(
    modelName = "MODEL_NAME",
    apiKey = BuildConfig.apiKey,
    safetySettings = listOf(harassmentSafety, hateSpeechSafety)
)

Java

SafetySetting harassmentSafety = new SafetySetting(HarmCategory.HARASSMENT,
    BlockThreshold.ONLY_HIGH);

SafetySetting hateSpeechSafety = new SafetySetting(HarmCategory.HATE_SPEECH,
    BlockThreshold.MEDIUM_AND_ABOVE);

GenerativeModel gm = new GenerativeModel(
    "MODEL_NAME",
    BuildConfig.apiKey,
    null, // generation config is optional
    Arrays.asList(harassmentSafety, hateSpeechSafety)
);

GenerativeModelFutures model = GenerativeModelFutures.from(gm);

A seguir

  • Design de prompt é o processo de criação de prompts que extraem a resposta desejada dos modelos de linguagem. Escrever solicitações bem estruturadas é uma parte essencial para garantir respostas precisas e de alta qualidade de um modelo de linguagem. Saiba mais sobre as práticas recomendadas para escrita de comandos.

  • O Gemini oferece diversas variações de modelo para atender às necessidades de diferentes casos de uso, como tipos de entrada e complexidade, implementações para chat ou outras tarefas de linguagem de diálogo e restrições de tamanho. Saiba mais sobre os modelos disponíveis do Gemini.

  • Gemini oferece opções para solicitar aumentos no limite de taxa. O limite de taxa para os modelos Genmini Pro é de 60 solicitações por minuto (RPM).

  • O SDK do cliente para Android descrito neste tutorial permite acessar os modelos Genmini Pro que são executados nos servidores do Google. Para casos de uso que envolvem o processamento de dados confidenciais, a disponibilidade off-line ou a economia de custos para fluxos de usuários usados com frequência, considere acessar o Gemini Nano, que é executado no dispositivo. Para mais detalhes, consulte o tutorial do Android (no dispositivo).