Gemini Live API를 사용한 양방향 스트리밍


Gemini Live API를 사용하면 Gemini와의 양방향 텍스트 및 음성 상호작용의 지연 시간을 줄일 수 있습니다. Live API를 사용하면 최종 사용자에게 사람처럼 자연스러운 음성 대화 경험과 텍스트 또는 음성 명령을 사용하여 모델의 응답을 중단할 수 있는 기능을 제공할 수 있습니다. 이 모델은 텍스트 및 오디오 입력을 처리할 수 있으며 (동영상은 곧 제공 예정) 텍스트 및 오디오 출력을 제공할 수 있습니다.

Vertex AI Studio에서 프롬프트와 Live API를 사용하여 프로토타입을 만들 수 있습니다.

Live API는 WebSocket 연결을 만들어 클라이언트와 Gemini 서버 간에 세션을 설정하는 스테이트풀 API입니다. 자세한 내용은 Live API 참조 문서를 참고하세요.

시작하기 전에

Vertex AI Gemini API를 API 제공업체로 사용하는 경우에만 사용할 수 있습니다.

아직 완료하지 않았다면 Firebase 프로젝트를 설정하고, 앱을 Firebase에 연결하고, SDK를 추가하고, Vertex AI Gemini API의 백엔드 서비스를 초기화하고, LiveModel 인스턴스를 만드는 방법을 설명하는 시작 가이드를 완료하세요.

이 기능을 지원하는 모델

Live APIgemini-2.0-flash이 아닌 gemini-2.0-flash-live-preview-04-09에서만 지원됩니다.

Live API의 표준 기능 사용

이 섹션에서는 Live API의 표준 기능을 사용하는 방법을 설명합니다. 특히 다양한 유형의 입력과 출력을 스트리밍하는 방법을 설명합니다.

스트리밍된 텍스트 입력에서 스트리밍된 텍스트 생성

이 샘플을 사용해 보기 전에 이 가이드의 시작하기 전에 섹션을 완료하여 프로젝트와 앱을 설정하세요.
이 섹션에서 선택한 Gemini API 제공업체의 버튼을 클릭하면 이 페이지에 제공업체별 콘텐츠가 표시됩니다.

스트리밍된 텍스트 입력을 전송하고 스트리밍된 텍스트 출력을 수신할 수 있습니다. liveModel 인스턴스를 만들고 응답 모달Text로 설정해야 합니다.

Swift

Live API는 아직 Apple 플랫폼 앱에서 지원되지 않지만 곧 지원될 예정이니 다시 확인해 주세요.

Kotlin

// Initialize the Vertex AI Gemini API backend service
// Create a `LiveModel` instance with the model that supports the Live API
val model = Firebase.vertexAI.liveModel(
    modelName = "gemini-2.0-flash-live-preview-04-09",
    // Configure the model to respond with text
    generationConfig = liveGenerationConfig {
        responseModality = ResponseModality.TEXT 
   }
)

val session = model.connect()

// Provide a text prompt
val text = "tell a short story"

session.send(text)

var outputText = ""
session.receive().collect {
    if(it.status == Status.TURN_COMPLETE) {
        // Optional: if you don't require to send more requests.
        session.stopReceiving();
    }
    outputText = outputText + it.text
}

// Output received from the server.
println(outputText)

Java

ExecutorService executor = Executors.newFixedThreadPool(1);
// Initialize the Vertex AI Gemini API backend service
// Create a `LiveModel` instance with the model that supports the Live API
LiveGenerativeModel lm = FirebaseAI.getInstance(GenerativeBackend.vertexAI()).liveModel(
        "gemini-2.0-flash-live-preview-04-09",
        // Configure the model to respond with text
        new LiveGenerationConfig.Builder()
                .setResponseModalities(ResponseModality.TEXT)
                .build()
);
LiveModelFutures model = LiveModelFutures.from(lm);
ListenableFuture<LiveSession> sessionFuture =  model.connect();
class LiveContentResponseSubscriber implements Subscriber<LiveContentResponse> {
    @Override
    public void onSubscribe(Subscription s) {
        s.request(Long.MAX_VALUE); // Request an unlimited number of items
    }
    @Override
    public void onNext(LiveContentResponse liveContentResponse) {
       // Handle the response from the server.
	System.out.println(liveContentResponse.getText());
    }
    @Override
    public void onError(Throwable t) {
        System.err.println("Error: " + t.getMessage());
    }
    @Override
    public void onComplete() {
        System.out.println("Done receiving messages!");
    }
}
Futures.addCallback(sessionFuture, new FutureCallback<LiveSession>() {
    @Override
    public void onSuccess(LiveSession ses) {
	  LiveSessionFutures session = LiveSessionFutures.from(ses);
        // Provide a text prompt
        String text = "tell me a short story?";
        session.send(text);
        Publisher<LiveContentResponse> publisher = session.receive();
        publisher.subscribe(new LiveContentResponseSubscriber());
    }
    @Override
    public void onFailure(Throwable t) {
        // Handle exceptions
    }
}, executor);

Web

Live API는 아직 웹 앱에서 지원되지 않지만 곧 지원될 예정이니 다시 확인해 주세요.

Dart

import 'package:firebase_ai/firebase_ai.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';

late LiveModelSession _session;

await Firebase.initializeApp(
  options: DefaultFirebaseOptions.currentPlatform,
);

// Initialize the Vertex AI Gemini API backend service
// Create a `LiveModel` instance with the model that supports the Live API
final model = FirebaseAI.vertexAI().liveModel(
  model: 'gemini-2.0-flash-live-preview-04-09',
  // Configure the model to respond with text
  config: LiveGenerationConfig(responseModalities: [ResponseModality.text]),
);

_session = await model.connect();

// Provide a text prompt
final prompt = Content.text('tell a short story');
await _session.send(input: prompt, turnComplete: true);

// In a separate thread, receive the response
await for (final message in _session.receive()) {
   // Process the received message 
}

Unity

using Firebase;
using Firebase.AI;

async Task SendTextReceiveText() {
  // Initialize the Vertex AI Gemini API backend service
  // Create a `LiveModel` instance with the model that supports the Live API
  var model = FirebaseAI.GetInstance(FirebaseAI.Backend.VertexAI()).GetLiveModel(
    modelName: "gemini-2.0-flash-live-preview-04-09",
    // Configure the model to respond with text
    liveGenerationConfig: new LiveGenerationConfig(
        responseModalities: new[] { ResponseModality.Text })
  );

  LiveSession session = await model.ConnectAsync();

  // Provide a text prompt
  var prompt = ModelContent.Text("tell a short story");
  await session.SendAsync(content: prompt, turnComplete: true);

  // Receive the response
  await foreach (var message in session.ReceiveAsync()) {
    // Process the received message
    if (!string.IsNullOrEmpty(message.Text)) {
      UnityEngine.Debug.Log("Received message: " + message.Text);
    }
  }
}

사용 사례 및 앱에 적합한 모델을 선택하는 방법을 알아보세요.

스트리밍된 오디오 입력에서 스트리밍된 오디오 생성

이 샘플을 사용해 보기 전에 이 가이드의 시작하기 전에 섹션을 완료하여 프로젝트와 앱을 설정하세요.
이 섹션에서 선택한 Gemini API 제공업체의 버튼을 클릭하면 이 페이지에 제공업체별 콘텐츠가 표시됩니다.

스트리밍된 오디오 입력을 전송하고 스트리밍된 오디오 출력을 수신할 수 있습니다. LiveModel 인스턴스를 만들고 응답 모달Audio로 설정해야 합니다.

응답 음성을 구성하고 맞춤설정하는 방법을 알아보세요 (이 페이지의 뒷부분 참고).

Swift

Live API는 아직 Apple 플랫폼 앱에서 지원되지 않지만 곧 지원될 예정이니 다시 확인해 주세요.

Kotlin

// Initialize the Vertex AI Gemini API backend service
// Create a `LiveModel` instance with the model that supports the Live API
val model = Firebase.vertexAI.liveModel(
    modelName = "gemini-2.0-flash-live-preview-04-09",
    // Configure the model to respond with text
    generationConfig = liveGenerationConfig {
        responseModality = ResponseModality.AUDIO 
   }
)

val session = model.connect()

// This is the recommended way.
// However, you can create your own recorder and handle the stream.
session.startAudioConversation()

Java

ExecutorService executor = Executors.newFixedThreadPool(1);
// Initialize the Vertex AI Gemini API backend service
// Create a `LiveModel` instance with the model that supports the Live API
LiveGenerativeModel lm = FirebaseAI.getInstance(GenerativeBackend.vertexAI()).liveModel(
        "gemini-2.0-flash-live-preview-04-09",
        // Configure the model to respond with text
        new LiveGenerationConfig.Builder()
                .setResponseModalities(ResponseModality.TEXT)
                .build()
);
LiveModelFutures model = LiveModelFutures.from(lm);
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);

Web

Live API는 아직 웹 앱에서 지원되지 않지만 곧 지원될 예정이니 다시 확인해 주세요.

Dart

import 'package:firebase_ai/firebase_ai.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
import 'package:your_audio_recorder_package/your_audio_recorder_package.dart';

late LiveModelSession _session;
final _audioRecorder = YourAudioRecorder();

await Firebase.initializeApp(
  options: DefaultFirebaseOptions.currentPlatform,
);

// Initialize the Vertex AI Gemini API backend service
// Create a `LiveModel` instance with the model that supports the Live API
final model = FirebaseAI.vertexAI().liveModel(
  model: 'gemini-2.0-flash-live-preview-04-09',
   // Configure the model to respond with audio
   config: LiveGenerationConfig(responseModalities: [ResponseModality.audio]),
);

_session = await model.connect();

final audioRecordStream = _audioRecorder.startRecordingStream();
// Map the Uint8List stream to InlineDataPart stream
final mediaChunkStream = audioRecordStream.map((data) {
  return InlineDataPart('audio/pcm', data);
});
await _session.startMediaStream(mediaChunkStream);

// In a separate thread, receive the audio response from the model
await for (final message in _session.receive()) {
   // Process the received message 
}

Unity

using Firebase;
using Firebase.AI;

async Task SendTextReceiveAudio() {
  // Initialize the Vertex AI Gemini API backend service
  // Create a `LiveModel` instance with the model that supports the Live API
  var model = FirebaseAI.GetInstance(FirebaseAI.Backend.VertexAI()).GetLiveModel(
    modelName: "gemini-2.0-flash-live-preview-04-09",
    // Configure the model to respond with audio
    liveGenerationConfig: new LiveGenerationConfig(
        responseModalities: new[] { ResponseModality.Audio })
  );

  LiveSession session = await model.ConnectAsync();

  // Start a coroutine to send audio from the Microphone
  var recordingCoroutine = StartCoroutine(SendAudio(session));

  // Start receiving the response
  await ReceiveAudio(session);
}

IEnumerator SendAudio(LiveSession liveSession) {
  string microphoneDeviceName = null;
  int recordingFrequency = 16000;
  int recordingBufferSeconds = 2;

  var recordingClip = Microphone.Start(microphoneDeviceName, true,
                                       recordingBufferSeconds, recordingFrequency);

  int lastSamplePosition = 0;
  while (true) {
    if (!Microphone.IsRecording(microphoneDeviceName)) {
      yield break;
    }

    int currentSamplePosition = Microphone.GetPosition(microphoneDeviceName);

    if (currentSamplePosition != lastSamplePosition) {
      // The Microphone uses a circular buffer, so we need to check if the
      // current position wrapped around to the beginning, and handle it
      // accordingly.
      int sampleCount;
      if (currentSamplePosition > lastSamplePosition) {
        sampleCount = currentSamplePosition - lastSamplePosition;
      } else {
        sampleCount = recordingClip.samples - lastSamplePosition + currentSamplePosition;
      }

      if (sampleCount > 0) {
        // Get the audio chunk
        float[] samples = new float[sampleCount];
        recordingClip.GetData(samples, lastSamplePosition);

        // Send the data, discarding the resulting Task to avoid the warning
        _ = liveSession.SendAudioAsync(samples);

        lastSamplePosition = currentSamplePosition;
      }
    }

    // Wait for a short delay before reading the next sample from the Microphone
    const float MicrophoneReadDelay = 0.5f;
    yield return new WaitForSeconds(MicrophoneReadDelay);
  }
}

Queue audioBuffer = new();

async Task ReceiveAudio(LiveSession liveSession) {
  int sampleRate = 24000;
  int channelCount = 1;

  // Create a looping AudioClip to fill with the received audio data
  int bufferSamples = (int)(sampleRate * channelCount);
  AudioClip clip = AudioClip.Create("StreamingPCM", bufferSamples, channelCount,
                                    sampleRate, true, OnAudioRead);

  // Attach the clip to an AudioSource and start playing it
  AudioSource audioSource = GetComponent();
  audioSource.clip = clip;
  audioSource.loop = true;
  audioSource.Play();

  // Start receiving the response
  await foreach (var message in liveSession.ReceiveAsync()) {
    // Process the received message
    foreach (float[] pcmData in message.AudioAsFloat) {
      lock (audioBuffer) {
        foreach (float sample in pcmData) {
          audioBuffer.Enqueue(sample);
        }
      }
    }
  }
}

// This method is called by the AudioClip to load audio data.
private void OnAudioRead(float[] data) {
  int samplesToProvide = data.Length;
  int samplesProvided = 0;

  lock(audioBuffer) {
    while (samplesProvided < samplesToProvide && audioBuffer.Count > 0) {
      data[samplesProvided] = audioBuffer.Dequeue();
      samplesProvided++;
    }
  }

  while (samplesProvided < samplesToProvide) {
    data[samplesProvided] = 0.0f;
    samplesProvided++;
  }
}

사용 사례 및 앱에 적합한 모델을 선택하는 방법을 알아보세요.



더 매력적이고 양방향적인 환경을 만듭니다.

이 섹션에서는 Live API의 더 매력적이거나 양방향적인 기능을 만들고 관리하는 방법을 설명합니다.

응답 음성 변경하기

Live API는 Chirp 3를 사용하여 합성 음성 응답을 지원합니다. Firebase AI Logic를 사용하면 5가지 HD 음성 및 31개 언어로 오디오를 전송할 수 있습니다.

음성을 지정하지 않으면 기본값은 Puck입니다. 또는 다음 음성 중 하나로 응답하도록 모델을 구성할 수 있습니다.

Aoede (여성)
Charon (남성)
Fenrir (남성)
Kore (여성)
Puck (남성)

이러한 음성의 소리를 들을 수 있는 데모와 사용 가능한 언어의 전체 목록은 Chirp 3: HD 음성을 참고하세요.

음성을 지정하려면 모델 구성의 일부로 speechConfig 객체 내에서 음성 이름을 설정합니다.

Swift

Live API는 아직 Apple 플랫폼 앱에서 지원되지 않지만 곧 지원될 예정이니 다시 확인해 주세요.

Kotlin

// ...

val model = Firebase.vertexAI.liveModel(
    modelName = "gemini-2.0-flash-live-preview-04-09",
    // Configure the model to use a specific voice for its audio response
    generationConfig = liveGenerationConfig {
        responseModality = ResponseModality.AUDIO
        speechConfig = SpeechConfig(voice = Voices.FENRIR)
    }
)

// ...

Java

// ...

LiveModel model = Firebase.getVertexAI().liveModel(
    "gemini-2.0-flash-live-preview-04-09",
    // Configure the model to use a specific voice for its audio response
    new LiveGenerationConfig.Builder()
        .setResponseModalities(ResponseModality.AUDIO)
        .setSpeechConfig(new SpeechConfig(Voices.FENRIR))
        .build()
);

// ...

Web

Live API는 아직 웹 앱에서 지원되지 않지만 곧 지원될 예정이니 다시 확인해 주세요.

Dart

// ...

final model = FirebaseVertexAI.instance.liveModel(
  model: 'gemini-2.0-flash-live-preview-04-09',
  // Configure the model to use a specific voice for its audio response
  config: LiveGenerationConfig(
    responseModality: ResponseModality.audio,
    speechConfig: SpeechConfig(voice: Voice.fenrir),
  ),
);

// ...

Unity

Snippets coming soon!

모델에 영어가 아닌 언어로 프롬프트하고 응답하도록 요구할 때 최상의 결과를 얻으려면 시스템 안내에 다음을 포함하세요.

RESPOND IN LANGUAGE. YOU MUST RESPOND UNMISTAKABLY IN LANGUAGE.

세션과 요청 전반에서 컨텍스트 유지

채팅 구조를 사용하여 세션과 요청 간에 컨텍스트를 유지할 수 있습니다. 이 방법은 텍스트 입력 및 텍스트 출력에만 작동합니다.

이 접근 방식은 짧은 컨텍스트에 가장 적합합니다. 차례대로 상호작용을 전송하여 정확한 이벤트 순서를 나타낼 수 있습니다. 컨텍스트가 긴 경우 후속 상호작용을 위해 컨텍스트 창을 확보할 수 있도록 단일 메시지 요약을 제공하는 것이 좋습니다.

방해 요소 처리

Firebase AI Logic는 아직 중단 처리를 지원하지 않습니다. 나중에 다시 확인해 주세요.

함수 호출 사용 (도구)

표준 콘텐츠 생성 메서드에서와 마찬가지로 사용 가능한 함수와 같은 도구를 Live API와 함께 사용할 수 있습니다. 이 섹션에서는 함수 호출과 함께 Live API를 사용할 때의 몇 가지 차이점을 설명합니다. 함수 호출에 관한 전체 설명과 예시는 함수 호출 가이드를 참고하세요.

모델은 단일 프롬프트에서 여러 함수 호출과 출력을 연결하는 데 필요한 코드를 생성할 수 있습니다. 이 코드는 샌드박스 환경에서 실행되어 후속 BidiGenerateContentToolCall 메시지를 생성합니다. 각 함수 호출의 결과가 나올 때까지 실행이 일시중지되므로 순차 처리가 보장됩니다.

또한 함수 호출과 함께 Live API를 사용하면 모델이 사용자에게 후속 조치 또는 명확한 정보를 요청할 수 있으므로 특히 강력합니다. 예를 들어 모델에 호출하려는 함수에 매개변수 값을 제공하기에 충분한 정보가 없는 경우 모델은 사용자에게 추가 정보 또는 명확한 정보를 제공해 달라고 요청할 수 있습니다.

클라이언트는 BidiGenerateContentToolResponse로 응답해야 합니다.



제한사항 및 요구사항

Live API의 다음과 같은 제한사항 및 요구사항에 유의하세요.

스크립트 작성

Firebase AI Logic는 아직 스크립트 작성을 지원하지 않습니다. 나중에 다시 확인해 주세요.

언어

오디오 형식

Live API는 다음 오디오 형식을 지원합니다.

  • 입력 오디오 형식: 16kHz little-endian의 원시 16비트 PCM 오디오
  • 출력 오디오 형식: 24kHz little-endian의 원시 16비트 PCM 오디오

비율 제한

다음 비율 한도가 적용됩니다.

  • Firebase 프로젝트당 동시 세션 10개
  • 분당 토큰 4백만 개

세션 길이

세션의 기본 길이는 30분입니다. 세션 시간이 한도를 초과하면 연결이 종료됩니다.

또한 모델은 컨텍스트 크기에 따라 제한됩니다. 대량의 입력 데이터를 전송하면 세션이 더 일찍 종료될 수 있습니다.

음성 활동 감지(VAD)

이 모델은 연속 오디오 입력 스트림에서 음성 활동 감지 (VAD)를 자동으로 실행합니다. VAD는 기본적으로 사용 설정되어 있습니다.

토큰 수 집계

CountTokens API는 Live API와 함께 사용할 수 없습니다.


Firebase AI Logic 사용 경험에 관한 의견 보내기