API para desarrolladores de Gemini

Para acceder a los modelos de Gemini Pro y Flash, recomendamos a los desarrolladores de Android que usen la API de Gemini Developer con Firebase AI Logic. Te permite comenzar sin necesidad de una tarjeta de crédito y ofrece un nivel gratuito generoso. Una vez que valides tu integración con una pequeña base de usuarios, puedes cambiar al nivel pagado para aumentar la escala.

Ilustración de una app para Android que contiene un SDK de Firebase Android. Una flecha apunta del SDK a Firebase dentro de un entorno de Cloud. Desde Firebase, otra flecha apunta a la API de Gemini Developer, que está conectada a Gemini Pro y Flash, también dentro de la nube.
Figura 1: Arquitectura de integración de Firebase AI Logic para acceder a la API de Gemini Developer.

Cómo comenzar

Antes de interactuar con la API de Gemini directamente desde tu app, primero deberás hacer algunas cosas, como familiarizarte con las instrucciones y configurar Firebase y tu app para usar el SDK.

Experimenta con instrucciones

Experimentar con instrucciones puede ayudarte a encontrar la mejor redacción, el mejor contenido y el mejor formato para tu app para Android. Google AI Studio es un IDE que puedes usar para crear prototipos y diseñar instrucciones para los casos de uso de tu app.

Crear la instrucción adecuada para tu caso de uso es más arte que ciencia, por lo que la experimentación es fundamental. Puedes obtener más información sobre las instrucciones en la documentación de Firebase.

Cuando estés conforme con tu instrucción, haz clic en el botón "<>" para obtener fragmentos de código que puedes agregar a tu código.

Configura un proyecto de Firebase y conecta tu app a Firebase

Cuando esté todo listo para llamar a la API desde tu app, sigue las instrucciones del "Paso 1" de la guía de introducción a Firebase AI Logic para configurar Firebase y el SDK en tu app.

Agrega la dependencia de Gradle

Agrega la siguiente dependencia de Gradle al módulo de tu app:

Kotlin

dependencies {
  // ... other androidx dependencies

  // Import the BoM for the Firebase platform
  implementation(platform("com.google.firebase:firebase-bom:34.2.0"))

  // Add the dependency for the Firebase AI Logic library When using the BoM,
  // you don't specify versions in Firebase library dependencies
  implementation("com.google.firebase:firebase-ai")
}

Java

dependencies {
  // Import the BoM for the Firebase platform
  implementation(platform("com.google.firebase:34.2.0"))

  // Add the dependency for the Firebase AI Logic library When using the BoM,
  // you don't specify versions in Firebase library dependencies
  implementation("com.google.firebase:firebase-ai")

  // 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")
}

Inicializa el modelo generativo

Comienza por crear una instancia de GenerativeModel y especificar el nombre del modelo:

Kotlin

val model = Firebase.ai(backend = GenerativeBackend.googleAI())
                        .generativeModel("gemini-2.5-flash")

Java

GenerativeModel firebaseAI = FirebaseAI.getInstance(GenerativeBackend.googleAI())
        .generativeModel("gemini-2.5-flash");

GenerativeModelFutures model = GenerativeModelFutures.from(firebaseAI);

Obtén más información sobre los modelos disponibles para usar con la API de Gemini Developer. También puedes obtener más información para configurar los parámetros del modelo.

Interactúa con la API de Gemini Developer desde tu app

Ahora que configuraste Firebase y tu app para usar el SDK, puedes interactuar con la API de Gemini Developer desde tu app.

Generar texto

Para generar una respuesta de texto, llama a generateContent() con tu instrucción.

Kotlin

scope.launch {
  val response = model.generateContent("Write a story about a magic backpack.")
}

Java

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

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

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

Genera texto a partir de imágenes y otro contenido multimedia

También puedes generar texto a partir de una instrucción que incluya texto, imágenes o algún otro contenido multimedia. Cuando llamas a generateContent(), puedes pasar el contenido multimedia como datos intercalados.

Por ejemplo, para usar un mapa de bits, usa el tipo de contenido image:

Kotlin

scope.launch {
  val response = model.generateContent(
    content {
      image(bitmap)
      text("what is the object in the picture?")
    }
  )
}

Java

Content content = new Content.Builder()
        .addImage(bitmap)
        .addText("what is the object in the picture?")
        .build();

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

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

Para pasar un archivo de audio, usa el tipo de contenido inlineData:

Kotlin

val contentResolver = applicationContext.contentResolver
val inputStream = contentResolver.openInputStream(audioUri).use { stream ->
    stream?.let {
        val bytes = stream.readBytes()

        val prompt = content {
            inlineData(bytes, "audio/mpeg")  // Specify the appropriate audio MIME type
            text("Transcribe this audio recording.")
        }

        val response = model.generateContent(prompt)
    }
}

Java

ContentResolver resolver = getApplicationContext().getContentResolver();

try (InputStream stream = resolver.openInputStream(audioUri)) {
    File audioFile = new File(new URI(audioUri.toString()));
    int audioSize = (int) audioFile.length();
    byte audioBytes = new byte[audioSize];
    if (stream != null) {
        stream.read(audioBytes, 0, audioBytes.length);
        stream.close();

        // Provide a prompt that includes audio specified earlier and text
        Content prompt = new Content.Builder()
              .addInlineData(audioBytes, "audio/mpeg")  // Specify the appropriate audio MIME type
              .addText("Transcribe what's said in this audio recording.")
              .build();

        // To generate text output, call `generateContent` with the prompt
        ListenableFuture<GenerateContentResponse> response = model.generateContent(prompt);
        Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
            @Override
            public void onSuccess(GenerateContentResponse result) {
                String text = result.getText();
                Log.d(TAG, (text == null) ? "" : text);
            }
            @Override
            public void onFailure(Throwable t) {
                Log.e(TAG, "Failed to generate a response", t);
            }
        }, executor);
    } else {
        Log.e(TAG, "Error getting input stream for file.");
        // Handle the error appropriately
    }
} catch (IOException e) {
    Log.e(TAG, "Failed to read the audio file", e);
} catch (URISyntaxException e) {
    Log.e(TAG, "Invalid audio file", e);
}

Para proporcionar un archivo de video, sigue usando el tipo de contenido inlineData:

Kotlin

val contentResolver = applicationContext.contentResolver
contentResolver.openInputStream(videoUri).use { stream ->
  stream?.let {
    val bytes = stream.readBytes()

    val prompt = content {
        inlineData(bytes, "video/mp4")  // Specify the appropriate video MIME type
        text("Describe the content of this video")
    }

    val response = model.generateContent(prompt)
  }
}

Java

ContentResolver resolver = getApplicationContext().getContentResolver();

try (InputStream stream = resolver.openInputStream(videoUri)) {
    File videoFile = new File(new URI(videoUri.toString()));
    int videoSize = (int) videoFile.length();
    byte[] videoBytes = new byte[videoSize];
    if (stream != null) {
        stream.read(videoBytes, 0, videoBytes.length);
        stream.close();

        // Provide a prompt that includes video specified earlier and text
        Content prompt = new Content.Builder()
                .addInlineData(videoBytes, "video/mp4")
                .addText("Describe the content of this video")
                .build();

        // To generate text output, call generateContent with the prompt
        ListenableFuture<GenerateContentResponse> response = model.generateContent(prompt);
        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);
    }
} catch (IOException e) {
    e.printStackTrace();
} catch (URISyntaxException e) {
    e.printStackTrace();
}

De manera similar, también puedes pasar documentos PDF (application/pdf) y de texto sin formato (text/plain) pasando su respectivo tipo de MIME como parámetro.

Chat de varios turnos

También puedes admitir conversaciones de varios turnos. Inicializa un chat con la función startChat(). De manera opcional, puedes proporcionar al modelo un historial de mensajes. Luego, llama a la función sendMessage() para enviar mensajes de chat.

Kotlin

val chat = model.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?")   }
    )
)

scope.launch {
   val response = chat.sendMessage("How many paws are in my house?")
}

Java

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.Builder messageBuilder = new Content.Builder();
messageBuilder.setRole("user");
messageBuilder.addText("How many paws are in my house?");

Content message = messageBuilder.build();

// Send the message
ListenableFuture<GenerateContentResponse> response = chat.sendMessage(message);
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);

Generar imagen

El modelo de Gemini 2.5 Flash Image (también conocido como Nano Banana) puede generar y editar imágenes aprovechando el conocimiento del mundo y el razonamiento. Genera imágenes pertinentes según el contexto y combina o intercala sin problemas las imágenes y el texto resultantes. También puede generar imágenes precisas con secuencias de texto largas y admite la edición de imágenes conversacionales sin perder el contexto.

Como alternativa a Gemini, puedes usar los modelos de Imagen, en especial para la generación de imágenes de alta calidad que requieren fotorrealismo, detalles artísticos o estilos específicos. Sin embargo, para la mayoría de los casos de uso del cliente en apps para Android, Gemini será más que suficiente.

En esta guía, se describe cómo usar el modelo de imagen Gemini 2.5 Flash con el SDK de Firebase AI Logic para Android. Para obtener más detalles sobre la generación de imágenes con Gemini, consulta la documentación de Genera imágenes con Gemini en Firebase. Si te interesa usar los modelos de Imagen, consulta la documentación.

Google AI Studio muestra las funciones de generación de imágenes.
Figura 1: Usa Google AI Studio para definir mejor tus instrucciones de generación de imágenes

Inicializa el modelo generativo

Crea una instancia de GenerativeModel y especifica el nombre del modelo gemini-2.5-flash-image-preview. Verifica que hayas configurado responseModalities para que incluya TEXT y IMAGE.

Kotlin

val model = Firebase.ai(backend = GenerativeBackend.googleAI()).generativeModel(
    modelName = "gemini-2.5-flash-image-preview",
    // Configure the model to respond with text and images (required)
    generationConfig = generationConfig {
        responseModalities = listOf(ResponseModality.TEXT,
        ResponseModality.IMAGE)
    }
)

Java

GenerativeModel ai = FirebaseAI.getInstance(GenerativeBackend.googleAI()).generativeModel(
    "gemini-2.5-flash-image-preview",
    // Configure the model to respond with text and images (required)
    new GenerationConfig.Builder()
        .setResponseModalities(Arrays.asList(ResponseModality.TEXT, ResponseModality.IMAGE))
        .build()
);
GenerativeModelFutures model = GenerativeModelFutures.from(ai);

Genera imágenes (entrada de solo texto)

Puedes indicarle a un modelo de Gemini que genere imágenes proporcionando una instrucción solo de texto:

Kotlin

// Provide a text prompt instructing the model to generate an image
val prompt = "A hyper realistic picture of a t-rex with a blue bag pack roaming a pre-historic forest."
// To generate image output, call `generateContent` with the text input
val generatedImageAsBitmap = model.generateContent(prompt)
.candidates.first().content.parts.filterIsInstance<ImagePart>()
.firstOrNull()?.image

Java

// Provide a text prompt instructing the model to generate an image
Content prompt = new Content.Builder()
    .addText("Generate an image of the Eiffel Tower with fireworks in the background.")
    .build();
// To generate an image, call `generateContent` with the text input
ListenableFuture<GenerateContentResponse> response = model.generateContent(prompt);
Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
    @Override
    public void onSuccess(GenerateContentResponse result) {
        // iterate over all the parts in the first candidate in the result object
        for (Part part : result.getCandidates().get(0).getContent().getParts()) {
            if (part instanceof ImagePart) {
                ImagePart imagePart = (ImagePart) part;
                // The returned image as a bitmap
                Bitmap generatedImageAsBitmap = imagePart.getImage();
                break;
            }
        }
    }
    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

Edita imágenes (entrada de texto y de imagen)

Puedes pedirle a un modelo de Gemini que edite imágenes existentes proporcionando texto y una o más imágenes en tu instrucción:

Kotlin

// Provide an image for the model to edit
val bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.scones)
// Provide a text prompt instructing the model to edit the image
val prompt = content {
    image(bitmap)
    text("Edit this image to make it look like a cartoon")
}
// To edit the image, call `generateContent` with the prompt (image and text input)
val generatedImageAsBitmap = model.generateContent(prompt)
    .candidates.first().content.parts.filterIsInstance<ImagePart>().firstOrNull()?.image
// Handle the generated text and image

Java

// Provide an image for the model to edit
Bitmap bitmap = BitmapFactory.decodeResource(resources, R.drawable.scones);
// Provide a text prompt instructing the model to edit the image
Content promptcontent = new Content.Builder()
    .addImage(bitmap)
    .addText("Edit this image to make it look like a cartoon")
    .build();
// To edit the image, call `generateContent` with the prompt (image and text input)
ListenableFuture<GenerateContentResponse> response = model.generateContent(promptcontent);
Futures.addCallback(response, new FutureCallback<GenerateContentResponse>() {
    @Override
    public void onSuccess(GenerateContentResponse result) {
        // iterate over all the parts in the first candidate in the result object
        for (Part part : result.getCandidates().get(0).getContent().getParts()) {
            if (part instanceof ImagePart) {
                ImagePart imagePart = (ImagePart) part;
                Bitmap generatedImageAsBitmap = imagePart.getImage();
                break;
            }
        }
    }
    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

Itera y edita imágenes a través de un chat de varios turnos

Para un enfoque conversacional de la edición de imágenes, puedes usar el chat de varios turnos. Esto permite que se realicen solicitudes de seguimiento para definir mejor las ediciones sin necesidad de volver a enviar la imagen original.

Primero, inicializa un chat con startChat() y, de manera opcional, proporciona un historial de mensajes. Luego, usa sendMessage() para los mensajes posteriores:

Kotlin

// Provide an image for the model to edit
val bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.scones)
// Create the initial prompt instructing the model to edit the image
val prompt = content {
    image(bitmap)
    text("Edit this image to make it look like a cartoon")
}
// Initialize the chat
val chat = model.startChat()
// To generate an initial response, send a user message with the image and text prompt
var response = chat.sendMessage(prompt)
// Inspect the returned image
var generatedImageAsBitmap = response
    .candidates.first().content.parts.filterIsInstance<ImagePart>().firstOrNull()?.image
// Follow up requests do not need to specify the image again
response = chat.sendMessage("But make it old-school line drawing style")
generatedImageAsBitmap = response
    .candidates.first().content.parts.filterIsInstance<ImagePart>().firstOrNull()?.image

Java

// Provide an image for the model to edit
Bitmap bitmap = BitmapFactory.decodeResource(resources, R.drawable.scones);
// Initialize the chat
ChatFutures chat = model.startChat();
// Create the initial prompt instructing the model to edit the image
Content prompt = new Content.Builder()
    .setRole("user")
    .addImage(bitmap)
    .addText("Edit this image to make it look like a cartoon")
    .build();
// To generate an initial response, send a user message with the image and text prompt
ListenableFuture<GenerateContentResponse> response = chat.sendMessage(prompt);
// Extract the image from the initial response
ListenableFuture<@Nullable Bitmap> initialRequest = Futures.transform(response,
    result -> {
        for (Part part : result.getCandidates().get(0).getContent().getParts()) {
            if (part instanceof ImagePart) {
                ImagePart imagePart = (ImagePart) part;
                return imagePart.getImage();
            }
        }
        return null;
    }, executor);
// Follow up requests do not need to specify the image again
ListenableFuture<GenerateContentResponse> modelResponseFuture = Futures.transformAsync(
    initialRequest,
    generatedImage -> {
        Content followUpPrompt = new Content.Builder()
            .addText("But make it old-school line drawing style")
            .build();
        return chat.sendMessage(followUpPrompt);
    }, executor);
// Add a final callback to check the reworked image
Futures.addCallback(modelResponseFuture, new FutureCallback<GenerateContentResponse>() {
    @Override
    public void onSuccess(GenerateContentResponse result) {
        for (Part part : result.getCandidates().get(0).getContent().getParts()) {
            if (part instanceof ImagePart) {
                ImagePart imagePart = (ImagePart) part;
                Bitmap generatedImageAsBitmap = imagePart.getImage();
                break;
            }
        }
    }
    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executor);

Prácticas recomendadas y limitaciones

  • Formato de salida: Las imágenes se generan como PNG con una dimensión máxima de 1,024 px.
  • Tipos de entrada: El modelo no admite entradas de audio ni video para la generación de imágenes.
  • Idiomas admitidos: Para obtener el mejor rendimiento, usa los siguientes idiomas: inglés (en), español (México; es-mx), japonés (ja-jp), chino simplificado (zh-cn) y hindi (hi-in).
  • Problemas de generación:
    • Es posible que la generación de imágenes no siempre se active, lo que a veces genera resultados solo de texto. Intenta pedir resultados de imágenes de forma explícita (p.ej., "genera una imagen", "proporciona imágenes a medida que avanzas", "actualiza la imagen").
    • Es posible que el modelo deje de generar contenido a mitad de la respuesta. Vuelve a intentarlo o usa otra instrucción.
    • El modelo puede generar texto como una imagen. Intenta pedir resultados de texto de forma explícita (p.ej., "Genera texto narrativo junto con ilustraciones").

Consulta la documentación de Firebase para obtener más detalles.

Próximos pasos