API Gemini Live

Per le applicazioni che richiedono il supporto vocale in tempo reale e a bassa latenza, come chatbot o interazioni con agenti, l'API Gemini Live fornisce un modo ottimizzato per trasmettere in streaming sia l'input che l'output per un modello Gemini. Utilizzando Firebase AI Logic, puoi chiamare l'API Gemini Live direttamente dalla tua app Android senza la necessità di un'integrazione backend. Questa guida mostra come utilizzare l'API Gemini Live nella tua app per Android con Firebase AI Logic.

Inizia

Prima di iniziare, assicurati che la tua app abbia come target il livello API 21 o versioni successive.

Se non l'hai ancora fatto, configura un progetto Firebase e connetti la tua app a Firebase. Per maggiori dettagli, consulta la documentazione di Firebase AI Logic.

Configurare il progetto Android

Aggiungi la dipendenza della libreria Firebase AI Logic al file build.gradle.kts o build.gradle a livello di app. Utilizza la distinta base di Firebase per Android per gestire le versioni delle librerie.

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

Dopo aver aggiunto la dipendenza, sincronizza il tuo progetto Android con Gradle.

Integra Firebase AI Logic e inizializza un modello generativo

Aggiungi l'autorizzazione RECORD_AUDIO al file AndroidManifest.xml della tua applicazione:

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

Inizializza il servizio di backend dell'API Gemini Developer e accedi a LiveModel. Utilizza un modello che supporti l'API Live, come gemini-2.0-flash-live-preview-04-09. Consulta la documentazione di Firebase per i modelli disponibili.

Per specificare una voce, imposta il nome della voce all'interno dell'oggetto speechConfig come parte della configurazione del modello. Se non specifichi una voce, il valore predefinito è 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
);

Puoi definire facoltativamente un personaggio o un ruolo che il modello interpreta impostando un'istruzione di 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
);

Puoi specializzare ulteriormente la conversazione con il modello utilizzando le istruzioni di sistema per fornire un contesto specifico per la tua app (ad esempio, la cronologia dell'attività in-app dell'utente).

Inizializzare una sessione dell'API Live

Dopo aver creato l'istanza LiveModel, chiama model.connect() per creare un oggetto LiveSession e stabilire una connessione persistente con il modello con streaming a bassa latenza. LiveSession ti consente di interagire con il modello avviando e interrompendo la sessione vocale, nonché inviando e ricevendo messaggi di testo.

Puoi quindi chiamare startAudioConversation() per iniziare la conversazione con il modello:

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);

Inoltre, nelle conversazioni con il modello, tieni presente che non gestisce le interruzioni. Abbiamo intenzione di aggiungerla in futuro.

Puoi anche utilizzare l'API Gemini Live per generare audio in streaming da testo e generare testo da audio in streaming. Tieni presente che l'API Live è bidirezionale, quindi utilizzi la stessa connessione per inviare e ricevere contenuti. In futuro, potrai anche inviare immagini e un live streaming video al modello.

Chiamata di funzioni: connetti l'API Gemini Live alla tua app

Per fare un ulteriore passo avanti, puoi anche consentire al modello di interagire direttamente con la logica della tua app utilizzando la chiamata di funzioni.

La chiamata di funzione (o chiamata di strumento) è una funzionalità delle implementazioni di AI generativa che consente al modello di chiamare le funzioni di propria iniziativa per eseguire azioni. Se la funzione ha un output, il modello lo aggiunge al contesto e lo utilizza per le generazioni successive.

Diagramma che illustra come l&#39;API Gemini Live consente a un prompt utente
       di essere interpretato da un modello, attivando una funzione predefinita con
       argomenti pertinenti in un&#39;app per Android, che poi riceve una risposta di conferma
       dal modello.
Figura 1: diagramma che illustra come l'API Gemini Live consente a un prompt dell'utente di essere interpretato da un modello, attivando una funzione predefinita con argomenti pertinenti in un'app per Android, che poi riceve una risposta di conferma dal modello.

Per implementare le chiamate di funzione nella tua app, inizia creando un oggetto FunctionDeclaration per ogni funzione che vuoi esporre al modello.

Ad esempio, per esporre a Gemini una funzione addList che aggiunge una stringa a un elenco di stringhe, inizia creando una variabile FunctionDeclaration con un nome e una breve descrizione in inglese semplice della funzione e del relativo parametro:

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()
);

Quindi, passa questo FunctionDeclaration come Tool al modello quando lo istanzi:

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
        );

Infine, implementa una funzione di gestione per gestire la chiamata allo strumento effettuata dal modello e restituire la risposta. Questa funzione del gestore fornita a LiveSession quando chiami startAudioConversation, accetta un parametro FunctionCallPart e restituisce 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());

Passaggi successivi