Convide e ganhe

Como funcionam as recompensas

Compartilhe seu link. Quando um amigo se cadastrar por ele e adicionar saldo, você receberá a recompensa exibida nas recargas posteriores.

Transcrição de Reuniões no Gemini 3.5 Transcribe: Locutores, Timestamps e Vocabulário na Prática

Um guia prático para transformar uma gravação de reunião de 45 minutos em uma transcrição verificada ou base de legendas com o Gemini 3.5 Transcribe: seleção de parâmetros de configuração, divisão correta de arquivos de áudio longos, estruturação de timestamps por palavra com o SDK em Python e execução de controle de qualidade manual.

Conteúdo
Transcrição de Reuniões no Gemini 3.5 Transcribe: Locutores, Timestamps e Vocabulário na Prática

Transformar a gravação em áudio de uma reunião de negócios em um documento de trabalho confiável exige decisões arquiteturais conscientes ao configurar os parâmetros de reconhecimento de voz. No Gemini 3.5 Transcribe, não existe um modo universal no estilo “tudo-em-um”: normalização editorial aprofundada (smart), separação por locutores (diarization_mode), grade temporal no nível de palavras (timestamp_granularities) e léxicos específicos de domínio (custom_vocabulary) representam capacidades de API mutuamente isoladas.

Todo pipeline de processamento deve começar estabelecendo seu objetivo final: você precisa de um bloco de texto conciso e legível para leitura rápida, de uma base estruturada para análises posteriores ou de uma matriz de timestamps exatos para edição de vídeo? Tentar combinar parâmetros mutuamente exclusivos resulta em erros de validação de schema antes mesmo que a requisição seja processada.

Abaixo está um passo a passo prático e completo: como preparar uma gravação de 45 minutos com dois participantes repleta de terminologia técnica, contornar os limites documentados da API, processar ambas as partes utilizando o SDK oficial em Python, montar as estruturas de dados preliminares, verificar e corrigir essas informações confrontando-as com a gravação de áudio e entregar cópias validadas ao redator da ata da reunião ou ao editor de legendas.


Restrições Arquiteturais e Conflitos de Parâmetros

Para ilustrar o pipeline, considere uma sessão de trabalho típica: Alexey (Tech Lead) e Mikhail (Product Manager) passam 45 minutos discutindo a arquitetura de migração e a implantação de serviços sob os nomes de projeto internos DataPulse e CloudForge. A conversa inclui jargões técnicos, estrangeirismos, interrupções rápidas e começos truncados de frases.

Ao planejar uma integração com o Gemini 3.5 Transcribe, é preciso levar em consideração três regras rígidas:

  • Incompatibilidade Entre Vocabulário Personalizado e Metadados Estruturais: O parâmetro custom_vocabulary (que suporta até 1.000 termos, com uma recomendação prática de até 100) não pode ser enviado junto com diarization_mode ou timestamp_granularities. É necessário fazer uma escolha de projeto: confiar no modelo para transcrever nomes de marcas especializados com precisão (abrindo mão dos rótulos automáticos de locutores e dos timestamps) ou solicitar o detalhamento de locutores e alinhamentos temporais enquanto a terminologia técnica é conferida na etapa de pós-processamento.
  • Incompatibilidade Entre o Modo Smart e o Alinhamento Temporal: O modo smart aplica normalização de fala: remove palavras de preenchimento, gagueiras e falsos inícios, reestruturando a sintaxe gramatical. Como os tokens são removidos, agrupados ou reordenados, o modelo não consegue mapear o texto resultante de volta para a linha do tempo do fluxo de áudio subjacente. Por isso, a identificação de locutores e os timestamps por palavra ficam indisponíveis no modo smart. Além disso, esse modo retorna apenas texto contínuo não anotado (output_text) e não extrai automaticamente listas de tarefas (action items).
  • Limite de 30 Minutos para Metadados Avançados: Requisições padrão de transcrição sem anotações detalhadas aceitam arquivos de áudio com até 60 minutos de duração. No entanto, assim que você ativa diarization_mode ou timestamp_granularities, a duração máxima documentada do arquivo cai para 30 minutos. O envio de arquivos que excedam esse limite foge da especificação suportada pela API e não deve ser realizado; gravações longas precisam ser divididas no lado do cliente antes do envio.

Preparando e Dividindo a Gravação de 45 Minutos

Para extrair a diarização e os timestamps por palavra de uma gravação de 45 minutos, o arquivo de origem precisa ser segmentado em blocos estritamente menores que 30 minutos. Em nosso cenário hipotético, dividimos a gravação em dois trechos:

  • Parte 1: 00:00–25:00 (assumido como exatamente 1500.0 segundos);
  • Parte 2: 25:00–45:00 (os 20 minutos restantes, ou 1200.0 segundos).

A marca de 1500.0 segundos é escolhida aqui unicamente para simplificar os cálculos matemáticos deste exemplo. Em ambientes de produção, os cortes devem ser posicionados durante pausas conversacionais naturais entre as falas, e a duração física exata do primeiro segmento deve ser extraída diretamente dos metadados do arquivo de mídia por meio de uma ferramenta de inspeção como o ffprobe.

A divisão do áudio introduz dois desafios críticos de continuidade:

  1. Reinício dos Timestamps no Segundo Segmento: A API processa o segundo segmento como um arquivo totalmente independente, reiniciando seus deslocamentos internos no nível de palavras em 0.000s. Para reconstruir uma linha do tempo contínua para a reunião completa, a duração real do primeiro segmento precisa ser adicionada programaticamente a cada timestamp de palavra extraído do segundo segmento.
  2. Escopo Local dos Rótulos de Locutores: O modelo atribui identificadores como spk_1 e spk_2 de forma independente dentro do escopo de cada chamada de API. O participante designado como spk_1 no primeiro bloco pode receber o rótulo spk_2 no segundo. Mesclar rótulos técnicos idênticos de requisições separadas sem conferência prévia irá misturar as falas dos participantes. Cada bloco exige uma tabela de mapeamento própria, associada aos participantes reais por meio de checagem auditiva pontual.

Variantes de Configuração para Diferentes Tarefas

Os parâmetros de transcrição são configurados no campo transcription_config dentro do dicionário generation_config. Abaixo estão configurações de referência adaptadas a diferentes necessidades operacionais.

Para notas de reunião coesas e normalizadas, sem identificação de locutores ou timestamps (adequado para arquivos integrais com menos de 60 minutos):

generation_config = {
    "transcription_config": {
        "mode": "smart"
    }
}

Para discussões focadas em termos de nicho ou nomes proprietários em que a grafia exata tem prioridade:

generation_config = {
    "transcription_config": {
        "custom_vocabulary": ["DataPulse", "CloudForge", "ClickHouse", "gRPC"]
    }
}

Para gerar atas de reuniões e grades temporais para legendas (sujeito ao limite de áudio de 30 minutos):

generation_config = {
    "transcription_config": {
        "mode": {
            "type": "verbatim",
            "diarization_mode": "speaker",
            "timestamp_granularities": ["word"],
        }
    }
}

Pipeline Completo com o SDK em Python: Processando Duas Partes

Este script é executado antes da escuta do áudio ou da realização de qualquer verificação manual. Ele envia ambos os segmentos via Files API, faz requisições para a Interactions API, extrai as anotações por palavra, valida os timestamps e os identificadores de locutores, desloca a linha do tempo da segunda parte em 1500.0 segundos e grava arquivos de rascunho preliminares:

  • meeting_transcript.txt — um rascunho do diálogo em UTF-8 estruturado por turnos de fala;
  • word_timestamps.json — um array preliminar de timestamps contínuos por palavra voltado para a segmentação de legendas.

Os arquivos gerados por este script são explicitamente rascunhos não verificados, e não registros definitivos. O profissional deve ouvir a gravação, associar os tokens técnicos de locutores às vozes reais (speaker mapping), validar a terminologia técnica (terms) e auditar os deslocamentos de tempo (time offsets). Após concluir essa auditoria, atualize os parâmetros de configuração no código e execute o pipeline novamente ou edite os arquivos de texto diretamente. Somente após esse protocolo de verificação as cópias finais devem ser entregues a um redator de atas ou a um editor de legendas.

O script produz estruturas de dados intermediárias para analistas e editores de vídeo; ele não cria automaticamente listas de tarefas (action items) nem arquivos de legenda formatados no padrão .srt. Os nomes dos participantes e a fronteira de 1500.0 segundos foram definidos aqui apenas para fins demonstrativos dentro deste cenário hipotético.

import json
from google import genai

client = genai.Client()

audio_part1 = client.files.upload(file="meeting_part1.mp3")
audio_part2 = client.files.upload(file="meeting_part2.mp3")

transcription_mode_config = {
    "transcription_config": {
        "mode": {
            "type": "verbatim",
            "diarization_mode": "speaker",
            "timestamp_granularities": ["word"],
        }
    }
}

interaction_part1 = client.interactions.create(
    model="gemini-3.5-transcribe",
    input=[
        {
            "type": "audio",
            "uri": audio_part1.uri,
            "mime_type": audio_part1.mime_type,
        }
    ],
    generation_config=transcription_mode_config,
)

interaction_part2 = client.interactions.create(
    model="gemini-3.5-transcribe",
    input=[
        {
            "type": "audio",
            "uri": audio_part2.uri,
            "mime_type": audio_part2.mime_type,
        }
    ],
    generation_config=transcription_mode_config,
)

def extract_word_annotations(interaction):
    words = []
    for step in getattr(interaction, "steps", []) or []:
        for content in getattr(step, "content", []) or []:
            for annotation in getattr(content, "annotations", []) or []:
                if getattr(annotation, "type", None) == "word_info":
                    words.append(annotation)
    return words

def parse_offset_seconds(offset_val, word_text):
    if offset_val is None or offset_val == "":
        raise ValueError(f"Отсутствует таймкод для слова '{word_text}'. Требуется проверка аудиозаписи.")
    val_str = str(offset_val)
    if val_str.endswith("s"):
        val_str = val_str[:-1]
    try:
        return float(val_str)
    except ValueError:
        raise ValueError(f"Некорректный формат таймкода '{offset_val}' для слова '{word_text}'. Требуется проверка аудиозаписи.")

words_part1 = extract_word_annotations(interaction_part1)
words_part2 = extract_word_annotations(interaction_part2)

if not words_part1 or not words_part2:
    raise ValueError("Один из аудиосегментов не содержит пословных аннотаций. Пустой результат не может считаться успешным.")

part1_offset_seconds = 0.0
part2_offset_seconds = 1500.0

manual_mapping_part1 = {
    "spk_1": "Алексей",
    "spk_2": "Михаил",
}

manual_mapping_part2 = {
    "spk_1": "Михаил",
    "spk_2": "Алексей",
}

unified_word_stream = []

for word in words_part1:
    text = getattr(word, "text", "")
    raw_speaker = getattr(word, "speaker", None)
    if not raw_speaker or raw_speaker not in manual_mapping_part1:
        raise ValueError(f"Неизвестный спикер '{raw_speaker}' в части 1. Требуется ручная верификация по аудио.")
    resolved_speaker = manual_mapping_part1[raw_speaker]
    word_start = parse_offset_seconds(getattr(word, "start_offset", None), text) + part1_offset_seconds
    word_end = parse_offset_seconds(getattr(word, "end_offset", None), text) + part1_offset_seconds
    unified_word_stream.append({
        "text": text,
        "speaker": resolved_speaker,
        "start_seconds": word_start,
        "end_seconds": word_end,
        "part": 1,
    })

for word in words_part2:
    text = getattr(word, "text", "")
    raw_speaker = getattr(word, "speaker", None)
    if not raw_speaker or raw_speaker not in manual_mapping_part2:
        raise ValueError(f"Неизвестный спикер '{raw_speaker}' в части 2. Требуется ручная верификация по аудио.")
    resolved_speaker = manual_mapping_part2[raw_speaker]
    word_start = parse_offset_seconds(getattr(word, "start_offset", None), text) + part2_offset_seconds
    word_end = parse_offset_seconds(getattr(word, "end_offset", None), text) + part2_offset_seconds
    unified_word_stream.append({
        "text": text,
        "speaker": resolved_speaker,
        "start_seconds": word_start,
        "end_seconds": word_end,
        "part": 2,
    })

dialogue_turns = []
current_turn = None

for item in unified_word_stream:
    if current_turn is None or current_turn["speaker"] != item["speaker"] or current_turn["part"] != item["part"]:
        if current_turn is not None:
            dialogue_turns.append(current_turn)
        current_turn = {
            "part": item["part"],
            "speaker": item["speaker"],
            "start_seconds": item["start_seconds"],
            "end_seconds": item["end_seconds"],
            "words": [item["text"]],
        }
    else:
        current_turn["end_seconds"] = item["end_seconds"]
        current_turn["words"].append(item["text"])

if current_turn is not None:
    dialogue_turns.append(current_turn)

def format_timestamp(seconds):
    minutes = int(seconds // 60)
    remaining_seconds = seconds % 60
    return f"{minutes:02d}:{remaining_seconds:06.3f}"

with open("meeting_transcript.txt", "w", encoding="utf-8") as f_transcript:
    for turn in dialogue_turns:
        start_str = format_timestamp(turn["start_seconds"])
        end_str = format_timestamp(turn["end_seconds"])
        speech_text = " ".join(turn["words"])
        f_transcript.write(f"[{start_str} - {end_str}] {turn['speaker']}: {speech_text}\n")

with open("word_timestamps.json", "w", encoding="utf-8") as f_json:
    json.dump(unified_word_stream, f_json, ensure_ascii=False, indent=2)

Exemplo Ilustrativo da Estrutura por Palavra e Zonas de Inspeção

Abaixo está uma representação sintética do fluxo de dados extraído durante uma transição entre locutores.

Nota: Este trecho serve exclusivamente para ilustrar a estrutura dos objetos retornados, não se tratando de um log real de chamada de API. A qualidade real da transcrição depende da acústica, dos microfones e da clareza da dicção.

[Строка 1] [spk_1] (0.100s -> 0.420s) Мы
[Строка 2] [spk_1] (0.450s -> 0.810s) переносим
[Строка 3] [spk_1] (0.830s -> 1.250s) ДатаПульс
[Строка 4] [spk_1] (1.300s -> 1.550s) на
[Строка 5] [spk_1] (1.600s -> 2.100s) CloudForge.
[Строка 6] [spk_1] (2.300s -> 2.600s) Да,
[Строка 7] [spk_2] (2.650s -> 2.900s) согласен,
[Строка 8] [spk_2] (2.950s -> 3.400s) э-э-э,
[Строка 9] [spk_2] (3.420s -> 3.900s) логично.

Checklist Crítico para Revisão Manual:

  1. Mapeamento de Rótulos para Participantes Reais (Linhas 1–5 e 7–9): Os identificadores spk_1 e spk_2 são rótulos de voz posicionais e arbitrários. Um editor deve ouvir os momentos iniciais de cada trecho para estabelecer as identidades verdadeiras: por exemplo, verificando que, na Parte 1, spk_1 corresponde a Alexey e spk_2 a Mikhail.
  2. Transições de Fala e Interjeições Curtas (Linha 6): A palavra “Да,” está agrupada no turno de spk_1. Em uma conversa ativa, isso pode ser na verdade uma confirmação breve ou assentimento sobreposto do ouvinte (spk_2). As fronteiras de transição entre locutores exigem checagens auditivas pontuais.
  3. Grafia Fonética de Marcas Não Reconhecidas (Linha 3): Com o custom_vocabulary desativado, termos técnicos em inglês podem ser transcritos foneticamente para o cirílico (por exemplo, ДатаПульс). Um editor precisa ajustar essas ocorrências para o formato canônico: DataPulse.
  4. Proibição de Substituições Globais Cegas: As alterações de terminologia devem ser feitas sempre de forma seletiva no contexto. Operações globais de “localizar e substituir” em todo o documento correm o risco de corromper palavras comuns, expressões idiomáticas ou citações literais que possuam sonoridade parecida.
  5. Hesitações e Marcadores Conversacionais (Linha 8): No modo verbatim, marcas de hesitação como “э-э-э” são capturadas explicitamente. Em uma ata de reunião formal, esses elementos são removidos. Para faixas de legendas em vídeo, contudo, sua marcação temporal deve ser mantida caso o ritmo da legenda precise acompanhar a articulação visível em tela.

Protocolo de Verificação Pontual Antes da Entrega do Material

Os dados brutos gerados pela concatenação programática devem passar por uma auditoria de qualidade direcionada em três pontos de controle:

  1. Verificação de Locutores e Fronteiras Conversacionais: Ouça de 15 a 20 segundos de áudio ao longo de 2 a 3 transições de fala entre participantes. Confirme que vozes distintas não foram unificadas em um único locutor e que monólogos contínuos não foram fragmentados em rótulos fantasmas. Conforme a documentação oficial, a diarização para reuniões com três ou mais participantes é experimental e requer uma fiscalização consideravelmente mais rigorosa.
  2. Verificação de Terminologia, Valores Numéricos e Entidades Nomeadas: Elabore uma lista direcionada dos nomes essenciais do projeto (DataPulse, CloudForge, números de versão, alocações de orçamento). Busque por esses termos no texto e confira passagens duvidosas diretamente no áudio, evitando substituições em massa indiscriminadas.
  3. Verificação da Continuidade da Linha do Tempo nas Fronteiras de Segmento: Compare o primeiro minuto da Parte 1 com a emenda de transição para a Parte 2 (logo após a marca de 25:00 / 1500.0 segundos). Assegure-se de que os timestamps do segundo segmento dão continuidade natural à linha do tempo, em vez de reiniciarem em zero.

Entrega para Etapas Seguintes e Condições de Parada do Processo

Os arquivos meeting_transcript.txt e word_timestamps.json gerados pelo script são criados antes da revisão auditiva e precisam ser tratados estritamente como rascunhos preliminares. Nunca os repasse em seu estado bruto. Primeiro execute o protocolo de verificação manual, reconcilie as identidades dos locutores, os termos e os deslocamentos da linha do tempo com o áudio original, faça os ajustes necessários (atualizando os parâmetros no código e executando novamente ou editando os arquivos diretamente) e só então libere as cópias verificadas para as etapas seguintes:

  • Para Redatores de Atas ou Modelos de Sumarização (Note Taker / LLM Summarization): Forneça uma cópia verificada da transcrição da reunião — um documento revisado com atribuição confirmada de locutores e terminologia técnica normalizada. Isso serve de base para resumos executivos e relatórios de decisões, embora não constitua, por si só, uma lista automatizada de tarefas (action items).
  • Para Editores de Vídeo ou Especialistas em Legendas (Caption Editor): Forneça uma cópia verificada da matriz de timestamps por palavra — uma sequência validada de palavras atrelada a timestamps contínuos. As regras de formatação seguintes (limites de exibição na tela, limites de tamanho de linha, velocidade de leitura) dependem do player de vídeo de destino e do idioma; depois disso, uma ferramenta dedicada de formatação gera os arquivos finais de legenda em .srt ou .vtt.

Condições de Parada do Processo (Stop Conditions)

Interrompa o fluxo de trabalho e não encaminhe os arquivos para as etapas seguintes se qualquer uma das seguintes condições for identificada:

  1. Áudio com mais de 30 minutos de duração tiver sido enviado para diarização ou timestamps por palavra sem segmentação prévia (isso viola os limites documentados da API e não deve ser enviado).
  2. Arquivos brutos de rascunho (meeting_transcript.txt ou word_timestamps.json) tiverem sido liberados para consumo logo após a execução do script, sem amostragem auditiva e conferência manual.
  3. Os rótulos de locutores no segundo segmento tiverem sido mapeados às cegas com base nos números do primeiro segmento sem ouvir o áudio, ou se identificadores de locutores não resolvidos permanecerem no conjunto de dados.
  4. A duração física do primeiro segmento não tiver sido adicionada à linha do tempo do segundo segmento, ou se timestamps de palavras ausentes forem detectados.
  5. Regras indiscriminadas de substituição global tiverem sido aplicadas à terminologia sem validação contextual, ou se parâmetros críticos de configuração e dados numéricos tiverem sido deixados sem conferência contra a gravação.

Quer otimizar seu fluxo de trabalho com LLMs?

Conecte modelos por uma única API, gerencie chaves e controle os gastos com IA.

Começar grátis