Live API

Live API を使用すると、Gemini との双方向の音声と動画による低レイテンシのやり取りが可能になります。これにより、動画入力のストリーミングや画面共有を行いながら、Gemini とリアルタイムで会話できます。Live API を使用すると、エンドユーザーに自然で人間のような音声会話のエクスペリエンスを提供できます。

Live API は Google AI Studio で試すことができます。Google AI Studio で Live API を使用するには、[ストリーミング] を選択します。

Live API の仕組み

ストリーミング

Live API は、WebSocket 接続を介したストリーミング モデルを使用します。API を操作すると、永続接続が作成されます。入力(音声、動画、テキスト)がモデルに継続的にストリーミングされ、モデルのレスポンス(テキストまたは音声)が同じ接続を介してリアルタイムでストリーミングされます。

この双方向ストリーミングにより、低レイテンシが保証され、音声アクティビティの検出、ツールの使用、音声生成などの機能がサポートされます。

Live API の概要

基盤となる WebSockets API の詳細については、WebSockets API リファレンスをご覧ください。

出力生成

Live API は、マルチモーダル入力(テキスト、音声、動画)を処理して、テキストまたは音声をリアルタイムで生成します。音声を生成するためのメカニズムが組み込まれており、使用するモデル バージョンに応じて、次の 2 つの音声生成方法のいずれかを使用します。

  • ハーフ カスケード: モデルはネイティブ音声入力を受け取り、個別のモデルの特殊なモデル カスケードを使用して入力を処理し、音声出力を生成します。
  • ネイティブ: Gemini 2.5 では、ネイティブ音声生成が導入されました。これにより、音声出力を直接生成し、より自然な音声、より表現力豊かな音声、トーンなどの追加コンテキストの認識、より積極的なレスポンスを実現できます。

Live API を使用した構築

Live API を使用してビルドを開始する前に、ニーズに最適な音声生成アプローチを選択します。

接続を確立する

次の例は、API キーを使用して接続を作成する方法を示しています。

PythonJavaScript
import asyncio
from google import genai

client = genai.Client(api_key="GEMINI_API_KEY")

model = "gemini-2.0-flash-live-001"
config = {"response_modalities": ["TEXT"]}

async def main():
    async with client.aio.live.connect(model=model, config=config) as session:
        print("Session started")

if __name__ == "__main__":
    asyncio.run(main())
import { GoogleGenAI } from '@google/genai';

const ai = new GoogleGenAI({ apiKey: "GOOGLE_API_KEY" });
const model = 'gemini-2.0-flash-live-001';
const config = { responseModalities: [Modality.TEXT] };

async function main() {

    const session = await ai.live.connect({
        model: model,
        callbacks: {
            onopen: function () {
                console.debug('Opened');
            },
            onmessage: function (message) {
                console.debug(message);
            },
            onerror: function (e) {
                console.debug('Error:', e.message);
            },
            onclose: function (e) {
                console.debug('Close:', e.reason);
            },
        },
        config: config,
    });

    // Send content...

    session.close();
}

main();

テキストの送受信

テキストの送受信方法は次のとおりです。

PythonJavaScript
import asyncio
from google import genai

client = genai.Client(api_key="GEMINI_API_KEY")
model = "gemini-2.0-flash-live-001"

config = {"response_modalities": ["TEXT"]}

async def main():
    async with client.aio.live.connect(model=model, config=config) as session:
        message = "Hello, how are you?"
        await session.send_client_content(
            turns={"role": "user", "parts": [{"text": message}]}, turn_complete=True
        )

        async for response in session.receive():
            if response.text is not None:
                print(response.text, end="")

if __name__ == "__main__":
    asyncio.run(main())
import { GoogleGenAI, Modality } from '@google/genai';

const ai = new GoogleGenAI({ apiKey: "GOOGLE_API_KEY" });
const model = 'gemini-2.0-flash-live-001';
const config = { responseModalities: [Modality.TEXT] };

async function live() {
    const responseQueue = [];

    async function waitMessage() {
        let done = false;
        let message = undefined;
        while (!done) {
            message = responseQueue.shift();
            if (message) {
                done = true;
            } else {
                await new Promise((resolve) => setTimeout(resolve, 100));
            }
        }
        return message;
    }

    async function handleTurn() {
        const turns = [];
        let done = false;
        while (!done) {
            const message = await waitMessage();
            turns.push(message);
            if (message.serverContent && message.serverContent.turnComplete) {
                done = true;
            }
        }
        return turns;
    }

    const session = await ai.live.connect({
        model: model,
        callbacks: {
            onopen: function () {
                console.debug('Opened');
            },
            onmessage: function (message) {
                responseQueue.push(message);
            },
            onerror: function (e) {
                console.debug('Error:', e.message);
            },
            onclose: function (e) {
                console.debug('Close:', e.reason);
            },
        },
        config: config,
    });

    const simple = 'Hello how are you?';
    session.sendClientContent({ turns: simple });

    const turns = await handleTurn();
    for (const turn of turns) {
        if (turn.text) {
            console.debug('Received text: %s\n', turn.text);
        }
        else if (turn.data) {
            console.debug('Received inline data: %s\n', turn.data);
        }
    }

    session.close();
}

async function main() {
    await live().catch((e) => console.error('got error', e));
}

main();

音声の送受信

音声を 16 ビット PCM、16 kHz、モノラル形式に変換して送信できます。この例では、WAV ファイルを読み取り、正しい形式で送信します。

PythonJavaScript
# Test file: https://storage.googleapis.com/generativeai-downloads/data/16000.wav
# Install helpers for converting files: pip install librosa soundfile
import asyncio
import io
from pathlib import Path
from google import genai
from google.genai import types
import soundfile as sf
import librosa

client = genai.Client(api_key="GEMINI_API_KEY")
model = "gemini-2.0-flash-live-001"

config = {"response_modalities": ["TEXT"]}

async def main():
    async with client.aio.live.connect(model=model, config=config) as session:

        buffer = io.BytesIO()
        y, sr = librosa.load("sample.wav", sr=16000)
        sf.write(buffer, y, sr, format='RAW', subtype='PCM_16')
        buffer.seek(0)
        audio_bytes = buffer.read()

        # If already in correct format, you can use this:
        # audio_bytes = Path("sample.pcm").read_bytes()

        await session.send_realtime_input(
            audio=types.Blob(data=audio_bytes, mime_type="audio/pcm;rate=16000")
        )

        async for response in session.receive():
            if response.text is not None:
                print(response.text)

if __name__ == "__main__":
    asyncio.run(main())
// Test file: https://storage.googleapis.com/generativeai-downloads/data/16000.wav
// Install helpers for converting files: npm install wavefile
import { GoogleGenAI, Modality } from '@google/genai';
import * as fs from "node:fs";
import pkg from 'wavefile';
const { WaveFile } = pkg;

const ai = new GoogleGenAI({ apiKey: "GOOGLE_API_KEY" });
const model = 'gemini-2.0-flash-live-001';
const config = { responseModalities: [Modality.TEXT] };

async function live() {
    const responseQueue = [];

    async function waitMessage() {
        let done = false;
        let message = undefined;
        while (!done) {
            message = responseQueue.shift();
            if (message) {
                done = true;
            } else {
                await new Promise((resolve) => setTimeout(resolve, 100));
            }
        }
        return message;
    }

    async function handleTurn() {
        const turns = [];
        let done = false;
        while (!done) {
            const message = await waitMessage();
            turns.push(message);
            if (message.serverContent && message.serverContent.turnComplete) {
                done = true;
            }
        }
        return turns;
    }

    const session = await ai.live.connect({
        model: model,
        callbacks: {
            onopen: function () {
                console.debug('Opened');
            },
            onmessage: function (message) {
                responseQueue.push(message);
            },
            onerror: function (e) {
                console.debug('Error:', e.message);
            },
            onclose: function (e) {
                console.debug('Close:', e.reason);
            },
        },
        config: config,
    });

    // Send Audio Chunk
    const fileBuffer = fs.readFileSync("sample.wav");

    // Ensure audio conforms to API requirements (16-bit PCM, 16kHz, mono)
    const wav = new WaveFile();
    wav.fromBuffer(fileBuffer);
    wav.toSampleRate(16000);
    wav.toBitDepth("16");
    const base64Audio = wav.toBase64();

    // If already in correct format, you can use this:
    // const fileBuffer = fs.readFileSync("sample.pcm");
    // const base64Audio = Buffer.from(fileBuffer).toString('base64');

    session.sendRealtimeInput(
        {
            audio: {
                data: base64Audio,
                mimeType: "audio/pcm;rate=16000"
            }
        }

    );

    const turns = await handleTurn();
    for (const turn of turns) {
        if (turn.text) {
            console.debug('Received text: %s\n', turn.text);
        }
        else if (turn.data) {
            console.debug('Received inline data: %s\n', turn.data);
        }
    }

    session.close();
}

async function main() {
    await live().catch((e) => console.error('got error', e));
}

main();

音声を受け取るには、レスポンス モダリティとして AUDIO を設定します。この例では、受信したデータを WAV ファイルとして保存します。

PythonJavaScript
import asyncio
import wave
from google import genai

client = genai.Client(api_key="GEMINI_API_KEY")
model = "gemini-2.0-flash-live-001"

config = {"response_modalities": ["AUDIO"]}

async def main():
    async with client.aio.live.connect(model=model, config=config) as session:
        wf = wave.open("audio.wav", "wb")
        wf.setnchannels(1)
        wf.setsampwidth(2)
        wf.setframerate(24000)

        message = "Hello how are you?"
        await session.send_client_content(
            turns={"role": "user", "parts": [{"text": message}]}, turn_complete=True
        )

        async for idx,response in async_enumerate(session.receive()):
            if response.data is not None:
                wf.writeframes(response.data)

            # Un-comment this code to print audio data info
            # if response.server_content.model_turn is not None:
            #      print(response.server_content.model_turn.parts[0].inline_data.mime_type)

        wf.close()

if __name__ == "__main__":
    asyncio.run(main())
import { GoogleGenAI, Modality } from '@google/genai';

const ai = new GoogleGenAI({ apiKey: "GOOGLE_API_KEY" });
const model = 'gemini-2.0-flash-live-001';
const config = { responseModalities: [Modality.AUDIO] };

async function live() {
    const responseQueue = [];

    async function waitMessage() {
        let done = false;
        let message = undefined;
        while (!done) {
            message = responseQueue.shift();
            if (message) {
                done = true;
            } else {
                await new Promise((resolve) => setTimeout(resolve, 100));
            }
        }
        return message;
    }

    async function handleTurn() {
        const turns = [];
        let done = false;
        while (!done) {
            const message = await waitMessage();
            turns.push(message);
            if (message.serverContent && message.serverContent.turnComplete) {
                done = true;
            }
        }
        return turns;
    }

    const session = await ai.live.connect({
        model: model,
        callbacks: {
            onopen: function () {
                console.debug('Opened');
            },
            onmessage: function (message) {
                responseQueue.push(message);
            },
            onerror: function (e) {
                console.debug('Error:', e.message);
            },
            onclose: function (e) {
                console.debug('Close:', e.reason);
            },
        },
        config: config,
    });

    const simple = 'Hello how are you?';
    session.sendClientContent({ turns: simple });

    const turns = await handleTurn();

    // Combine audio data strings and save as wave file
    const combinedAudio = turns.reduce((acc, turn) => {
        if (turn.data) {
            const buffer = Buffer.from(turn.data, 'base64');
            const intArray = new Int16Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / Int16Array.BYTES_PER_ELEMENT);
            return acc.concat(Array.from(intArray));
        }
        return acc;
    }, []);

    const audioBuffer = new Int16Array(combinedAudio);

    const wf = new WaveFile();
    wf.fromScratch(1, 24000, '16', audioBuffer);
    fs.writeFileSync('output.wav', wf.toBuffer());

    session.close();
}

async function main() {
    await live().catch((e) => console.error('got error', e));
}

main();

オーディオ形式

Live API の音声データは常に未加工のリトル エンディアン 16 ビット PCM です。オーディオ出力では常に 24 kHz のサンプリング レートが使用されます。入力音声はネイティブで 16 kHz ですが、Live API は必要に応じて再サンプリングするため、任意のサンプルレートを送信できます。入力音声のサンプルレートを伝えるには、音声を含む各 Blob の MIME タイプを audio/pcm;rate=16000 などの値に設定します。

音声文字変換の受信

設定構成で output_audio_transcription を送信すると、モデルの音声出力の文字起こしを有効にできます。音声文字変換の言語は、モデルのレスポンスから推測されます。

import asyncio
from google import genai
from google.genai import types

client = genai.Client(api_key="GEMINI_API_KEY")
model = "gemini-2.0-flash-live-001"

config = {"response_modalities": ["AUDIO"],
          "output_audio_transcription": {}
}

async def main():
    async with client.aio.live.connect(model=model, config=config) as session:
        message = "Hello? Gemini are you there?"

        await session.send_client_content(
            turns={"role": "user", "parts": [{"text": message}]}, turn_complete=True
        )

        async for response in session.receive():
            if response.server_content.model_turn:
                print("Model turn:", response.server_content.model_turn)
            if response.server_content.output_transcription:
                print("Transcript:", response.server_content.output_transcription.text)


if __name__ == "__main__":
    asyncio.run(main())

設定構成で input_audio_transcription を送信すると、音声入力の文字起こしを有効にできます。

import asyncio
from google import genai
from google.genai import types

client = genai.Client(api_key="GEMINI_API_KEY")
model = "gemini-2.0-flash-live-001"

config = {"response_modalities": ["TEXT"],
    "realtime_input_config": {
        "automatic_activity_detection": {"disabled": True},
        "activity_handling": "NO_INTERRUPTION",
    },
    "input_audio_transcription": {},
}

async def main():
    async with client.aio.live.connect(model=model, config=config) as session:
        audio_data = Path("sample.pcm").read_bytes()

        await session.send_realtime_input(activity_start=types.ActivityStart())
        await session.send_realtime_input(
            audio=types.Blob(data=audio_data, mime_type='audio/pcm;rate=16000')
        )
        await session.send_realtime_input(activity_end=types.ActivityEnd())

        async for msg in session.receive():
            if msg.server_content.input_transcription:
                print('Transcript:', msg.server_content.input_transcription.text)

if __name__ == "__main__":
    asyncio.run(main())

ストリーミング音声およびストリーミング動画

システム指示

システム指示を使用すると、特定のニーズやユースケースに基づいてモデルの動作を制御できます。システム指示は設定構成で設定でき、セッション全体で有効になります。

from google.genai import types

config = {
    "system_instruction": types.Content(
        parts=[
            types.Part(
                text="You are a helpful assistant and answer in a friendly tone."
            )
        ]
    ),
    "response_modalities": ["TEXT"],
}

コンテンツの増分更新

増分更新を使用して、テキスト入力の送信、セッション コンテキストの確立、セッション コンテキストの復元を行います。コンテキストが短い場合は、ターンバイターンのインタラクションを送信して、イベントの正確なシーケンスを表すことができます。

PythonJSON
turns = [
    {"role": "user", "parts": [{"text": "What is the capital of France?"}]},
    {"role": "model", "parts": [{"text": "Paris"}]},
]

await session.send_client_content(turns=turns, turn_complete=False)

turns = [{"role": "user", "parts": [{"text": "What is the capital of Germany?"}]}]

await session.send_client_content(turns=turns, turn_complete=True)
{
  "clientContent": {
    "turns": [
      {
        "parts":[
          {
            "text": ""
          }
        ],
        "role":"user"
      },
      {
        "parts":[
          {
            "text": ""
          }
        ],
        "role":"model"
      }
    ],
    "turnComplete": true
  }
}

コンテキストが長い場合は、1 つのメッセージの概要を提供して、後続のインタラクション用にコンテキスト ウィンドウを空けておくことをおすすめします。

音声と言語の変更

Live API は、Puck、Charon、Kore、Fenrir、Aoede、Leda、Orus、Zephyr の音声をサポートしています。

音声を指定するには、セッション構成の一部として、speechConfig オブジェクト内に音声名を設定します。

PythonJSON
from google.genai import types

config = types.LiveConnectConfig(
    response_modalities=["AUDIO"],
    speech_config=types.SpeechConfig(
        voice_config=types.VoiceConfig(
            prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name="Kore")
        )
    )
)
{
  "voiceConfig": {
    "prebuiltVoiceConfig": {
      "voiceName": "Kore"
    }
  }
}

Live API は複数の言語をサポートしています。

言語を変更するには、セッション構成の一部として speechConfig オブジェクト内に言語コードを設定します。

from google.genai import types

config = types.LiveConnectConfig(
    response_modalities=["AUDIO"],
    speech_config=types.SpeechConfig(
        language_code="de-DE",
    )
)

ネイティブ オーディオ出力

Live API を使用すると、ネイティブ音声入力に加えてネイティブ音声出力を可能にするモデルにもアクセスできます。これにより、より質の高い音声出力が可能になり、ペース、音声の自然さ、冗長性、ムードが向上します。

ネイティブ オーディオ出力は、次のネイティブ オーディオ モデルでサポートされています。

  • gemini-2.5-flash-preview-native-audio-dialog
  • gemini-2.5-flash-exp-native-audio-thinking-dialog

ネイティブ音声出力の使用方法

ネイティブ音声出力を使用するには、ネイティブ音声モデルのいずれかを構成し、response_modalitiesAUDIO に設定します。

model = "gemini-2.5-flash-preview-native-audio-dialog"
config = types.LiveConnectConfig(response_modalities=["AUDIO"])

async with client.aio.live.connect(model=model, config=config) as session:
    # Send audio input and receive audio

感情的な会話

この機能により、Gemini は入力された表現とトーンに合わせて応答スタイルを調整できます。

感情的なダイアログを使用するには、設定メッセージで enable_affective_dialogtrue に設定します。

config = types.LiveConnectConfig(
    response_modalities=["AUDIO"],
    enable_affective_dialog=True
)

現時点では、感情的なダイアログはネイティブ音声出力モデルでのみサポートされています。

先行オーディオ

この機能が有効になっている場合、Gemini はコンテンツが関連性がない場合は事前に応答しないことを決定できます。

使用するには、セットアップ メッセージの proactivity フィールドを構成し、proactive_audiotrue に設定します。

config = types.LiveConnectConfig(
    response_modalities=["AUDIO"],
    proactivity={'proactive_audio': True}
)

プロアクティブ音声は、現在のところネイティブ音声出力モデルでのみサポートされています。

思考中のネイティブ音声出力

ネイティブ音声出力は思考機能をサポートしており、別個のモデル gemini-2.5-flash-exp-native-audio-thinking-dialog で利用できます。

model = "gemini-2.5-flash-exp-native-audio-thinking-dialog"
config = types.LiveConnectConfig(response_modalities=["AUDIO"])

async with client.aio.live.connect(model=model, config=config) as session:
    # Send audio input and receive audio

Live API でのツールの使用

Live API を使用して、関数呼び出しコード実行Google 検索などのツールを定義できます。

サポートされているツールの概要

各モデルで利用できるツールの概要は次のとおりです。

ツール カスケード モデル
gemini-2.0-flash-live-001
gemini-2.5-flash-preview-native-audio-dialog gemini-2.5-flash-exp-native-audio-thinking-dialog
検索
関数呼び出し いいえ
コードの実行 × いいえ
URL コンテキスト × いいえ

関数呼び出し

関数宣言は、セッション構成の一部として定義できます。詳細については、関数呼び出しチュートリアルをご覧ください。

ツール呼び出しを受け取ったクライアントは、session.send_tool_response メソッドを使用して FunctionResponse オブジェクトのリストを返す必要があります。

import asyncio
from google import genai
from google.genai import types

client = genai.Client(api_key="GEMINI_API_KEY")
model = "gemini-2.0-flash-live-001"

# Simple function definitions
turn_on_the_lights = {"name": "turn_on_the_lights"}
turn_off_the_lights = {"name": "turn_off_the_lights"}

tools = [{"function_declarations": [turn_on_the_lights, turn_off_the_lights]}]
config = {"response_modalities": ["TEXT"], "tools": tools}

async def main():
    async with client.aio.live.connect(model=model, config=config) as session:
        prompt = "Turn on the lights please"
        await session.send_client_content(turns={"parts": [{"text": prompt}]})

        async for chunk in session.receive():
            if chunk.server_content:
                if chunk.text is not None:
                    print(chunk.text)
            elif chunk.tool_call:
                function_responses = []
                for fc in tool_call.function_calls:
                    function_response = types.FunctionResponse(
                        id=fc.id,
                        name=fc.name,
                        response={ "result": "ok" } # simple, hard-coded function response
                    )
                    function_responses.append(function_response)

                await session.send_tool_response(function_responses=function_responses)


if __name__ == "__main__":
    asyncio.run(main())

モデルは、単一のプロンプトから複数の関数呼び出しと、出力の連結に必要なコードを生成できます。このコードはサンドボックス環境で実行され、後続の BidiGenerateContentToolCall メッセージを生成します。

非同期関数呼び出し

デフォルトでは、各関数呼び出しの結果が表示されるまで実行は停止するため、順番どおりに処理が行われます。つまり、関数が実行されている間は、モデルの操作を続行できません。

会話をブロックしたくない場合は、関数を非同期で実行するようにモデルに指示できます。

そのためには、まず関数定義に behavior を追加する必要があります。

  # Non-blocking function definitions
  turn_on_the_lights = {"name": "turn_on_the_lights", "behavior": "NON_BLOCKING"} # turn_on_the_lights will run asynchronously
  turn_off_the_lights = {"name": "turn_off_the_lights"} # turn_off_the_lights will still pause all interactions with the model

NON-BLOCKING を使用すると、モデルの操作を続行しながら関数を非同期で実行できます。

次に、scheduling パラメータを使用して、FunctionResponse を受信したときにモデルがどのように動作するかを指定する必要があります。次のいずれかです。

  • 処理を中断して、すぐに取得したレスポンスについて通知する(scheduling="INTERRUPT")、
  • 現在の処理が完了するまで待ちます(scheduling="WHEN_IDLE")。
  • または、何もせずに、その知識を後で会話で使用します(scheduling="SILENT"
# Non-blocking function definitions
  function_response = types.FunctionResponse(
      id=fc.id,
      name=fc.name,
      response={
          "result": "ok",
          "scheduling": "INTERRUPT" # Can also be WHEN_IDLE or SILENT
      }
  )

コードの実行

コード実行は、セッション構成の一部として定義できます。詳細については、コード実行チュートリアルをご覧ください。

import asyncio
from google import genai
from google.genai import types

client = genai.Client(api_key="GEMINI_API_KEY")
model = "gemini-2.0-flash-live-001"

tools = [{'code_execution': {}}]
config = {"response_modalities": ["TEXT"], "tools": tools}

async def main():
    async with client.aio.live.connect(model=model, config=config) as session:
        prompt = "Compute the largest prime palindrome under 100000."
        await session.send_client_content(turns={"parts": [{"text": prompt}]})

        async for chunk in session.receive():
            if chunk.server_content:
                if chunk.text is not None:
                    print(chunk.text)
            
                model_turn = chunk.server_content.model_turn
                if model_turn:
                    for part in model_turn.parts:
                      if part.executable_code is not None:
                        print(part.executable_code.code)

                      if part.code_execution_result is not None:
                        print(part.code_execution_result.output)

if __name__ == "__main__":
    asyncio.run(main())

グラウンディングと Google 検索は、セッション構成の一部として有効にできます。詳しくは、グラウンディング チュートリアルをご覧ください。

import asyncio
from google import genai
from google.genai import types

client = genai.Client(api_key="GEMINI_API_KEY")
model = "gemini-2.0-flash-live-001"

tools = [{'google_search': {}}]
config = {"response_modalities": ["TEXT"], "tools": tools}

async def main():
    async with client.aio.live.connect(model=model, config=config) as session:
        prompt = "When did the last Brazil vs. Argentina soccer match happen?"
        await session.send_client_content(turns={"parts": [{"text": prompt}]})

        async for chunk in session.receive():
            if chunk.server_content:
                if chunk.text is not None:
                    print(chunk.text)

                # The model might generate and execute Python code to use Search
                model_turn = chunk.server_content.model_turn
                if model_turn:
                    for part in model_turn.parts:
                      if part.executable_code is not None:
                        print(part.executable_code.code)

                      if part.code_execution_result is not None:
                        print(part.code_execution_result.output)

if __name__ == "__main__":
    asyncio.run(main())

複数のツールを組み合わせる

Live API 内で複数のツールを組み合わせることができます。

prompt = """
Hey, I need you to do three things for me.

1. Compute the largest prime palindrome under 100000.
2. Then use Google Search to look up information about the largest earthquake in California the week of Dec 5 2024?
3. Turn on the lights

Thanks!
"""

tools = [
    {"google_search": {}},
    {"code_execution": {}},
    {"function_declarations": [turn_on_the_lights, turn_off_the_lights]},
]

config = {"response_modalities": ["TEXT"], "tools": tools}

割り込みの処理

モデルの出力はいつでも中断できます。音声アクティビティ検出(VAD)が中断を検出すると、進行中の生成はキャンセルされ、破棄されます。クライアントにすでに送信された情報だけが、セッション履歴に保持されます。その後、サーバーは中断を報告する BidiGenerateContentServerContent メッセージを送信します。

さらに、Gemini サーバーは保留中の関数呼び出しを破棄し、キャンセルされた呼び出しの ID を記載した BidiGenerateContentServerContent メッセージを送信します。

async for response in session.receive():
    if response.server_content.interrupted is True:
        # The generation was interrupted

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

音声アクティビティ検出(VAD)を構成または無効にできます。

自動 VAD の使用

デフォルトでは、モデルは連続した音声入力ストリームに対して VAD を自動的に実行します。VAD は、設定構成realtimeInputConfig.automaticActivityDetection フィールドで構成できます。

音声ストリームが 1 秒以上一時停止した場合(ユーザーがマイクをオフにした場合など)、キャッシュに保存されている音声をフラッシュするために audioStreamEnd イベントを送信する必要があります。クライアントはいつでも音声データの送信を再開できます。

# example audio file to try:
# URL = "https://storage.googleapis.com/generativeai-downloads/data/hello_are_you_there.pcm"
# !wget -q $URL -O sample.pcm
import asyncio
from pathlib import Path
from google import genai
from google.genai import types

client = genai.Client(api_key="GEMINI_API_KEY")
model = "gemini-2.0-flash-live-001"

config = {"response_modalities": ["TEXT"]}

async def main():
    async with client.aio.live.connect(model=model, config=config) as session:
        audio_bytes = Path("sample.pcm").read_bytes()

        await session.send_realtime_input(
            audio=types.Blob(data=audio_bytes, mime_type="audio/pcm;rate=16000")
        )

        # if stream gets paused, send:
        # await session.send_realtime_input(audio_stream_end=True)

        async for response in session.receive():
            if response.text is not None:
                print(response.text)

if __name__ == "__main__":
    asyncio.run(main())

send_realtime_input を使用すると、API は VAD に基づいて音声に自動的に応答します。send_client_content は順序に従ってモデル コンテキストにメッセージを追加しますが、send_realtime_input は確定的な順序付けを犠牲にして応答性を最適化します。

自動 VAD の構成

VAD アクティビティをより細かく制御するには、次のパラメータを構成します。詳細については、API リファレンスをご覧ください。

from google.genai import types

config = {
    "response_modalities": ["TEXT"],
    "realtime_input_config": {
        "automatic_activity_detection": {
            "disabled": False, # default
            "start_of_speech_sensitivity": types.StartSensitivity.START_SENSITIVITY_LOW,
            "end_of_speech_sensitivity": types.EndSensitivity.END_SENSITIVITY_LOW,
            "prefix_padding_ms": 20,
            "silence_duration_ms": 100,
        }
    }
}

自動 VAD の無効化

または、設定メッセージで realtimeInputConfig.automaticActivityDetection.disabledtrue に設定して、自動 VAD を無効にすることもできます。この構成では、クライアントがユーザーの音声を検出し、適切なタイミングで activityStart メッセージと activityEnd メッセージを送信します。この構成では audioStreamEnd は送信されません。代わりに、ストリームの中断は activityEnd メッセージでマークされます。

config = {
    "response_modalities": ["TEXT"],
    "realtime_input_config": {"automatic_activity_detection": {"disabled": True}},
}

async with client.aio.live.connect(model=model, config=config) as session:
    # ...
    await session.send_realtime_input(activity_start=types.ActivityStart())
    await session.send_realtime_input(
        audio=types.Blob(data=audio_bytes, mime_type="audio/pcm;rate=16000")
    )
    await session.send_realtime_input(activity_end=types.ActivityEnd())
    # ...

トークン数

消費されたトークンの合計数は、返されたサーバー メッセージの usageMetadata フィールドで確認できます。

async for message in session.receive():
    # The server will periodically send messages that include UsageMetadata.
    if message.usage_metadata:
        usage = message.usage_metadata
        print(
            f"Used {usage.total_token_count} tokens in total. Response token breakdown:"
        )
        for detail in usage.response_tokens_details:
            match detail:
                case types.ModalityTokenCount(modality=modality, token_count=count):
                    print(f"{modality}: {count}")

セッション継続時間の延長

最大セッション時間は、次の 2 つのメカニズムを使用して無制限に延長できます。

また、セッションが終了する前に GoAway メッセージが届き、追加の操作を行えます。

コンテキスト ウィンドウの圧縮

セッションを長くして、接続が突然終了しないようにするには、セッション構成の一部として contextWindowCompression フィールドを設定して、コンテキスト ウィンドウ圧縮を有効にします。

ContextWindowCompressionConfig で、スライディング ウィンドウ メカニズムと、圧縮をトリガーするトークン数を構成できます。

from google.genai import types

config = types.LiveConnectConfig(
    response_modalities=["AUDIO"],
    context_window_compression=(
        # Configures compression with default parameters.
        types.ContextWindowCompressionConfig(
            sliding_window=types.SlidingWindow(),
        )
    ),
)

セッションの再開

サーバーが WebSocket 接続を定期的にリセットするときにセッションが終了しないようにするには、設定構成sessionResumption フィールドを構成します。

この構成を渡すと、サーバーは SessionResumptionUpdate メッセージを送信します。このメッセージは、最後の再開トークンを後続の接続の SessionResumptionConfig.handle として渡すことで、セッションを再開するために使用できます。

import asyncio
from google import genai
from google.genai import types

client = genai.Client(api_key="GEMINI_API_KEY")
model = "gemini-2.0-flash-live-001"

async def main():
    print(f"Connecting to the service with handle {previous_session_handle}...")
    async with client.aio.live.connect(
        model=model,
        config=types.LiveConnectConfig(
            response_modalities=["AUDIO"],
            session_resumption=types.SessionResumptionConfig(
                # The handle of the session to resume is passed here,
                # or else None to start a new session.
                handle=previous_session_handle
            ),
        ),
    ) as session:
        while True:
            await session.send_client_content(
                turns=types.Content(
                    role="user", parts=[types.Part(text="Hello world!")]
                )
            )
            async for message in session.receive():
                # Periodically, the server will send update messages that may
                # contain a handle for the current state of the session.
                if message.session_resumption_update:
                    update = message.session_resumption_update
                    if update.resumable and update.new_handle:
                        # The handle should be retained and linked to the session.
                        return update.new_handle

                # For the purposes of this example, placeholder input is continually fed
                # to the model. In non-sample code, the model inputs would come from
                # the user.
                if message.server_content and message.server_content.turn_complete:
                    break

if __name__ == "__main__":
    asyncio.run(main())

セッションが切断される前にメッセージを受信する

サーバーは、現在の接続がまもなく終了することを通知する GoAway メッセージを送信します。このメッセージには、残り時間を示す timeLeft が含まれており、接続が ABORTED として終了する前に追加のアクションを実行できます。

async for response in session.receive():
    if response.go_away is not None:
        # The connection will soon be terminated
        print(response.go_away.time_left)

生成が完了したときにメッセージが届く

サーバーは、モデルがレスポンスを生成し終えたことを通知する generationComplete メッセージを送信します。

async for response in session.receive():
    if response.server_content.generation_complete is True:
        # The generation is complete

メディアの解像度

入力メディアのメディア解像度を指定するには、セッション構成の一部として mediaResolution フィールドを設定します。

from google.genai import types

config = types.LiveConnectConfig(
    response_modalities=["AUDIO"],
    media_resolution=types.MediaResolution.MEDIA_RESOLUTION_LOW,
)

制限事項

プロジェクトを計画する際は、Live API の次の制限事項を考慮してください。

レスポンス モダリティ

セッション構成で設定できるレスポンス モダリティ(TEXT または AUDIO)は、セッションごとに 1 つだけです。両方を設定すると、構成エラー メッセージが表示されます。つまり、テキストまたは音声のいずれかで応答するようにモデルを構成できますが、同じセッションで両方を使用することはできません。

クライアント認証

Live API が提供するのはサーバー間認証のみであるため、クライアントが直接使用することはおすすめしません。クライアントの入力を Live API で安全に認証するには、中間アプリケーション サーバーを経由する必要があります。

セッション継続時間

セッションの圧縮を有効にすると、セッションの継続時間を無制限に延長できます。圧縮なしの場合、音声のみのセッションは 15 分に制限され、音声と動画のセッションは 2 分に制限されます。圧縮なしでこれらの上限を超えると、接続が終了します。

また、セッションの再開を構成して、クライアントが終了したセッションを再開できるようにすることもできます。

コンテキスト ウィンドウ

セッションのコンテキスト ウィンドウの上限は次のとおりです。

サポートされている言語

Live API は次の言語をサポートしています。

言語 BCP-47 コード
ドイツ語(ドイツ) de-DE
英語(オーストラリア) en-AU
英語(英国) en-GB
英語(インド) en-IN
英語(米国) en-US
スペイン語(米国) es-US
フランス語(フランス) fr-FR
ヒンディー語(インド) hi-IN
ポルトガル語(ブラジル) pt-BR
アラビア語(一般) ar-XA
スペイン語(スペイン) es-ES
フランス語(カナダ) fr-CA
インドネシア語(インドネシア) id-ID
イタリア語(イタリア) it-IT
日本語(日本) ja-JP
トルコ語(トルコ) tr-TR
ベトナム語(ベトナム) vi-VN
ベンガル語(インド) bn-IN
グジャラト語(インド) gu-IN
カンナダ語(インド) kn-IN
マラヤーラム語(インド) ml-IN
マラーティー語(インド) mr-IN
タミル語(インド) ta-IN
テルグ語(インド) te-IN
オランダ語(オランダ) nl-NL
韓国語(韓国) ko-KR
北京語(中国) cmn-CN
ポーランド語(ポーランド) pl-PL
ロシア語(ロシア) ru-RU
タイ語(タイ) th-TH

サードパーティとの連携

ウェブアプリとモバイルアプリのデプロイでは、次のオプションを検討できます。

次のステップ