Gemini Live API

W przypadku aplikacji, które wymagają obsługi głosu w czasie rzeczywistym i z niskim opóźnieniem, takich jak chatboty czy interakcje z agentem, interfejs Gemini Live API zapewnia zoptymalizowany sposób przesyłania strumieniowego danych wejściowych i wyjściowych dla modelu Gemini. Korzystając z Firebase AI Logic, możesz wywoływać interfejs Gemini Live API bezpośrednio z aplikacji na Androida bez konieczności integracji z backendem. Ten przewodnik pokazuje, jak używać interfejsu Gemini Live API w aplikacji na Androida z Firebase AI Logic.

Rozpocznij

Zanim zaczniesz, upewnij się, że aplikacja jest kierowana na interfejs API na poziomie 21 lub wyższym.

Jeśli jeszcze tego nie zrobisz, skonfiguruj projekt Firebase i połącz aplikację z Firebase. Szczegółowe informacje znajdziesz w dokumentacji Firebase AI Logic.

Konfigurowanie projektu na Androida

Dodaj zależność biblioteki Firebase AI Logic do pliku na poziomie aplikacji build.gradle.kts lub build.gradle. Do zarządzania wersjami bibliotek używaj Firebase Android BoM.

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

Po dodaniu zależności zsynchronizuj projekt Androida z Gradle.

Integracja Firebase AI Logic i inicjowanie modelu generatywnego

Dodaj uprawnienie RECORD_AUDIO do pliku AndroidManifest.xml aplikacji:

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

Zainicjuj usługę backendu Gemini Developer API i uzyskaj dostęp do LiveModel. Użyj modelu, który obsługuje interfejs Live API, np. gemini-2.0-flash-live-preview-04-09. Więcej informacji o dostępnych modelach znajdziesz w dokumentacji Firebase.

Aby określić głos, ustaw nazwę głosu w obiekcie speechConfig w ramach konfiguracji modelu. Jeśli nie określisz głosu, zostanie użyty domyślny głos 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
);

Opcjonalnie możesz zdefiniować personę lub rolę, jaką ma odgrywać model, ustawiając instrukcję systemową:

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

Możesz jeszcze bardziej dostosować rozmowę z modelem, używając instrukcji systemowych, aby podać kontekst specyficzny dla Twojej aplikacji (np. historię aktywności użytkownika w aplikacji).

Inicjowanie sesji Live API

Po utworzeniu instancji LiveModel wywołaj model.connect(), aby utworzyć obiekt LiveSession i nawiązać trwałe połączenie z modelem za pomocą strumieniowania o niskim opóźnieniu. LiveSession umożliwia interakcję z modelem przez rozpoczęcie i zakończenie sesji głosowej, a także wysyłanie i odbieranie tekstu.

Następnie możesz wywołać funkcję startAudioConversation(), aby rozpocząć rozmowę z modelem:

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

Pamiętaj też, że w rozmowach z modelem nie obsługuje on przerywania. W przyszłości planujemy dodać tę funkcję.

Możesz też użyć interfejsu Gemini Live API, aby generować strumieniowy dźwięk na podstawie tekstugenerować tekst na podstawie strumieniowego dźwięku. Pamiętaj, że interfejs Live API jest dwukierunkowy, więc możesz używać tego samego połączenia do wysyłania i odbierania treści. W przyszłości będzie można też przesyłać do modelu obrazy i transmisje wideo na żywo.

Wywoływanie funkcji: łączenie interfejsu Gemini Live API z aplikacją

Możesz też pójść o krok dalej i umożliwić modelowi bezpośrednią interakcję z logiką aplikacji za pomocą wywoływania funkcji.

Wywoływanie funkcji (lub wywoływanie narzędzi) to funkcja implementacji generatywnej AI, która umożliwia modelowi samodzielne wywoływanie funkcji w celu wykonywania działań. Jeśli funkcja ma dane wyjściowe, model dodaje je do kontekstu i wykorzystuje w kolejnych generacjach.

Diagram ilustrujący, jak interfejs Gemini Live API umożliwia interpretację promptu użytkownika przez model, co wywołuje predefiniowaną funkcję z odpowiednimi argumentami w aplikacji na Androida, która następnie otrzymuje od modelu odpowiedź z potwierdzeniem.
Ilustracja 1. Diagram ilustrujący, jak interfejs Gemini Live API umożliwia interpretację promptu użytkownika przez model, co wywołuje predefiniowaną funkcję z odpowiednimi argumentami w aplikacji na Androida, która następnie otrzymuje odpowiedź potwierdzającą z modelu.

Aby zaimplementować wywoływanie funkcji w aplikacji, zacznij od utworzenia obiektu FunctionDeclaration dla każdej funkcji, którą chcesz udostępnić modelowi.

Aby na przykład udostępnić Gemini funkcję addList, która dodaje ciąg tekstowy do listy ciągów tekstowych, zacznij od utworzenia zmiennej FunctionDeclaration z nazwą i krótkim opisem funkcji i jej parametru w języku angielskim:

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

Następnie przekaż ten obiekt FunctionDeclaration jako Tool do modelu podczas jego tworzenia:

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

Na koniec zaimplementuj funkcję obsługi, która będzie obsługiwać wywołanie narzędzia przez model i przekazywać mu odpowiedź. Ta funkcja obsługi przekazywana do funkcji LiveSession podczas wywoływania funkcji startAudioConversation przyjmuje parametr FunctionCallPart i zwraca wartość 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());

Dalsze kroki