使用 Gemini Live API 进行实时转写

Gemini Live API 支持使用 gemini-3.5-transcribe-live 模型进行低延迟的实时语音转文字转写。通过 WebSockets 连接到 Live API 或使用 Google Gen AI SDK,您可以流式传输连续的音频输入,并在说话时接收增量式实时转写文本。

借助 Gemini Live API,AgoraFishjamLiveKitPipecatVercelVision Agents 等开发者平台可让开发者轻松构建和部署高性能的语音驱动型界面。这些平台可在后台管理复杂的实时媒体流式传输基础设施,让开发者能够完全专注于打造用户体验。

人工客服与实时转写

虽然两者都使用 Live API 双向流式传输连接,但实时转写作为专用的低延迟语音识别流水线运行,而不是对话式代理。

功能 在线客服人员 实时转写
主要作用 能够聆听、推理并回答问题的对话式助理。 一种实时语音转文字流水线,用于转写传入的音频。
回答模态 口述音频和文字 (response_modalities=["AUDIO"])。 流式文本转写 (response_modalities=["TEXT"])。
互动样式 基于回合的对话,支持检测暂停和中断。 在说话人说话时进行连续的流处理。
支持的功能 函数调用、Google 搜索、系统指令。 语音偏向 (custom_vocabulary)、语言检测、手动和混合 VAD、智能转写。
输入流 多模态:音频、视频、图片、文本。 音频输入(原始 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 中发出两个互补的转写字段:

  • interim_input_transcription:低延迟、推测性部分假设,在说话者积极说话时更新。这些部分更新会快速进行,延迟时间极短。使用 interim_input_transcription 渲染自适应实时界面字幕或预览字幕。
  • 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);
  }
};

发送音频

通过有效连接以原始 16 位 PCM 音频格式传输音频块。

  • 音频格式:16 kHz 原始 16 位 PCM(单声道,小端字节序)。
  • 块大小:以 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));

自定义词汇偏向

提供最多 1,000 个短语、专有名词、品牌名称或技术术语的列表(以 custom_vocabulary 为单位),以使语音识别偏向特定术语(通常最多使用 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_transcription 中的 mode 参数配置转写输出格式:

  • 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: {},
  },
}));

客户端应用中的临时令牌

对于客户端到服务器的应用(例如直接从麦克风进行流式传输的移动应用或 Web 应用),请使用临时令牌,以避免在客户端代码中公开您的 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 Kabuverdianu 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 可停用自动语音活动检测,并手动发送 activityStartactivityEnd 信号。

服务器响应字段

字段 说明
server_content.interim_input_transcription 在用户积极说话时持续发出的低延迟临时部分转写假设。
server_content.input_transcription 在语音轮次结束时发出的最终权威输入转写。

限制

  • 会话时长:实时转写会话支持长达 10 分钟的持续流式传输。
  • 发言者区分:直播会话不支持发言者区分。对于说话人日记,请使用非流式 Audio transcription 端点。
  • 字词级时间戳:Live API 不支持字词级时间戳。Live API 会发出话语级时间戳(interim_input_transcriptioninput_transcription)。
  • 自定义词汇:您可以在 custom_vocabulary 中提供最多 1,000 个字词,但通常最多 100 个字词就能获得最佳效果。
  • 模式兼容性:智能转写 ("mode": "SMART") 会移除填充词并设置意图感知文本的格式,但无法与字词注释结合使用。

后续步骤