Gemini Live API

לאפליקציות שדורשות תמיכה קולית בזמן אמת עם השהיה נמוכה, כמו צ'אטבוטים או אינטראקציות עם סוכנים, Gemini Live API מספק דרך אופטימלית להזרמת קלט ופלט עבור מודל Gemini. באמצעות Firebase AI Logic, אפשר לקרוא ל-Gemini Live API ישירות מאפליקציית Android בלי לשלב את ה-API עם קצה העורפי. במדריך הזה מוסבר איך להשתמש ב-Gemini Live API באפליקציה ל-Android עם Firebase AI Logic.

שנתחיל?

לפני שמתחילים, מוודאים שהאפליקציה מטרגטת רמת API 21 ומעלה.

אם עדיין לא עשיתם זאת, אתם צריכים להגדיר פרויקט Firebase ולקשר את האפליקציה ל-Firebase. פרטים נוספים זמינים במסמכי התיעוד בנושא Firebase AI Logic.

הגדרת פרויקט Android

מוסיפים את התלות בספריית Firebase AI Logic לקובץ build.gradle.kts או build.gradle ברמת האפליקציה. משתמשים ב-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")
}

אחרי שמוסיפים את יחסי התלות, מסנכרנים את פרויקט Android עם Gradle.

שילוב של Firebase AI Logic ואתחול של מודל גנרטיבי

מוסיפים את ההרשאה RECORD_AUDIO לקובץ AndroidManifest.xml של האפליקציה:

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

מאתחלים את שירות ה-Backend של Gemini Developer API וניגשים אל LiveModel. משתמשים במודל שתומך ב-Live API, כמו gemini-2.0-flash-live-preview-04-09. בתיעוד של Firebase מפורטים המודלים הזמינים.

כדי לציין קול, מגדירים את שם הקול באובייקט speechConfig כחלק מהגדרת המודל. אם לא מציינים קול, ברירת המחדל היא 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
);

אפשר להגדיר הנחיית מערכת כדי להגדיר פרסונה או תפקיד שהמודל יגלם:

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

כדי לספק למודל הקשר ספציפי לאפליקציה (לדוגמה, היסטוריית הפעילות של המשתמש באפליקציה), אפשר להשתמש בהוראות מערכת כדי להתאים את השיחה.

אתחול של סשן Live API

אחרי שיוצרים את מופע LiveModel, קוראים ל-model.connect() כדי ליצור אובייקט LiveSession וליצור חיבור מתמשך עם המודל באמצעות סטרימינג עם זמן אחזור נמוך. ‫LiveSession מאפשר לכם ליצור אינטראקציה עם המודל על ידי הפעלה והפסקה של סשן קולי, וגם שליחה וקבלה של טקסט.

אחרי כן, תוכלו להתקשר אל startAudioConversation() כדי להתחיל את השיחה עם המודל:

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

בנוסף, חשוב לדעת שהמודל לא יודע להתמודד עם הפרעות בשיחה. אנחנו מתכוונים להוסיף את האפשרות הזו בעתיד.

אפשר גם להשתמש ב-Gemini Live API כדי ליצור אודיו בסטרימינג מטקסט וליצור טקסט מאודיו בסטרימינג. חשוב לזכור ש-Live API הוא דו-כיווני, ולכן משתמשים באותו חיבור כדי לשלוח ולקבל תוכן. בסופו של דבר, תוכלו גם לשלוח למודל תמונות ושידור וידאו חי.

קריאה לפונקציה: חיבור Gemini Live API לאפליקציה

כדי להרחיב את האפשרויות, אתם יכולים גם להפעיל את האפשרות של המודל ליצור אינטראקציה ישירה עם הלוגיקה של האפליקציה באמצעות קריאה לפונקציות.

התכונה 'הפעלת פונקציות' (או 'הפעלת כלים') היא תכונה של יישומי AI גנרטיבי שמאפשרת למודל להפעיל פונקציות מיוזמתו כדי לבצע פעולות. אם לפונקציה יש פלט, המודל מוסיף אותו להקשר ומשתמש בו ליצירות הבאות.

תרשים שממחיש איך Gemini Live API מאפשר למודל לפרש הנחיית משתמש, להפעיל פונקציה מוגדרת מראש עם ארגומנטים רלוונטיים באפליקציית Android, ואז לקבל מהמודל תגובת אישור.
איור 1: דיאגרמה שממחישה איך Gemini Live API מאפשר למודל לפרש הנחיה של משתמש, להפעיל פונקציה מוגדרת מראש עם ארגומנטים רלוונטיים באפליקציית Android, ואז לקבל מהמודל תשובת אישור.

כדי להטמיע קריאות לפונקציות באפליקציה, מתחילים ביצירת אובייקט FunctionDeclaration לכל פונקציה שרוצים לחשוף למודל.

לדוגמה, כדי לחשוף פונקציה addList שמצרפת מחרוזת לרשימה של מחרוזות ל-Gemini, מתחילים ביצירת משתנה FunctionDeclaration עם שם ותיאור קצר באנגלית פשוטה של הפונקציה והפרמטר שלה:

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

אחר כך מעבירים את FunctionDeclaration כ-Tool למודל כשמפעילים אותו:

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

לבסוף, מטמיעים פונקציית handler לטיפול בקריאה לכלי שהמודל מבצע ומעבירים לו את התשובה. פונקציית ה-handler הזו מסופקת ל-LiveSession כשמפעילים את startAudioConversation, היא מקבלת פרמטר FunctionCallPart ומחזירה את 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());

השלבים הבאים