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-live-preview-04-09 でのみサポートされます(gemini-2.0-flash ではサポートされません)。

また、gemini-2.0-flash-live-preview-04-09us-central1 ロケーションでのみサポートされています。

Live API の標準機能を使用する

このセクションでは、Live API の標準機能を使用して、さまざまなタイプの入力と出力をストリーミングする方法について説明します。

ストリーミング テキスト入力からストリーミング テキストを生成する

このサンプルを試す前に、このガイドの始める前にのセクションを完了して、プロジェクトとアプリを設定してください。
このセクションでは、選択した Gemini API プロバイダのボタンをクリックして、このページにプロバイダ固有のコンテンツを表示します。

ストリーミング テキスト入力を送信し、ストリーミング テキスト出力を受信できます。liveModel インスタンスを作成し、レスポンス モダリティText に設定してください。

Swift

Live API は Apple プラットフォーム アプリではまだサポートされていませんが、近日中にサポートされる予定です。

Kotlin

// Initialize the Vertex AI Gemini API backend service
// Set the location to `us-central1` (the flash-live model is only supported in that location)
// Create a `LiveModel` instance with the flash-live model (only model that supports the Live API)
val model = Firebase.ai(backend = GenerativeBackend.vertexAI(location = "us-central1")).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
// Set the location to `us-central1` (the flash-live model is only supported in that location)
// Create a `LiveModel` instance with the flash-live model (only model that supports the Live API)
LiveGenerativeModel lm = FirebaseAI.getInstance(GenerativeBackend.vertexAI("us-central1")).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
// Set the location to `us-central1` (the flash-live model is only supported in that location)
// Create a `LiveModel` instance with the flash-live model (only model that supports the Live API)
final model = FirebaseAI.vertexAI(location: 'us-central1').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
  // Set the location to `us-central1` (the flash-live model is only supported in that location)
  // Create a `LiveModel` instance with the flash-live model (only model that supports the Live API)
  var model = FirebaseAI.GetInstance(FirebaseAI.Backend.VertexAI(location: "us-central1")).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
// Set the location to `us-central1` (the flash-live model is only supported in that location)
// Create a `LiveModel` instance with the flash-live model (only model that supports the Live API)
val model = Firebase.ai(backend = GenerativeBackend.vertexAI(location = "us-central1")).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
// Set the location to `us-central1` (the flash-live model is only supported in that location)
// Create a `LiveModel` instance with the flash-live model (only model that supports the Live API)
LiveGenerativeModel lm = FirebaseAI.getInstance(GenerativeBackend.vertexAI("us-central1")).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
// Set the location to `us-central1` (the flash-live model is only supported in that location)
// Create a `LiveModel` instance with the flash-live model (only model that supports the Live API)
final model = FirebaseAI.vertexAI(location: 'us-central1').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
  // Set the location to `us-central1` (the flash-live model is only supported in that location)
  // Create a `LiveModel` instance with the flash-live model (only model that supports the Live API)
  var model = FirebaseAI.GetInstance(FirebaseAI.Backend.VertexAI(location: "us-central1")).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 を使用すると、さまざまな HD 音声言語で音声を送信できます。音声の完全なリストと各音声のデモについては、Chirp 3: HD 音声をご覧ください。

音声を指定するには、モデル構成の一部として、speechConfig オブジェクト内に音声名を設定します。音声を指定しない場合、デフォルトは Puck です。

Swift

Live API は Apple プラットフォーム アプリではまだサポートされていませんが、近日中にサポートされる予定です。

Kotlin

// ...

val model = Firebase.ai(backend = GenerativeBackend.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 = FirebaseAI.getInstance(GenerativeBackend.vertexAI()).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 = FirebaseAI.vertexAI().liveGenerativeModel(
  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(voiceName: 'Fenrir'),
  ),
);

// ...

Unity

var model = FirebaseAI.GetInstance(FirebaseAI.Backend.VertexAI()).GetLiveModel(
  modelName: "gemini-2.0-flash-live-preview-04-09",
  liveGenerationConfig: new LiveGenerationConfig(
    responseModalities: new[] { ResponseModality.Audio },
    speechConfig: SpeechConfig.UsePrebuiltVoice("Fenrir"),
);

プロンプトでモデルに英語以外の言語での応答を求める場合は、システム指示の一部として次の文言を含めることをおすすめします。

RESPOND IN LANGUAGE. YOU MUST RESPOND UNMISTAKABLY IN LANGUAGE.

セッションとリクエスト間でコンテキストを維持する

チャット構造を使用すると、セッションとリクエスト間でコンテキストを維持できます。この機能は、テキスト入力とテキスト出力でのみ使用できます。

このアプローチはコンテキストが短い場合に最適です。ターンバイターンのインタラクションを送信して、イベントの正確なシーケンスを表すことができます。コンテキストが長い場合は、1 つのメッセージの概要を提供して、後続のインタラクション用にコンテキスト ウィンドウを空けておくことをおすすめします。

割り込みを処理する

Firebase AI Logic は、中断の処理をまだサポートしていません。しばらくしてからもう一度ご確認ください。

関数呼び出し(ツール)を使用する

標準のコンテンツ生成メソッドと同様に、Live API で使用するツール(利用可能な関数など)を定義できます。このセクションでは、関数呼び出しで Live API を使用する際のニュアンスについて説明します。関数呼び出しの完全な説明と例については、関数呼び出しガイドをご覧ください。

モデルは、単一のプロンプトから複数の関数呼び出しと、出力の連結に必要なコードを生成できます。このコードはサンドボックス環境で実行され、後続の BidiGenerateContentToolCall メッセージを生成します。各関数呼び出しの結果が表示されるまで実行は停止するため、順番どおりに処理が行われます。

また、関数呼び出しで Live API を使用すると、モデルがユーザーにフォローアップ情報や説明情報をリクエストできるため、特に強力です。たとえば、呼び出す関数にパラメータ値を指定するのに十分な情報がモデルにない場合、モデルはユーザーに追加の情報や明確な情報の提供を求めることができます。

クライアントは BidiGenerateContentToolResponse を返します。



制限事項と要件

Live API の次の制限事項と要件に注意してください。

音声文字変換

Firebase AI Logic は、まだ文字起こしをサポートしていません。しばらくしてからもう一度ご確認ください。

言語

音声形式

Live API は、次のオーディオ形式をサポートしています。

  • 入力音声形式: RAW 16 ビット PCM 音声、16kHz、リトル エンディアン
  • 出力音声形式: RAW 16 ビット PCM 音声、24kHz、リトル エンディアン

レート上限

次のレート制限が適用されます。

  • Firebase プロジェクトあたり 10 個の同時実行セッション
  • 1 分あたり 400 万個のトークン

セッションの長さ

セッションのデフォルトの長さは 30 分です。セッション継続時間が上限を超えると、接続が終了します。

モデルはコンテキストのサイズによっても制限されます。大量の入力を送信すると、セッションが早期に終了する可能性があります。

音声アクティビティ検出(VAD)

モデルは、連続した音声入力ストリームに対して、音声アクティビティ検出(VAD)を自動的に実行します。VAD はデフォルトで有効になっています。

トークンのカウント

Live APICountTokens API を使用することはできません。


Firebase AI Logic の使用感についてフィードバックを送信する