สตรีมมิงแบบ 2 ทิศทางโดยใช้ Gemini Live API


Gemini Live API ช่วยให้สามารถโต้ตอบด้วยข้อความและเสียงแบบ 2 ทิศทางที่มีเวลาในการตอบสนองต่ำกับ Gemini เมื่อใช้ Live API คุณจะมอบประสบการณ์การสนทนาด้วยเสียงที่เหมือนมนุษย์และดูเป็นธรรมชาติให้แก่ผู้ใช้ปลายทางได้ พร้อมทั้งสามารถขัดจังหวะคำตอบของโมเดลโดยใช้คำสั่งแบบข้อความหรือเสียง โมเดลนี้สามารถประมวลผลอินพุตข้อความและเสียง (วิดีโอจะพร้อมใช้งานเร็วๆ นี้) รวมถึงแสดงผลเป็นข้อความและเสียง

คุณสามารถสร้างต้นแบบด้วยพรอมต์และ Live API ใน Vertex AI Studio ได้

Live API เป็น API ที่มีสถานะซึ่งสร้างการเชื่อมต่อ WebSocket เพื่อตั้งค่าเซสชันระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ Gemini โปรดดูรายละเอียดในLive APIเอกสารอ้างอิง

ก่อนเริ่มต้น

ใช้ได้เฉพาะเมื่อใช้ Vertex AI Gemini API เป็นผู้ให้บริการ API

หากยังไม่ได้ดำเนินการ ให้ทำตามคู่มือเริ่มต้นใช้งาน ซึ่งอธิบายวิธีตั้งค่าโปรเจ็กต์ Firebase, เชื่อมต่อแอปกับ Firebase, เพิ่ม SDK, เริ่มต้นบริการแบ็กเอนด์สําหรับ Vertex AI Gemini API และสร้างอินสแตนซ์ LiveModel

รุ่นที่รองรับความสามารถนี้

Live API รองรับโดย gemini-2.0-flash-live-preview-04-09เท่านั้น (ไม่ใช่ gemini-2.0-flash)

ใช้ฟีเจอร์มาตรฐานของ Live API

ส่วนนี้จะอธิบายวิธีใช้ฟีเจอร์มาตรฐานของ Live API โดยเฉพาะสําหรับสตรีมอินพุตและเอาต์พุตประเภทต่างๆ ดังนี้

สร้างข้อความสตรีมจากอินพุตข้อความสตรีม

ก่อนลองใช้ตัวอย่างนี้ ให้อ่านก่อนเริ่มต้นในส่วนแรกของคู่มือนี้ให้เสร็จสิ้นเพื่อตั้งค่าโปรเจ็กต์และแอป
ในส่วนนั้น คุณจะต้องคลิกปุ่มของGemini APIผู้ให้บริการที่เลือกด้วย เพื่อดูเนื้อหาเฉพาะผู้ให้บริการในหน้านี้

คุณสามารถส่งอินพุตข้อความที่สตรีม และรับเอาต์พุตข้อความที่สตรีม อย่าลืมสร้างอินสแตนซ์ liveModel และตั้งค่ารูปแบบคำตอบเป็น Text

Swift

แอปบนแพลตฟอร์ม Apple ยังไม่รองรับ Live API แต่โปรดกลับมาตรวจสอบอีกครั้งในเร็วๆ นี้

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

แอปบนแพลตฟอร์ม Apple ยังไม่รองรับ Live API แต่โปรดกลับมาตรวจสอบอีกครั้งในเร็วๆ นี้

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 เสียงและภาษา 31 ภาษาได้

หากไม่ได้ระบุเสียง ค่าเริ่มต้นจะเป็น Puck หรือจะกำหนดค่าให้โมเดลตอบกลับด้วยเสียงต่อไปนี้ก็ได้

Aoede (หญิง)
Charon (ชาย)
Fenrir (ชาย)
Kore (หญิง)
Puck (ชาย)

ดูตัวอย่างเสียงของเสียงเหล่านี้และรายการภาษาทั้งหมดที่มีให้บริการได้ที่ Chirp 3: เสียง HD

หากต้องการระบุเสียง ให้ตั้งค่าชื่อเสียงภายในออบเจ็กต์ speechConfig โดยเป็นส่วนหนึ่งของการกำหนดค่าโมเดล

Swift

แอปบนแพลตฟอร์ม Apple ยังไม่รองรับ Live API แต่โปรดกลับมาตรวจสอบอีกครั้งในเร็วๆ นี้

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 รองรับรูปแบบเสียงต่อไปนี้

  • รูปแบบเสียงอินพุต: เสียง PCM 16 บิตดิบที่ 16kHz แบบ Little-endian
  • รูปแบบเสียงเอาต์พุต: เสียง PCM 16 บิตดิบที่ 24 kHz แบบ Little-endian

ขีดจำกัดอัตรา

โดยจะมีการจำกัดจำนวนพรอมต์ดังต่อไปนี้

  • เซสชันพร้อมกัน 10 รายการต่อโปรเจ็กต์ Firebase
  • โทเค็น 4 ล้านรายการต่อนาที

ระยะเวลาของเซสชัน

ระยะเวลาเริ่มต้นของเซสชันคือ 30 นาที เมื่อระยะเวลาของเซสชันเกินขีดจำกัด ระบบจะตัดการเชื่อมต่อ

โมเดลยังถูกจํากัดด้วยขนาดบริบทด้วย การส่งอินพุตจำนวนมากอาจส่งผลให้เซสชันสิ้นสุดลงก่อนเวลา

การตรวจจับกิจกรรมเสียงพูด (VAD)

โมเดลจะดำเนินการตรวจจับกิจกรรมเสียง (VAD) ในสตรีมอินพุตเสียงอย่างต่อเนื่องโดยอัตโนมัติ VAD จะเปิดใช้อยู่โดยค่าเริ่มต้น

การนับโทเค็น

คุณใช้ CountTokens API กับ Live API ไม่ได้


แสดงความคิดเห็นเกี่ยวกับประสบการณ์การใช้งาน Firebase AI Logic