Gemini Live API を使用したライブ文字起こし

Gemini Live API は、gemini-3.5-transcribe-live モデルを使用して、低レイテンシのリアルタイム音声文字変換をサポートしています。WebSocket 経由で Live API に接続するか、Google Gen AI SDK を使用することで、継続的な音声入力をストリーミングし、音声が発生するたびに増分でリアルタイムのテキスト文字起こしを受け取ることができます。

Gemini Live API を活用することで、AgoraFishjamLiveKitPipecatVercelVision Agents などのデベロッパー プラットフォームを使用すると、デベロッパーは高性能の音声駆動型インターフェースを簡単に構築してデプロイできます。これらのプラットフォームは、複雑なリアルタイム メディア ストリーミング インフラストラクチャを舞台裏で管理するため、デベロッパーはユーザー エクスペリエンスの作成に専念できます。

ライブ対応のエージェントとライブ文字起こし

どちらも Live API の双方向ストリーミング接続を使用しますが、音声文字変換は会話エージェントではなく、低レイテンシの専用音声認識パイプラインとして動作します。

機能 ライブ対応のエージェント 音声文字変換
主要な役割 会話を聞き取り、推論し、応答する会話アシスタント。 着信音声を文字起こしするリアルタイム音声文字変換パイプライン。
レスポンスのモダリティ 音声とテキスト(response_modalities=["AUDIO"])。 ストリーミング テキストの文字起こし(response_modalities=["TEXT"])。
対話のトーン 一時停止の検出と割り込みを含むターンベースのダイアログ。 話者の発話に合わせて継続的にストリーム処理を行います。
サポートされる機能 関数呼び出し、Google 検索、システム指示。 音声バイアス(custom_vocabulary)、言語検出、手動 VAD とハイブリッド VAD、スマート文字起こし。
入力ストリーム マルチモーダル: 音声、動画、画像、テキスト。 音声入力(RAW 16 ビット PCM)。

始める

次の例は、gemini-3.5-transcribe-live で双方向ストリーミング セッションを開き、リアルタイムの文字起こしを受信する方法を示しています。

Python

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

client = genai.Client()
model = "gemini-3.5-transcribe-live"

config = types.LiveConnectConfig(
    response_modalities=["TEXT"],
    input_audio_transcription=types.AudioTranscriptionConfig(
        language_codes=[],  # Automatic language detection
    ),
)

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

        # Receive transcription events
        async for response in session.receive():
            server_content = response.server_content
            if server_content and server_content.input_transcription:
                print("Transcript:", server_content.input_transcription.text)

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

JavaScript

import { GoogleGenAI, Modality } from '@google/genai';

const ai = new GoogleGenAI({});
const model = 'gemini-3.5-transcribe-live';

const config = {
  responseModalities: [Modality.TEXT],
  inputAudioTranscription: {
    languageCodes: [], // Automatic language detection
  },
};

async function main() {
  const session = await ai.live.connect({
    model: model,
    config: config,
    callbacks: {
      onopen: () => console.log('Connected to Live Transcription'),
      onmessage: (message) => {
        const content = message.serverContent;
        if (content?.inputTranscription) {
          console.log('Transcript:', content.inputTranscription.text);
        }
      },
      onerror: (e) => console.error('Error:', e.message),
      onclose: (e) => console.log('Connection closed:', e.reason),
    },
  });
}

main();

WebSocket

const API_KEY = "YOUR_API_KEY";
const MODEL_NAME = "gemini-3.5-transcribe-live";
const WS_URL = `wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent?key=${API_KEY}`;

const websocket = new WebSocket(WS_URL);

websocket.onopen = () => {
  console.log('WebSocket connected');

  const setupMessage = {
    setup: {
      model: `models/${MODEL_NAME}`,
      generationConfig: {
        responseModalities: ['TEXT'],
      },
      inputAudioTranscription: {
        languageCodes: []
      }
    }
  };
  websocket.send(JSON.stringify(setupMessage));
};

websocket.onmessage = (event) => {
  const response = JSON.parse(event.data);
  const content = response.serverContent;
  if (content?.inputTranscription) {
    console.log('Transcript:', content.inputTranscription.text);
  }
};

暫定的な音声文字変換と最終的な音声文字変換

音声が Live API にストリーミングされると、サーバーは server_content 内で 2 つの補完的な文字起こしフィールドを出力します。

  • interim_input_transcription: 発話者が話している間に更新される、低レイテンシの投機的な部分仮説。これらの部分的な更新は、遅延を最小限に抑えて迅速に行われます。interim_input_transcription を使用して、レスポンシブなライブ UI 字幕またはプレビュー字幕をレンダリングします。
  • input_transcription: 発話者が一時停止したとき、ターンが完了したとき、または発話が確定したときに発行される最終的な文字起こし。このテキストは、発話セグメントのモデルによる信頼できる文字起こしを表します。スマート文字起こしモードでは、クリーンアップされ、フォーマットされたレスポンスも含まれます。

次の例は、ストリーミングの中間部分を表示し、最終的な文字起こしをコミットする方法を示しています。

Python

async def receive_transcripts(session):
    async for response in session.receive():
        server_content = response.server_content
        if not server_content:
            continue

        # Real-time interim hypothesis (updates dynamically as user speaks)
        if server_content.interim_input_transcription:
            interim_text = server_content.interim_input_transcription.text
            print(f"\r[Interim] {interim_text}", end="", flush=True)

        # Finalized transcript (emitted on speech completion)
        if server_content.input_transcription:
            final_text = server_content.input_transcription.text
            print(f"\n[Final] {final_text}")

JavaScript

onmessage: (message) => {
  const content = message.serverContent;
  if (!content) return;

  if (content.interimInputTranscription) {
    // Update live subtitle preview on screen
    renderInterimPreview(content.interimInputTranscription.text);
  }

  if (content.inputTranscription) {
    // Append final committed transcript to chat history
    commitFinalTranscript(content.inputTranscription.text);
  }
};

WebSocket

websocket.onmessage = (event) => {
  const response = JSON.parse(event.data);
  const content = response.serverContent;
  if (content?.interimInputTranscription) {
    console.log('[Interim]:', content.interimInputTranscription.text);
  }
  if (content?.inputTranscription) {
    console.log('[Final]:', content.inputTranscription.text);
  }
};

音声を送信する

アクティブな接続を介して、音声チャンクを RAW 16 ビット PCM 音声としてストリーミングします。

  • 音声形式: RAW 16 ビット PCM、16kHz(モノラル、リトル エンディアン)。
  • チャンクサイズ: 音声を 100 ミリ秒(1,024 ~ 2,048 フレーム)のチャンクで送信します。
  • MIME タイプ: audio/pcm;rate=16000(または一致するサンプルレート)。

Python

# Stream a raw PCM audio chunk
await session.send_realtime_input(
    audio=types.Blob(
        data=audio_chunk_bytes,
        mime_type="audio/pcm;rate=16000"
    )
)

# Signal the end of the audio stream when finished
await session.send_realtime_input(audio_stream_end=True)

JavaScript

// Send base64-encoded PCM audio chunk
session.sendRealtimeInput({
  audio: {
    data: audioChunkBase64,
    mimeType: 'audio/pcm;rate=16000'
  }
});

// Signal stream end
session.sendRealtimeInput({
  audioStreamEnd: true
});

WebSocket

// Send base64-encoded PCM audio chunk
websocket.send(JSON.stringify({
  realtimeInput: {
    audio: {
      data: audioChunkBase64,
      mimeType: 'audio/pcm;rate=16000'
    }
  }
}));

// Signal stream end
websocket.send(JSON.stringify({
  realtimeInput: {
    audioStreamEnd: true
  }
}));

文字起こし機能

自動言語検出

デフォルトでは、language_codes を省略するか language_codes=[] を設定すると、言語の自動識別が有効になります。このモデルは、多言語の会話やコード切り替えなど、発話全体で音声言語を動的に検出します。

Python

config = types.LiveConnectConfig(
    response_modalities=["TEXT"],
    input_audio_transcription=types.AudioTranscriptionConfig(
        language_codes=[],
    ),
)

JavaScript

const config = {
  responseModalities: [Modality.TEXT],
  inputAudioTranscription: {
    languageCodes: [],
  },
};

WebSocket

const setupMessage = {
  setup: {
    model: 'models/gemini-3.5-transcribe-live',
    generationConfig: {
      responseModalities: ['TEXT'],
    },
    inputAudioTranscription: {
      languageCodes: [],
    },
  },
};
websocket.send(JSON.stringify(setupMessage));

具体的な言語のヒント

特定の言語に認識を偏らせるには、明示的な BCP-47 言語コード(スペイン語の場合は ["es-ES"]、フランス語の場合は ["fr-FR"] など)を指定します(サポートされている言語をご覧ください)。

Python

config = types.LiveConnectConfig(
    response_modalities=["TEXT"],
    input_audio_transcription=types.AudioTranscriptionConfig(
        language_codes=["es-ES"],
    ),
)

JavaScript

const config = {
  responseModalities: [Modality.TEXT],
  inputAudioTranscription: {
    languageCodes: ['es-ES'],
  },
};

WebSocket

const setupMessage = {
  setup: {
    model: 'models/gemini-3.5-transcribe-live',
    generationConfig: {
      responseModalities: ['TEXT'],
    },
    inputAudioTranscription: {
      languageCodes: ['es-ES'],
    },
  },
};
websocket.send(JSON.stringify(setupMessage));

カスタム語彙のバイアス

custom_vocabulary に最大 1,000 個のフレーズ、固有名詞、ブランド名、技術用語のリストを指定して、特定の用語に音声認識をバイアスします(通常、100 個までの用語で最適な結果が得られます)。

Python

config = types.LiveConnectConfig(
    response_modalities=["TEXT"],
    input_audio_transcription=types.AudioTranscriptionConfig(
        language_codes=[],
        custom_vocabulary=["Gemini", "Kubernetes", "BigQuery"],
    ),
)

JavaScript

const config = {
  responseModalities: [Modality.TEXT],
  inputAudioTranscription: {
    languageCodes: [],
    customVocabulary: ['Gemini', 'Kubernetes', 'BigQuery'],
  },
};

WebSocket

const setupMessage = {
  setup: {
    model: 'models/gemini-3.5-transcribe-live',
    generationConfig: {
      responseModalities: ['TEXT'],
    },
    inputAudioTranscription: {
      languageCodes: [],
      customVocabulary: ['Gemini', 'Kubernetes', 'BigQuery'],
    },
  },
};
websocket.send(JSON.stringify(setupMessage));

スマート文字起こし

input_audio_transcriptionmode パラメータを使用して、文字起こし出力の形式を構成します。

  • VERBATIM(デフォルト): 発言された内容をそのまま文字起こしし、フィラー(「えー」、「あー」、「みたいな」など)、繰り返し、言い直しをそのまま残します。
  • SMART(スマート文字起こし): 文字起こしを読みやすくするために、クリーンアップして構造化します。

    • 言い淀みの削除: つなぎ言葉、どもり、言い直しを削除します。
    • インライン自己修正: 発話された修正を自然に解決します。
    • 構造化された書式設定: リスト、箇条書き、番号、日付、段落区切りを自動的に書式設定します。
    • 文法と大文字 / 小文字の区別: 自然な大文字 / 小文字の区別と句読点の修正を適用します。

Python

config = types.LiveConnectConfig(
    response_modalities=["TEXT"],
    input_audio_transcription=types.AudioTranscriptionConfig(
        mode="SMART",
    ),
)

JavaScript

const config = {
  responseModalities: [Modality.TEXT],
  inputAudioTranscription: {
    mode: 'SMART',
  },
};

WebSocket

const setupMessage = {
  setup: {
    model: 'models/gemini-3.5-transcribe-live',
    generationConfig: {
      responseModalities: ['TEXT'],
    },
    inputAudioTranscription: {
      mode: 'SMART',
    },
  },
};
websocket.send(JSON.stringify(setupMessage));

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

自動 VAD(デフォルト)

デフォルトでは、サーバーサイドの自動音声検出により、話者が発言を開始または終了したタイミングが検出されます。

ハイブリッド VAD

ハイブリッド VAD は、サーバーサイドの自動音声開始検出とクライアントサイドの音声終了検出を組み合わせて、遅延のないターン終了を実現します。

  1. サーバーサイドの自動 VAD は有効なままで、プレフィックス音声パディングを使用して音声の開始を正確に検出し、先頭の単語が切り捨てられるのを防ぎます。
  2. クライアントサイドの VAD が無音を検出する: ローカルのオンデバイス VAD が発話者の発話停止を検出すると、クライアントは直ちに audio_stream_end 信号を送信します。
  3. 高速の最終処理: サーバーは audio_stream_end を即時のターン最終処理プロンプトとして扱い、デフォルトのサーバーサイドの無音待機時間をバイパスして、最小限のレイテンシで最終処理された文字起こしを返します。
  4. フォールバック: クライアント VAD がトリガーに失敗した場合、サーバーサイド VAD が自動フォールバックとして機能します。

Python

config = types.LiveConnectConfig(
    response_modalities=["TEXT"],
    input_audio_transcription=types.AudioTranscriptionConfig(),
)

async with client.aio.live.connect(model=model, config=config) as session:
    # Stream audio chunks...
    await session.send_realtime_input(
        audio=types.Blob(data=chunk, mime_type="audio/pcm;rate=16000")
    )

    # When client-side VAD detects end of speech, send audio_stream_end:
    await session.send_realtime_input(audio_stream_end=True)

JavaScript

const config = {
  responseModalities: [Modality.TEXT],
  inputAudioTranscription: {},
};

// Stream audio...
session.sendRealtimeInput({
  audio: { data: chunkBase64, mimeType: 'audio/pcm;rate=16000' }
});

// When client VAD detects end of speech, send audioStreamEnd:
session.sendRealtimeInput({
  audioStreamEnd: true
});

WebSocket

const setupMessage = {
  setup: {
    model: 'models/gemini-3.5-transcribe-live',
    generationConfig: {
      responseModalities: ['TEXT'],
    },
    inputAudioTranscription: {},
  },
};
websocket.send(JSON.stringify(setupMessage));

// Stream audio...
websocket.send(JSON.stringify({
  realtimeInput: {
    audio: { data: chunkBase64, mimeType: 'audio/pcm;rate=16000' }
  }
}));

// When client VAD detects end of speech, send audioStreamEnd:
websocket.send(JSON.stringify({
  realtimeInput: {
    audioStreamEnd: true
  }
}));

手動 VAD(プッシュ ツー トーク)

トランシーバー インターフェースまたはプッシュ トゥ トーク ボタンの場合、自動 VAD を完全に無効にし、activity_startactivity_end を使用してターン境界を明示的に制御します。

Python

config = types.LiveConnectConfig(
    response_modalities=["TEXT"],
    realtime_input_config=types.RealtimeInputConfig(
        automatic_activity_detection=types.AutomaticActivityDetection(
            disabled=True
        )
    ),
    input_audio_transcription=types.AudioTranscriptionConfig(),
)

async with client.aio.live.connect(model=model, config=config) as session:
    # Button pressed: signal speech start
    await session.send_realtime_input(activity_start=types.ActivityStart())

    # Stream audio chunks...
    await session.send_realtime_input(audio=types.Blob(data=chunk, mime_type="audio/pcm;rate=16000"))

    # Button released: signal speech end
    await session.send_realtime_input(activity_end=types.ActivityEnd())

JavaScript

const config = {
  responseModalities: [Modality.TEXT],
  realtimeInputConfig: {
    automaticActivityDetection: {
      disabled: true,
    },
  },
  inputAudioTranscription: {},
};

// Signal speech start
session.sendRealtimeInput({ activityStart: {} });

// Stream audio...

// Signal speech end
session.sendRealtimeInput({ activityEnd: {} });

WebSocket

const setupMessage = {
  setup: {
    model: 'models/gemini-3.5-transcribe-live',
    generationConfig: {
      responseModalities: ['TEXT'],
    },
    realtimeInputConfig: {
      automaticActivityDetection: {
        disabled: true,
      },
    },
    inputAudioTranscription: {},
  },
};
websocket.send(JSON.stringify(setupMessage));

// Button pressed: signal speech start
websocket.send(JSON.stringify({
  realtimeInput: {
    activityStart: {},
  },
}));

// Stream audio...
websocket.send(JSON.stringify({
  realtimeInput: {
    audio: { data: chunkBase64, mimeType: 'audio/pcm;rate=16000' },
  },
}));

// Button released: signal speech end
websocket.send(JSON.stringify({
  realtimeInput: {
    activityEnd: {},
  },
}));

クライアント アプリケーションのエフェメラル トークン

クライアントからサーバーへのアプリケーション(マイクから直接ストリーミングするモバイルアプリやウェブアプリなど)の場合は、エフェメラル トークンを使用して、クライアント コードで API キーが公開されないようにします。

クライアント接続を開始する前に、サーバーで制約付きの短命トークンを作成します。

Python

import datetime
from google import genai

client = genai.Client()
expire_time = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(minutes=30)

token = client.auth_tokens.create(
    config={
        "uses": 1,
        "expire_time": expire_time,
        "live_connect_constraints": {
            "model": "gemini-3.5-transcribe-live",
            "config": {
                "response_modalities": ["TEXT"],
                "input_audio_transcription": {
                    "language_codes": [],
                },
            },
        },
    }
)

JavaScript

import { GoogleGenAI } from '@google/genai';

const client = new GoogleGenAI({});
const expireTime = new Date(Date.now() + 30 * 60 * 1000).toISOString();

const token = await client.authTokens.create({
  config: {
    uses: 1,
    expireTime: expireTime,
    liveConnectConstraints: {
      model: 'gemini-3.5-transcribe-live',
      config: {
        responseModalities: ['TEXT'],
        inputAudioTranscription: {
          languageCodes: [],
        },
      },
    },
  },
});

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/auth_tokens" \
  -H "x-goog-api-key: ${GEMINI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "uses": 1,
    "expireTime": "YYYY-MM-DDTHH:MM:SSZ",
    "liveConnectConstraints": {
      "model": "models/gemini-3.5-transcribe-live",
      "config": {
        "responseModalities": ["TEXT"],
        "inputAudioTranscription": {
          "languageCodes": []
        }
      }
    }
  }'

サポートされている言語

Gemini 3.5 Transcribe Live では、次の言語と BCP-47 言語コードがサポートされています。

言語 BCP-47 コード 言語 BCP-47 コード
アフリカーンス語 af-ZA 日本語 ja-JP
アムハラ語 am-ET ジャワ語 jv-ID
アラビア語(エジプト) ar-EG カーボベルデ語 kea-CV
アルメニア語 hy-AM カンナダ語 kn-IN
アッサム語 as-IN カザフ語 kk-KZ
アゼルバイジャン語 az-AZ 韓国語 ko-KR
ベラルーシ語 be-BY キルギス語 ky-KG
ベンガル語(バングラデシュ) bn-BD ラトビア語 lv-LV
ベンガル語(インド) bn-IN リンガラ語 ln-CD
ボスニア語 bs-BA リトアニア語 lt-LT
ブルガリア語 bg-BG マケドニア語 mk-MK
ブルガリア語(アルーマニア語) rup-BG マレー語 ms-MY
ビルマ語 my-MM マラヤーラム語 ml-IN
広東語(繁体) yue-Hant-HK マルタ語 mt-MT
カタルーニャ語 ca-ES 標準中国語(簡体) cmn-Hans-CN
セブアノ語 ceb マラーティー語 mr-IN
中央クメール語 km-KH モンゴル語 mn-MN
クロアチア語 hr-HR ネパール語 ne-NP
チェコ語 cs-CZ ノルウェー語 nb-NO
デンマーク語 da-DK オリヤ語 or-IN
オランダ語 nl-NL ポーランド語 pl-PL
英語(英国) en-GB ポルトガル語(ブラジル) pt-BR
英語(インド) en-IN ポルトガル語(ポルトガル) pt-PT
英語(米国) en-US パンジャブ語 pa-IN
エストニア語 et-EE パンジャブ語(グルムキー文字) pa-Guru-IN
ペルシア語 fa-IR ルーマニア語 ro-RO
フィリピン語 fil-PH ロシア語 ru-RU
フィンランド語 fi-FI セルビア語 sr-RS
フランス語 fr-FR シンド語(アラビア文字) sd-Arab-IN
ガリシア語 gl-ES スロバキア語 sk-SK
ジョージア語 ka-GE スロベニア語 sl-SI
ドイツ語 de-DE スペイン語(ラテンアメリカ) es-419
ギリシャ語 el-GR スペイン語(米国) es-US
グジャラート語 gu-IN スワヒリ語(ケニア) sw-KE
ハウサ語 ha-NG スウェーデン語 sv-SE
ヘブライ語 he-IL タジク語 tg-TJ
ヒンディー語 hi-IN テルグ語 te-IN
ハンガリー語 hu-HU タイ語 th-TH
アイスランド語 is-IS トルコ語 tr-TR
インド英語 en-IN ウクライナ語 uk-UA
インドネシア語 id-ID ウズベク語 uz-UZ
イタリア語 it-IT ベトナム語 vi-VN

パラメータ リファレンス

input_audio_transcriptionrealtime_input_config のフィールドを使用して、リアルタイム文字起こしを構成します。

パラメータ 説明
language_codes 文字列の配列 BCP-47 言語コード(例: ["en-US"])。省略または空([])の場合、モデルは言語を自動的に検出し、多言語音声処理を行います。
custom_vocabulary 文字列の配列 音声認識のバイアスをかけるためのカスタム用語、頭字語、ブランド名、固有名詞(最大 1,000 個)。
mode 文字列 文字起こしモード: "VERBATIM"(デフォルト)または "SMART"(スマート文字起こし)。"SMART" に設定すると、モデルはフィラーを削除し、リストの形式を整え、言い淀みを修正します。
automatic_activity_detection.disabled ブール値 true に設定すると、音声検出の自動検出が無効になり、activityStart シグナルと activityEnd シグナルを手動で送信します。

サーバー レスポンス フィールド

フィールド 説明
server_content.interim_input_transcription ユーザーが話している間、低遅延の中間部分転写仮説が継続的に出力されます。
server_content.input_transcription 発話ターンが終了したときに発行される、最終的な信頼できる入力文字起こし。

制限事項

  • セッション継続時間: ライブ文字起こしセッションは、最大 10 分間の連続ストリーミングをサポートします。
  • 話者ダイアライゼーション: ライブ ストリーミング セッションでは、話者ダイアライゼーションはサポートされていません。話者ダイアライゼーションの場合は、非ストリーミングの音声文字変換エンドポイントを使用します。
  • 単語レベルのタイムスタンプ: Live API では単語レベルのタイムスタンプはサポートされていません。Live API は、発話レベルのタイムスタンプ(interim_input_transcriptioninput_transcription)を出力します。
  • カスタム語彙: custom_vocabulary で最大 1,000 個の用語を指定できますが、通常は 100 個までの用語で最適な結果が得られます。
  • モードの互換性: スマート文字起こし("mode": "SMART")では、フィラーワードが削除され、インテント認識テキストがフォーマットされますが、単語アノテーションと組み合わせることはできません。

次のステップ