Invita y gana

Cómo funcionan las recompensas

Comparte tu enlace. Cuando un amigo se registre con él y recargue saldo, recibirás la recompensa indicada por sus recargas posteriores.

Transcripción de reuniones en Gemini 3.5 Transcribe: hablantes, marcas de tiempo y vocabulario en la práctica

Una guía práctica para transformar una grabación de reunión de 45 minutos en una transcripción verificada o una base para subtítulos con Gemini 3.5 Transcribe: selección de parámetros de configuración, división adecuada de archivos de audio largos, ensamblado de marcas de tiempo a nivel de palabra mediante el SDK de Python y ejecución del control de calidad manual.

Índice
Transcripción de reuniones en Gemini 3.5 Transcribe: hablantes, marcas de tiempo y vocabulario en la práctica

Transformar la grabación de audio de una reunión de trabajo en un documento confiable exige tomar decisiones arquitectónicas deliberadas al configurar los parámetros de reconocimiento de voz. En Gemini 3.5 Transcribe, no existe un modo universal «todo en uno»: la normalización editorial profunda (smart), la separación de hablantes (diarization_mode), la cuadrícula temporal a nivel de palabra (timestamp_granularities) y los léxicos especializados por dominio (custom_vocabulary) representan capacidades de la API funcionalmente aisladas entre sí.

Todo pipeline de procesamiento debe comenzar definiendo con claridad su objetivo final: ¿se requiere un bloque de texto conciso y legible para una revisión rápida, una base estructurada para análisis posteriores o una matriz de marcas de tiempo exactas para la edición de video? Intentar combinar parámetros mutuamente excluyentes provocará errores de validación de esquema antes siquiera de que la solicitud comience a procesarse.

A continuación se presenta una guía práctica integral: cómo preparar una grabación de 45 minutos de dos interlocutores con terminología técnica, gestionar los límites documentados de la API, procesar ambas partes utilizando el SDK oficial de Python, estructurar los datos preliminares en borrador, verificarlos y corregirlos cotejándolos con el audio y entregar copias verificadas a un redactor de actas o a un editor de subtítulos.


Restricciones arquitectónicas y conflictos de parámetros

Para ilustrar el flujo de trabajo, consideremos una sesión de trabajo típica: Alexey (Tech Lead) y Mikhail (Product Manager) dedican 45 minutos a debatir sobre la arquitectura de migración y el despliegue de servicios bajo los nombres internos de proyecto DataPulse y CloudForge. La conversación incluye jerga técnica, préstamos lingüísticos, interrupciones rápidas y comienzos en falso.

Al diseñar una integración con Gemini 3.5 Transcribe, es obligatorio considerar tres reglas estrictas:

  • Incompatibilidad entre vocabulario personalizado y metadatos estructurales: El parámetro custom_vocabulary (que admite hasta 1000 términos, con una recomendación práctica de hasta 100) no puede enviarse junto con diarization_mode ni con timestamp_granularities. Es necesario asumir un compromiso de diseño: confiar en el modelo para transcribir con precisión nombres de marcas especializados (renunciando a las etiquetas automáticas de hablante y marcas de tiempo), o bien solicitar una alineación detallada de interlocutores y tiempos, verificando la terminología técnica durante el posprocesamiento.
  • Incompatibilidad entre el modo smart y la alineación temporal: El modo smart aplica una normalización lingüística: elimina muletillas, tartamudeos y comienzos en falso, al tiempo que reestructura la sintaxis gramatical. Dado que los tokens se eliminan, fusionan o reordenan, el modelo no puede asociar el texto resultante con la línea temporal del flujo de audio subyacente. En consecuencia, la atribución de hablantes y las marcas de tiempo a nivel de palabra no están disponibles en el modo smart. Además, este modo solo devuelve texto continuo sin anotaciones (output_text) y no extrae automáticamente listas de tareas pendientes (action items).
  • Límite de 30 minutos para metadatos avanzados: Las solicitudes estándar de transcripción sin anotaciones detalladas admiten archivos de audio de hasta 60 minutos de duración. Sin embargo, en cuanto se activa diarization_mode o timestamp_granularities, la duración máxima documentada del archivo se reduce a 30 minutos. Enviar archivos que superen este umbral queda fuera de la especificación admitida por la API y no debe intentarse; los audios extensos deben dividirse en el cliente antes de su envío.

Preparación y división de la grabación de 45 minutos

Para extraer la diarización y las marcas de tiempo a nivel de palabra de una grabación de 45 minutos, el archivo de origen debe dividirse en segmentos estrictamente inferiores a 30 minutos. En nuestro escenario hipotético, dividimos la grabación en dos partes:

  • Parte 1: 00:00–25:00 (asumiendo exactamente 1500.0 segundos);
  • Parte 2: 25:00–45:00 (los 20 minutos restantes o 1200.0 segundos).

El límite de 1500.0 segundos se elige en este caso únicamente para simplificar los cálculos del ejemplo. En entornos de producción, los cortes deben realizarse durante pausas conversacionales naturales entre turnos de palabra, y la duración física exacta del primer segmento debe extraerse directamente de los metadatos del archivo multimedia mediante una herramienta de inspección como ffprobe.

La división del audio introduce dos desafíos críticos de continuidad:

  1. Reinicio de marcas de tiempo en el segundo segmento: La API procesa el segundo segmento como un archivo totalmente independiente, reiniciando sus desplazamientos internos a nivel de palabra desde 0.000s. Para reconstruir una línea temporal continua de toda la reunión, la duración real del primer segmento debe sumarse mediante programación a cada marca de tiempo de palabra extraída del segundo segmento.
  2. Localidad de las etiquetas de hablante: El modelo asigna identificadores de interlocutor como spk_1 y spk_2 de forma aislada dentro del alcance de cada llamada individual a la API. El participante designado como spk_1 en el primer fragmento puede recibir spk_2 en el segundo. Fusionar etiquetas técnicas idénticas provenientes de solicitudes independientes sin verificación previa alterará por completo la atribución de las intervenciones. Cada fragmento requiere una tabla de correspondencia independiente cotejada con las voces reales de los participantes mediante una escucha selectiva.

Variantes de configuración para distintas tareas

Los parámetros de transcripción se configuran dentro del campo transcription_config del diccionario generation_config. A continuación se presentan las configuraciones base adaptadas a distintas necesidades operativas.

Para obtener notas de reunión coherentes y normalizadas sin etiquetas de hablantes ni marcas de tiempo (adecuado para archivos completos de menos de 60 minutos):

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

Para conversaciones centradas en nombres de productos de nicho o jerga propietaria donde la ortografía exacta tiene prioridad:

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

Para generar actas de reunión y cuadrículas de sincronización para subtítulos (sujeto al límite de 30 minutos de audio):

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

Pipeline de trabajo completo con el SDK de Python: procesamiento de dos partes

Este script se ejecuta antes de escuchar el audio o realizar cualquier verificación manual. Sube ambos segmentos a través de la Files API, envía solicitudes a la Interactions API, extrae las anotaciones a nivel de palabra, valida las marcas de tiempo y los identificadores de hablante, desplaza la línea temporal de la segunda parte en 1500.0 segundos y genera los archivos de borrador preliminares:

  • meeting_transcript.txt — un borrador del diálogo en UTF-8 organizado por turnos de palabra;
  • word_timestamps.json — un array preliminar de marcas de tiempo continuas a nivel de palabra previsto para la segmentación de subtítulos.

Los archivos generados por este script son explícitamente borradores sin verificar, no registros definitivos. El profesional a cargo debe escuchar la grabación, asignar los tokens técnicos de interlocutor a las voces reales (speaker mapping), verificar la terminología técnica (terms) y auditar los desplazamientos temporales (time offsets). Tras completar esta auditoría, actualice los parámetros de configuración en el código y vuelva a ejecutar el pipeline, o bien edite directamente los archivos de texto generados. Solo tras cumplir este protocolo de verificación deben entregarse copias definitivas a un redactor de actas o a un editor de subtítulos.

El script genera estructuras de datos intermedias para analistas y editores de video; no produce de forma automática listas de tareas pendientes ni archivos de subtítulos con formato .srt. Los nombres de los participantes y el límite de 1500.0 segundos se definen aquí con fines demostrativos dentro de este escenario 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)

Ejemplo ilustrativo de la estructura a nivel de palabra y zonas de inspección

A continuación se presenta una representación sintética del flujo de datos extraído en la transición entre dos interlocutores.

Nota: Este fragmento sirve exclusivamente para ilustrar la estructura de los objetos devueltos, no como un registro real de llamadas a la API. La calidad real de la transcripción depende de la acústica, los micrófonos y la claridad del habla.

[Строка 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) логично.

Lista de verificación crítica para la revisión manual:

  1. Asignación de etiquetas a participantes reales (Líneas 1–5 y 7–9): Los identificadores spk_1 y spk_2 son tokens vocales posicionales arbitrarios. Un editor debe escuchar los primeros instantes de cada segmento para determinar las identidades reales: por ejemplo, verificar que en la Parte 1, spk_1 corresponde a Alexey y spk_2 a Mikhail.
  2. Cambios de turno e interjecciones breves (Línea 6): La palabra «Да,» se agrupa dentro del turno de spk_1. En una conversación fluida, esto podría ser en realidad un asentimiento de escucha activa o una respuesta solapada del interlocutor (spk_2). Los límites de alternancia entre hablantes requieren comprobaciones auditivas puntuales.
  3. Ortografía fonética de marcas no reconocidas (Línea 3): Con custom_vocabulary desactivado, los nombres técnicos en inglés pueden transcribirse fonéticamente al cirílico (por ejemplo, ДатаПульс). El editor debe corregir estas apariciones a su formato canónico: DataPulse.
  4. Prohibición del reemplazo global indiscriminado: Las correcciones terminológicas deben aplicarse siempre de manera selectiva y en contexto. Las operaciones de «buscar y reemplazar» automáticas en todo el documento conllevan el riesgo de corromper palabras comunes, giros idiomáticos o citas literales que compartan similitudes fonéticas.
  5. Titubeos conversacionales y palabras de relleno (Línea 8): En el modo verbatim, las marcas de vacilación como «э-э-э» se registran explícitamente. En un acta de reunión depurada, estas se eliminan. Sin embargo, para pistas de subtítulos de video, sus tiempos deben preservarse si el ritmo del subtítulo debe coincidir con la articulación visible en pantalla.

Protocolo de verificación puntual antes de entregar el material

Los datos sin procesar generados por concatenación programática deben superar una auditoría de calidad focalizada en tres puntos de control de verificación:

  1. Verificar los hablantes y los límites conversacionales: Escuche entre 15 y 20 segundos de audio a lo largo de 2 o 3 transiciones de turno entre interlocutores. Confirme que las voces no se hayan fusionado en un único hablante y que los monólogos continuos no se hayan fragmentado en etiquetas erróneas. Según la documentación oficial, la diarización para reuniones con tres o más participantes es experimental y exige un escrutinio considerablemente más riguroso.
  2. Verificar la terminología, los valores numéricos y las entidades con nombre: Elabore una lista de comprobación con los nombres clave del proyecto (DataPulse, CloudForge, números de versión, asignaciones de presupuesto). Busque estos términos en el texto y coteje los pasajes dudosos directamente con el audio, evitando reemplazos masivos e indiscriminados.
  3. Verificar la continuidad de la línea temporal en los límites de los segmentos: Compare el primer minuto de la Parte 1 con la transición hacia la Parte 2 (inmediatamente después del límite de 25:00 / 1500.0 segundos). Asegúrese de que las marcas de tiempo del segundo segmento continúen la línea temporal de manera fluida y sin reiniciar a cero.

Entrega a fases posteriores y condiciones de parada del proceso

Los archivos meeting_transcript.txt y word_timestamps.json generados por el script se crean antes de la revisión auditiva y deben tratarse estrictamente como borradores preliminares. Nunca los entregue en su estado sin procesar. Primero ejecute el protocolo de verificación manual, concilie las identidades de los interlocutores, los términos y los desfases temporales con el audio, corrija los resultados (actualizando los parámetros en el código y volviendo a ejecutar el script o editando los archivos directamente) y solo entonces distribuya las copias verificadas a las siguientes etapas:

  • Para redactores de actas o modelos de resumen (Note Taker / LLM Summarization): Entregue una copia verificada de la transcripción de la reunión: un documento revisado con atribución confirmada de hablantes y términos técnicos normalizados. Esto sirve de base para resúmenes ejecutivos y registros de decisiones, aunque no constituye por sí mismo una lista automática de tareas pendientes.
  • Para editores de video o especialistas en subtitulado (Caption Editor): Entregue una copia verificada de la matriz de marcas de tiempo por palabra: una secuencia validada de palabras vinculadas a marcas temporales continuas. Las reglas de estilo posteriores (límites de permanencia en pantalla, longitud máxima de línea, velocidad de lectura) dependen del reproductor de video de destino y del idioma, tras lo cual una herramienta de formateo dedicada generará los archivos finales de subtítulos .srt o .vtt.

Condiciones de parada del proceso (Stop Conditions)

Detenga el flujo de trabajo y no transfiera los archivos a los equipos receptores si se cumple cualquiera de las siguientes condiciones:

  1. Se envió audio de más de 30 minutos de duración para diarización o marcas de tiempo por palabra sin segmentación previa (esto excede los límites documentados de la API y no debe enviarse).
  2. Se entregaron archivos preliminares sin procesar (meeting_transcript.txt o word_timestamps.json) a los usuarios receptores inmediatamente después de ejecutar el script, sin realizar verificaciones auditivas puntuales ni revisión manual.
  3. Las etiquetas de hablante del segundo segmento se asignaron a ciegas según la numeración del primer segmento sin escuchar el audio, o permanecen identificadores de hablante sin resolver en el conjunto de datos.
  4. No se añadió la duración física del primer segmento a la línea temporal del segundo segmento, o se detectan marcas de tiempo de palabras faltantes.
  5. Se aplicaron reglas indiscriminadas de búsqueda y reemplazo global a la terminología sin validación contextual, o se dejaron parámetros de configuración críticos y cifras numéricas sin contrastar con la grabación.

¿Quieres optimizar tu flujo de trabajo con LLM?

Conecta modelos mediante una API, gestiona claves y controla el gasto en IA.

Empezar gratis