API de Gemini Live

Para las aplicaciones que requieren asistencia por voz en tiempo real y con baja latencia, como los chatbots o las interacciones con agentes, la API de Gemini Live proporciona una forma optimizada de transmitir la entrada y la salida de un modelo de Gemini. Con Firebase AI Logic, puedes llamar a la API de Gemini Live directamente desde tu app para Android sin necesidad de una integración de backend. En esta guía, se muestra cómo usar la API de Gemini Live en tu app para Android con Firebase AI Logic.

Comenzar

Antes de comenzar, asegúrate de que tu app se oriente al nivel de API 21 o superior.

Si aún no lo has hecho, configura un proyecto de Firebase y conecta tu app a Firebase. Para obtener más detalles, consulta la documentación de Firebase AI Logic.

Configura tu proyecto de Android

Agrega la dependencia de la biblioteca de Firebase AI Logic a tu archivo build.gradle.kts o build.gradle a nivel de la app. Usa la BoM de Firebase para Android para administrar las versiones de las bibliotecas.

dependencies {
  // Import the Firebase BoM
  implementation(platform("com.google.firebase:firebase-bom:34.1.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")
}

Después de agregar la dependencia, sincroniza tu proyecto de Android con Gradle.

Integra Firebase AI Logic e inicializa un modelo generativo

Agrega el permiso RECORD_AUDIO al archivo AndroidManifest.xml de tu aplicación:

<uses-permission android:name="android.permission.RECORD_AUDIO" />

Inicializa el servicio de backend de la API para desarrolladores de Gemini y accede a LiveModel. Usa un modelo que admita la API de Live, como gemini-2.0-flash-live-preview-04-09. Consulta la documentación de Firebase para conocer los modelos disponibles.

Para especificar una voz, configura el nombre de la voz dentro del objeto speechConfig como parte de la configuración del modelo. Si no especificas una voz, la predeterminada es Puck.

Kotlin

// Initialize the `LiveModel`
val model = Firebase.ai(backend = GenerativeBackend.googleAI()).liveModel(
       modelName = "gemini-2.0-flash-live-preview-04-09",
       generationConfig = liveGenerationConfig {
          responseModality = ResponseModality.AUDIO
          speechConfig = SpeechConfig(voice= Voice("FENRIR"))
       })

Java

// Initialize the `LiveModel`
LiveGenerativeModel model = FirebaseAI
       .getInstance(GenerativeBackend.googleAI())
       .liveModel(
              "gemini-2.0-flash-live-preview-04-09",
              new LiveGenerationConfig.Builder()
                     .setResponseModality(ResponseModality.AUDIO)
                     .setSpeechConfig(new SpeechConfig(new Voice("FENRIR"))
              ).build(),
        null,
        null
);

De manera opcional, puedes definir un arquetipo o un rol que desempeñe el modelo configurando una instrucción del sistema:

Kotlin

val systemInstruction = content {
            text("You are a helpful assistant, you main role is [...]")}

val model = Firebase.ai(backend = GenerativeBackend.googleAI()).liveModel(
       modelName = "gemini-2.0-flash-live-preview-04-09",
       generationConfig = liveGenerationConfig {
          responseModality = ResponseModality.AUDIO
          speechConfig = SpeechConfig(voice= Voice("FENRIR"))
       },
       systemInstruction = systemInstruction,
)

Java

Content systemInstruction = new Content.Builder()
       .addText("You are a helpful assistant, you main role is [...]")
       .build();

LiveGenerativeModel model = FirebaseAI
       .getInstance(GenerativeBackend.googleAI())
       .liveModel(
              "gemini-2.0-flash-live-preview-04-09",
              new LiveGenerationConfig.Builder()
                     .setResponseModality(ResponseModality.AUDIO)
                     .setSpeechConfig(new SpeechConfig(new Voice("FENRIR"))
              ).build(),
        tools, // null if you don't want to use function calling
        systemInstruction
);

Puedes especializar aún más la conversación con el modelo usando instrucciones del sistema para proporcionar contexto específico de tu app (por ejemplo, el historial de actividad del usuario en la app).

Inicializa una sesión de la API de Live

Una vez que crees la instancia de LiveModel, llama a model.connect() para crear un objeto LiveSession y establecer una conexión persistente con el modelo con transmisión de baja latencia. LiveSession te permite interactuar con el modelo iniciando y deteniendo la sesión de voz, y también enviando y recibiendo texto.

Luego, puedes llamar a startAudioConversation() para iniciar la conversación con el modelo:

Kotlin

val session = model.connect()
session.startAudioConversation()

Java

LiveModelFutures model = LiveModelFutures.from(liveModel);
ListenableFuture<LiveSession> sessionFuture =  model.connect();

Futures.addCallback(sessionFuture, new FutureCallback<LiveSession>() {
    @Override
    public void onSuccess(LiveSession ses) {
         LiveSessionFutures session = LiveSessionFutures.from(ses);
        session.startAudioConversation();
    }
    @Override
    public void onFailure(Throwable t) {
        // Handle exceptions
    }
}, executor);

Además, en tus conversaciones con el modelo, ten en cuenta que no maneja interrupciones. Tenemos la intención de agregar esta función en el futuro.

También puedes usar la API de Gemini Live para generar audio transmitido a partir de texto y generar texto a partir de audio transmitido. Ten en cuenta que la API de Live es bidireccional, por lo que usas la misma conexión para enviar y recibir contenido. Con el tiempo, también podrás enviar imágenes y una transmisión de video en vivo al modelo.

Llamada a función: Conecta la API de Gemini Live a tu app

Para ir un paso más allá, también puedes habilitar el modelo para que interactúe directamente con la lógica de tu app a través de la llamada a función.

Las llamadas a función (o llamadas a herramientas) son una característica de las implementaciones de IA generativa que permite que el modelo llame a funciones por su propia iniciativa para realizar acciones. Si la función tiene un resultado, el modelo lo agrega a su contexto y lo usa para las generaciones posteriores.

Diagrama que ilustra cómo la API de Gemini Live permite que un modelo interprete una instrucción del usuario, lo que activa una función predefinida con argumentos relevantes en una app para Android, que luego recibe una respuesta de confirmación del modelo.
Figura 1: Diagrama que ilustra cómo la API de Gemini Live permite que un modelo interprete una instrucción del usuario, lo que activa una función predefinida con argumentos relevantes en una app para Android, que luego recibe una respuesta de confirmación del modelo.

Para implementar la llamada a función en tu app, comienza por crear un objeto FunctionDeclaration para cada función que quieras exponer al modelo.

Por ejemplo, para exponer una función addList que agrega una cadena a una lista de cadenas a Gemini, comienza por crear una variable FunctionDeclaration con un nombre y una descripción breve en inglés simple de la función y su parámetro:

Kotlin

val itemList = mutableListOf<String>()

fun addList(item: String){
   itemList.add(item)
}

val addListFunctionDeclaration = FunctionDeclaration(
        name = "addList",
        description = "Function adding an item the list",
        parameters = mapOf("item" to Schema.string("A short string
            describing the item to add to the list"))
        )

Java

HashMap<String, Schema> addListParams = new HashMap<String, Schema>(1);

addListParams.put("item", Schema.str("A short string describing the item
    to add to the list"));

FunctionDeclaration addListFunctionDeclaration = new FunctionDeclaration(
    "addList",
    "Function adding an item the list",
    addListParams,
    Collections.emptyList()
);

Luego, pasa este FunctionDeclaration como un Tool al modelo cuando lo instancias:

Kotlin

val addListTool = Tool.functionDeclarations(listOf(addListFunctionDeclaration))

val model = Firebase.ai(backend = GenerativeBackend.googleAI()).liveModel(
       modelName = "gemini-2.0-flash-live-preview-04-09",
       generationConfig = liveGenerationConfig {
          responseModality = ResponseModality.AUDIO
          speechConfig = SpeechConfig(voice= Voice("FENRIR"))
       },
       systemInstruction = systemInstruction,
       tools = listOf(addListTool)
)

Java

LiveGenerativeModel model = FirebaseAI.getInstance(
    GenerativeBackend.googleAI()).liveModel(
        "gemini-2.0-flash-live-preview-04-09",
  new LiveGenerationConfig.Builder()
        .setResponseModalities(ResponseModality.AUDIO)
        .setSpeechConfig(new SpeechConfig(new Voice("FENRIR")))
        .build(),
  List.of(Tool.functionDeclarations(List.of(addListFunctionDeclaration))),
               null,
               systemInstruction
        );

Por último, implementa una función de controlador para controlar la llamada a la herramienta que realiza el modelo y pasarle la respuesta. Esta función de controlador proporcionada a LiveSession cuando llamas a startAudioConversation, toma un parámetro FunctionCallPart y devuelve FunctionResponsePart:

Kotlin

session.startAudioConversation(::functionCallHandler)

// ...

fun functionCallHandler(functionCall: FunctionCallPart): FunctionResponsePart {
    return when (functionCall.name) {
        "addList" -> {
            // Extract function parameter from functionCallPart
            val itemName = functionCall.args["item"]!!.jsonPrimitive.content
            // Call function with parameter
            addList(itemName)
            // Confirm the function call to the model
            val response = JsonObject(
                mapOf(
                    "success" to JsonPrimitive(true),
                    "message" to JsonPrimitive("Item $itemName added to the todo list")
                )
            )
            FunctionResponsePart(functionCall.name, response)
        }
        else -> {
            val response = JsonObject(
                mapOf(
                    "error" to JsonPrimitive("Unknown function: ${functionCall.name}")
                )
            )
            FunctionResponsePart(functionCall.name, response)
        }
    }
}

Java

Futures.addCallback(sessionFuture, new FutureCallback<LiveSessionFutures>() {

    @RequiresPermission(Manifest.permission.RECORD_AUDIO)
    @Override
    @OptIn(markerClass = PublicPreviewAPI.class)
    public void onSuccess(LiveSessionFutures ses) {
        ses.startAudioConversation(::handleFunctionCallFuture);
    }

    @Override
    public void onFailure(Throwable t) {
        // Handle exceptions
    }
}, executor);

// ...

ListenableFuture<JsonObject> handleFunctionCallFuture = Futures.transform(response, result -> {
    for (FunctionCallPart functionCall : result.getFunctionCalls()) {
        if (functionCall.getName().equals("addList")) {
            Map<String, JsonElement> args = functionCall.getArgs();
            String item =
                    JsonElementKt.getContentOrNull(
                            JsonElementKt.getJsonPrimitive(
                                    locationJsonObject.get("item")));
            return addList(item);
        }
    }
    return null;
}, Executors.newSingleThreadExecutor());

Próximos pasos