Transcrição em tempo real com a API Gemini Live

A API Gemini Live oferece suporte à transcrição de fala em texto em tempo real e com baixa latência usando o modelo gemini-3.5-transcribe-live. Ao se conectar à API Live por WebSockets ou usar o SDK de IA generativa do Google, você pode transmitir entrada de áudio contínua e receber transcrições de texto incrementais em tempo real à medida que a fala ocorre.

Ao aproveitar a API Gemini Live, plataformas de desenvolvedores como Agora, Fishjam, LiveKit, Pipecat, Vercel e Vision Agents permitem que os desenvolvedores criem e implantem interfaces de alta performance controladas por voz com facilidade. Essas plataformas gerenciam uma infraestrutura complexa de streaming de mídia em tempo real nos bastidores, permitindo que os desenvolvedores se concentrem totalmente na criação da experiência do usuário.

Atendente x transcrição instantânea

Embora ambos usem a conexão de streaming bidirecional da API Live, a Transcrição instantânea funciona como um pipeline de reconhecimento de fala dedicado e de baixa latência, em vez de um agente de conversa.

Recurso Agente em tempo real Transcrição em tempo real
Função principal Assistente de conversa que ouve, raciocina e responde. Pipeline de voz em texto em tempo real que transcreve o áudio recebido.
Modalidade de resposta Áudio falado e texto (response_modalities=["AUDIO"]). Transcrição de texto por streaming (response_modalities=["TEXT"]).
Estilo de interação Diálogo por turnos com detecção de pausas e interrupções. Processamento contínuo de streams enquanto o falante fala.
Recursos compatíveis Chamada de função, Pesquisa Google, instruções do sistema. Preferência de fala (custom_vocabulary), detecção de idioma, VAD manual e híbrido, transcrição inteligente.
Fluxo de entrada Multimodal: áudio, vídeo, imagens, texto. Entrada de áudio (PCM bruto de 16 bits).

Primeiros passos

Os exemplos a seguir mostram como abrir uma sessão de streaming bidirecional com gemini-3.5-transcribe-live e receber transcrições em tempo real.

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();

WebSockets

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);
  }
};

Transcrição provisória e finalizada

À medida que o áudio é transmitido para a API Live, o servidor emite dois campos de transcrição complementares em server_content:

  • interim_input_transcription: hipóteses parciais especulativas de baixa latência atualizadas enquanto o falante está falando. Essas atualizações parciais ocorrem rapidamente com atraso mínimo. Use interim_input_transcription para renderizar legendas responsivas da interface dinâmica ou prévias de legendas.
  • input_transcription: a transcrição finalizada emitida quando o falante faz uma pausa, o turno termina ou a fala é finalizada. Depois de emitido, esse texto representa a transcrição oficial do modelo desse segmento de fala. No modo de transcrição inteligente, isso inclui a resposta limpa e formatada.

O exemplo a seguir demonstra como mostrar resultados parciais provisórios de streaming e confirmar transcrições finais:

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);
  }
};

WebSockets

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);
  }
};

Enviando áudio

Transmita partes de áudio pela conexão ativa como áudio PCM bruto de 16 bits.

  • Formato de áudio:PCM bruto de 16 bits a 16 kHz (mono, little endian).
  • Tamanho do bloco:envie áudio em blocos de 100 ms (1.024 a 2.048 frames).
  • Tipo MIME:audio/pcm;rate=16000 (ou a taxa de amostragem correspondente).

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
});

WebSockets

// 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
  }
}));

Recursos de transcrição

Detecção automática de idioma

Por padrão, omitir language_codes ou definir language_codes=[] ativa a identificação automática de idioma. O modelo detecta dinamicamente o idioma falado em todas as declarações, incluindo conversas multilíngues e troca de código.

Python

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

JavaScript

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

WebSockets

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

Dica de idioma específico

Forneça códigos de idioma BCP-47 explícitos (por exemplo, ["es-ES"] para espanhol ou ["fr-FR"] para francês) para direcionar o reconhecimento a idiomas específicos (consulte Idiomas compatíveis).

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'],
  },
};

WebSockets

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

Bias de vocabulário personalizado

Forneça uma lista de até 1.000 frases, substantivos próprios, nomes de marcas ou termos técnicos em custom_vocabulary para direcionar o reconhecimento de fala a uma terminologia específica. Os melhores resultados geralmente são alcançados com até 100 termos.

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'],
  },
};

WebSockets

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

Transcrição inteligente

Configure a formatação da saída de transcrição usando o parâmetro mode em input_audio_transcription:

  • VERBATIM (padrão): produz uma transcrição literal exata de tudo o que foi falado, preservando palavras de preenchimento brutas ("um", "ã", "tipo"), repetições e falsos inícios.
  • SMART (Transcrição inteligente): limpa e estrutura a transcrição para facilitar a leitura:

    • Remoção de disfluências: remove palavras desnecessárias, gagueira e falsos inícios.
    • Autocorreções inline: resolvem correções faladas naturalmente.
    • Formatação estruturada: formata automaticamente listas, marcadores, números, datas e quebras de parágrafo.
    • Gramática e uso de maiúsculas: aplica capitalização natural e revisão de pontuação.

Python

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

JavaScript

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

WebSockets

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

Estratégias de detecção de atividade de voz (VAD)

VAD automático (padrão)

Por padrão, a detecção automática de atividade de voz do lado do servidor detecta quando um falante começa e para de falar.

VAD híbrido

O VAD híbrido combina a detecção automática de início de fala do lado do servidor com a detecção de fim de fala do lado do cliente para finalização de turnos com latência zero:

  1. A VAD automática do lado do servidor permanece ativada para detectar com precisão o início da fala com padding de áudio de prefixo, evitando o truncamento da primeira palavra.
  2. A VAD do lado do cliente detecta o silêncio: quando uma VAD local no dispositivo detecta que o falante parou de falar, o cliente envia um sinal audio_stream_end imediatamente.
  3. Finalização rápida: o servidor trata audio_stream_end como um comando imediato de finalização de turno, ignorando o tempo de espera de silêncio padrão do lado do servidor e retornando a transcrição finalizada com latência mínima.
  4. Substituição: se a VAD do cliente não for acionada, a VAD do lado do servidor vai funcionar como uma substituição automática.

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
});

WebSockets

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 manual (falar para ativar)

Para interfaces de walkie-talkie ou botões push-to-talk, desative totalmente a VAD automática e controle os limites de turno explicitamente usando activity_start e activity_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: {} });

WebSockets

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

Tokens temporários em aplicativos cliente

Para aplicativos cliente-servidor (como apps para dispositivos móveis ou da Web que transmitem diretamente de um microfone), use tokens efêmeros para evitar expor sua chave de API no código do cliente.

Crie um token efêmero restrito no seu servidor antes de iniciar a conexão do cliente:

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": []
        }
      }
    }
  }'

Idiomas compatíveis

Os seguintes idiomas e códigos de idioma BCP-47 são compatíveis com o Gemini 3.5 Transcribe Live:

Idioma Código BCP-47 Idioma Código BCP-47
Africâner af-ZA Japonês ja-JP
Amárico am-ET Javanês jv-ID
Árabe (Egito) ar-EG Kabuverdianu kea-CV
Armênio hy-AM Canarês kn-IN
Assamês as-IN Cazaque kk-KZ
Azerbaijano az-AZ Coreano ko-KR
Bielorrusso be-BY Quirguiz ky-KG
Bengali (Bangladesh) bn-BD Letão lv-LV
Bengali (Índia) bn-IN Lingala ln-CD
Bósnio bs-BA Lituano lt-LT
Búlgaro bg-BG Macedônio mk-MK
Búlgaro (aromaniano) rup-BG Malaio ms-MY
Birmanês my-MM Malaiala ml-IN
Cantonês (tradicional) yue-Hant-HK Maltês mt-MT
Catalão ca-ES Chinês mandarim (simplificado) cmn-Hans-CN
Cebuano ceb Marati mr-IN
Khmer central km-KH Mongol mn-MN
Croata hr-HR Nepalês ne-NP
Tcheco cs-CZ Norueguês nb-NO
Dinamarquês da-DK Oriá or-IN
Holandês nl-NL Polonês pl-PL
Inglês (Grã-Bretanha) en-GB Português (Brasil) pt-BR
Inglês (Índia) en-IN Português (Portugal) pt-PT
Inglês (EUA) en-US Punjabi pa-IN
Estoniano et-EE Punjabi (script gurmukhi) pa-Guru-IN
Farsi fa-IR Romeno ro-RO
Filipino fil-PH Russo ru-RU
Finlandês fi-FI Sérvio sr-RS
Francês fr-FR Sindi (escrita árabe) sd-Arab-IN
Galego gl-ES Eslovaco sk-SK
Georgiano ka-GE Esloveno sl-SI
Alemão de-DE Espanhol (América Latina) es-419
Grego el-GR Espanhol (Estados Unidos) es-US
Gujarati gu-IN Suaíli (Quênia) sw-KE
Hauçá ha-NG Sueco sv-SE
Hebraico he-IL Tadjique tg-TJ
Hindi hi-IN Télugo te-IN
Húngaro hu-HU Tailandês th-TH
Islandês is-IS Turco tr-TR
Inglês indiano en-IN Ucraniano uk-UA
Indonésio id-ID Usbeque uz-UZ
Italiano it-IT Vietnamita vi-VN

Referência de parâmetros

Configure a transcrição instantânea usando os campos em input_audio_transcription e realtime_input_config:

Parâmetro Tipo Descrição
language_codes Matriz de strings Códigos de idioma BCP-47 (por exemplo, ["en-US"]). Se omitido ou vazio ([]), o modelo detecta automaticamente o idioma e processa a fala multilíngue.
custom_vocabulary Matriz de strings Até 1.000 termos personalizados, acrônimos, nomes de marcas ou substantivos próprios para influenciar o reconhecimento de fala.
mode String Modo de transcrição: "VERBATIM" (padrão) ou "SMART" (transcrição inteligente). Quando definido como "SMART", o modelo remove palavras desnecessárias, formata listas e corrige disfluências.
automatic_activity_detection.disabled Booleano Defina como true para desativar a detecção automática de atividade de voz e enviar manualmente os sinais activityStart e activityEnd.

Campos de resposta do servidor

Campo Descrição
server_content.interim_input_transcription Hipótese de transcrição parcial provisória de baixa latência emitida continuamente enquanto o usuário fala.
server_content.input_transcription Transcrição de entrada finalizada e confiável emitida quando uma rodada de fala termina.

Limitações

  • Duração da sessão:as sessões de transcrição instantânea oferecem suporte a streaming contínuo por até 10 minutos.
  • Diarização de falantes:não há suporte para esse recurso em sessões de transmissão ao vivo. Para a diarização de falantes, use o endpoint Transcrição de áudio que não é de streaming.
  • Carimbos de data/hora no nível da palavra:eles estão indisponíveis na API Live. A API Live emite carimbos de data/hora no nível do enunciado (interim_input_transcription e input_transcription).
  • Vocabulário personalizado:é possível fornecer até 1.000 termos em custom_vocabulary, mas os melhores resultados geralmente são alcançados com até 100 termos.
  • Compatibilidade de modo:a transcrição inteligente ("mode": "SMART") remove palavras de preenchimento e formata o texto com reconhecimento de intenção, mas não pode ser combinada com anotações de palavras.

A seguir