Ir al contenido

Reuniones y transcripción

Control Center puede grabar una llamada y devolverte un informe bien presentado —un resumen, tareas y decisiones— con reconocimiento de voz y separación de hablantes ejecutándose en tu propio hardware. Piensa en Granola, pero autoalojado y conectado al mismo espacio de trabajo en el que viven tus agentes.

Una reunión es una sesión grabada y transcrita. No es lo mismo que un evento de calendario: un evento es un compromiso programado sincronizado desde Google, mientras que una reunión es algo que has grabado realmente. Los dos pueden vincularse, ya que puedes iniciar una grabación desde un evento, pero siguen siendo registros distintos.

Toda reunión tiene alcance de espacio de trabajo, como todo lo demás en Control Center. Las reuniones grabadas en un espacio de trabajo nunca aparecen en otro.

«En el dispositivo» es el instinto correcto, pero el sustantivo equivocado. El cliente captura el audio y transmite tramas PCM16 de 16 kHz a la máquina que ejecuta cc_server. Ese host hace todo lo demás: escribe los WAV por canal en <dataDir>/meetings/<meetingId>/, transcribe en un isolate de worker, filtra el eco y diariza a posteriori. En un escritorio independiente, ese host es la misma máquina. Si apuntas a un servidor remoto, ya no lo es, así que «nada sale de mi portátil» solo es cierto cuando el servidor es tu portátil.

Hay una excepción más, y es la importante.

Todo lo anterior al resumen —captura, transcripción, cancelación de eco, diarización, coincidencia de huellas de voz— se ejecuta en el servidor sin ninguna llamada de red.

Los modelos de embedding, diarización y voz (ASR) se instalan a la fuerza en el primer arranque (se omiten en una demo), así que la separación de hablantes y la grabación existen sin pasar por los ajustes. El ASR sigue siendo seleccionable: ocupa varios cientos de megabytes y se incluyen cuatro compilaciones en el selector. El modelo de voz sigue necesitando un reinicio después de esa primera descarga, porque el transcriptor resuelve su modelo antes de que pueda terminar la descarga.

Las cuatro entradas del selector, que difieren en tamaño, cobertura de idiomas y precisión:

  • Parakeet TDT 0.6B v3 — multilingüe, la opción predeterminada recomendada (~600 MB)
  • Parakeet TDT 0.6B v2 — inglés (~480 MB)
  • Whisper large-v3-turbo — multilingüe (~626 MB)
  • Whisper base.en — solo en inglés, el pequeño valor predeterminado histórico (~198 MB)

Los modelos son los únicos artefactos que el servidor descarga en tiempo de ejecución; todas las bibliotecas nativas se incluyen en el paquete.

Una reunión graba dos canales de audio a la vez:

  • Tú («me»): tu micrófono.
  • Ellos («them»): la salida de audio de la reunión, capturada mediante un loopback sin controladores: taps de proceso/dispositivo de Core Audio en macOS, loopback WASAPI en Windows y un monitor de PipeWire / PulseAudio en Linux.

Como los dos canales se capturan por separado, la transcripción lleva atribución de hablante desde el principio: tus palabras se etiquetan como me y las de todos los demás en la llamada, como them.

Tu propia voz se cuela desde la salida del sistema de vuelta al micrófono y, de otro modo, se transcribiría dos veces. Dos filtros lo evitan. El AEC3 a nivel de señal se ejecuta en todas las grabaciones en modo remoto y es obligatorio: si la biblioteca nativa de AEC no puede cargarse, la grabación se niega a empezar en lugar de transmitir en silencio un micrófono contaminado por eco. (El modo presencial no tiene una referencia de extremo lejano contra la que cancelar, así que allí el AEC es un paso directo de identidad.) Por encima de él, se ejecuta un filtro de eco de nivel de texto en el lado del host en todas las plataformas.

Todo el procesamiento de micrófono a nivel de sistema operativo está desactivado deliberadamente. Activar la cancelación de eco o la ganancia automática propias de la plataforma en macOS cambia el micrófono a Voice Processing I/O, lo que en esta compilación acabó tanto con el micrófono como con el tap de audio del sistema.

Mientras grabas, el audio se decodifica en ventanas deslizantes —cortadas tras un breve silencio final o al alcanzar una longitud máxima de ventana— fuera del hilo de la interfaz. Cada ventana se convierte en un segmento de transcripción etiquetado por hablante y con desplazamientos en milisegundos.

Las ventanas que nunca superaron un umbral de RMS se omiten sin llegar a decodificarse, porque un modelo de voz convierte el silencio en tokens alucinados que no son habla y la decodificación desperdicia CPU. La consecuencia práctica: un hablante sistemáticamente muy silencioso no produce ninguna transcripción. Si alguien vuelve vacío, comprueba su nivel de entrada antes de culpar al modelo.

Cuando paras, la diarización se ejecuta a posteriori sobre la grabación y divide el canal remoto en hablantes individuales (Person 1, Person 2, …) que puedes renombrar. El número de hablantes se infiere de un umbral de agrupamiento, no de un recuento que fijes tú, así que es un artefacto del umbral y un hablante bajo o solapado puede fusionarse con un vecino. La transcripción se representa como líneas [mm:ss] SPEAKER: text.

Renombrar a un hablante hace más que etiquetar una transcripción. Control Center puede guardar la huella de voz del hablante como un perfil de voz, de modo que lo reconoce automáticamente en reuniones futuras. Cuando pones nombre a un hablante diarizado, se te pregunta si quieres guardar la huella de voz; si lo haces, se fusiona en un centroide acumulado para ese nombre y se compara con nuevos hablantes por similitud de coseno, de modo que la misma persona aparece con su nombre la próxima vez sin que tengas que volver a etiquetarla.

Los perfiles de voz tienen alcance de espacio de trabajo y nunca cruzan esa frontera. Gestiónalos en Ajustes → Espacio de trabajo → Reuniones. Cambiar el nombre a un hablante que se había guardado antes retira el nombre antiguo y ofrece registrar el nuevo; eliminar un perfil quita la huella de voz almacenada, pero deja intactos los nombres ya aplicados a reuniones anteriores.

Cuando se detiene una grabación, el servidor publica un MeetingRecordingStopped evento de dominio. La plantilla de pipeline integrada meeting_summary se dispara con ese evento. El grabador no espera a ella; la reunión simplemente pasa por su ciclo de vida de estados:

recording → processing → done

El agente de resumen recibe el título, tus notas en vivo aproximadas y la transcripción, y devuelve JSON estructurado. Las secciones que escribe las determina la plantilla de notas de reunión activa del espacio de trabajo (Ajustes → Espacio de trabajo → Reuniones); la plantilla activa se aplica a los resúmenes nuevos y reejecutados. Los pasos de persistencia del pipeline escriben luego ese JSON en filas discretas:

  • enhancedNotes y summary → las notas de la reunión
  • cada tarea → una fila MeetingActionItem (contenido, responsable, vínculo opcional a un ticket)
  • cada decisión → una fila MeetingDecision

Las tareas y las decisiones nunca se extraen de markdown de forma libre, solo de los arrays estructurados del agente. Si una ejecución no produce salida estructurada, se omiten los pasos de persistencia y se conserva la transcripción sin procesar como respaldo, de modo que nunca pierdes el registro. Nada en el pipeline marca la reunión como done: lo hace un único reconciliador a partir del evento terminal de la ejecución, de modo que el fallo de un paso hermano no puede dejar varada una reunión a medio escribir que ya parece terminada.

Superficie Qué muestra
/meetings La lista de reuniones, con recuentos de tareas y decisiones
/meetings/record El HUD de grabación en vivo: tus notas a un lado y la transcripción en streaming al otro
/meetings/:meetingId El detalle de una reunión: pestañas Notas, Transcripción, Tareas y Decisiones
Ajustes → Espacio de trabajo → Reuniones Plantillas de notas y perfiles de voz guardados de este espacio de trabajo

La captura no necesita controladores en las tres plataformas de escritorio (taps de Core Audio en macOS, WASAPI en Windows y PipeWire en Linux).

El cliente web también graba, algo que el enfoque de escritorio del resto de esta página puede ocultar: el navegador toma tu micrófono con getUserMedia y el audio de la reunión con getDisplayMedia (compartir pantalla), reduce la frecuencia a PCM16 de 16 kHz y lo transmite al mismo host. Aquí se aplican tres advertencias:

  • La superficie compartida debe llevar una pista de audio. Safari, Firefox y el uso compartido de pantalla completa de macOS no generan ninguna y la grabación se niega a empezar.
  • No hay AEC3 nativo. La cancelación de eco propia del navegador se solicita sobre el micrófono; el filtro de eco de texto del lado del host sigue ejecutándose. El HUD muestra un medidor de nivel de entrada alimentado por el PCM del micrófono.
  • Volver a ejecutar el resumen y cancelar el procesamiento solo están disponibles en escritorio.

La acción Grabar y vincular del calendario solo está disponible en el escritorio y lo indica con claridad en la web, aunque el propio flujo de grabación de la pantalla de reuniones sí funciona ahí.