Gemini Live API

챗봇이나 에이전트 상호작용과 같이 실시간 및 짧은 지연 시간의 음성 지원이 필요한 애플리케이션의 경우 Gemini Live API를 사용하면 Gemini 모델의 입력과 출력을 모두 스트리밍하는 최적화된 방법을 제공합니다. Firebase AI Logic을 사용하면 백엔드 통합 없이 Android 앱에서 바로 Gemini Live API를 호출할 수 있습니다. 이 가이드에서는 Firebase AI Logic을 사용하여 Android 앱에서 Gemini Live API를 사용하는 방법을 보여줍니다.

시작하기

시작하기 전에 앱이 API 수준 21 이상을 타겟팅하는지 확인하세요.

아직 Firebase 프로젝트를 설정하지 않았다면 설정하고 앱을 Firebase에 연결합니다. 자세한 내용은 Firebase AI Logic 문서를 참고하세요.

Android 프로젝트 설정

앱 수준 build.gradle.kts 또는 build.gradle 파일에 Firebase AI Logic 라이브러리 종속 항목을 추가합니다. 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 통합 및 생성형 모델 초기화

애플리케이션의 AndroidManifest.xml 파일에 RECORD_AUDIO 권한을 추가합니다.

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

Gemini Developer API 백엔드 서비스를 초기화하고 LiveModel에 액세스합니다. gemini-2.0-flash-live-preview-04-09와 같이 Live API를 지원하는 모델을 사용합니다. 사용 가능한 모델은 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"))
       })

자바

// 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,
)

자바

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

자바

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

자바

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

그런 다음 모델을 인스턴스화할 때 이 FunctionDeclarationTool로 모델에 전달합니다.

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

자바

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

마지막으로 모델이 수행하는 도구 호출을 처리하고 응답을 다시 전달하는 핸들러 함수를 구현합니다. startAudioConversation를 호출할 때 LiveSession에 제공되는 이 핸들러 함수는 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());

다음 단계