Skip to main content
Una transcripción no son notas. Es la reunión otra vez, solo que más larga de leer que de asistir a ella. Lo que la gente quiere después es corto: qué decidimos, quién se comprometió a hacer qué y qué queda abierto. Este tutorial construye eso, y enlaza cada elemento con el segundo en que se dijo, para que puedas ir a escuchar la parte con la que no estés de acuerdo:
Por el camino haremos lo siguiente:
  1. Transcribir una grabación con /audio/transcriptions
  2. Pedir marcas de tiempo, que no todos los modelos ofrecen
  3. Extraer decisiones y tareas contra un esquema
  4. Lidiar con el hecho de que la transcripción nunca dice quién está hablando
  5. Dividir una grabación larga sin perder el reloj

Configuración

Necesitas Python 3.9 o más reciente, el paquete requests y una clave de API de Venice. Consulta Generar una clave de API si no tienes una. Aporta cualquier grabación de una conversación en wav, mp3, m4a, flac, aac, mp4, ogg o webm.

1. Transcribir la grabación

/audio/transcriptions es compatible con OpenAI y acepta una subida multipart. El archivo tiene que ser una parte real, porque base64 no se admite en este endpoint.
La transcripción se factura por la duración del audio, no por cuánto se dijo en él, lo que facilita predecir el coste de una reunión antes de ejecutarla: Llama a GET /models?type=asr para obtener la lista actual en lugar de fijar estos valores, ya que el catálogo cambia.

2. Pedir marcas de tiempo

Las marcas de tiempo son las que hacen que las notas sean verificables, así que esta es la decisión que más importa, y por defecto no te las darán:
nvidia/parakeet-tdt-0.6b-v3 es el modelo por defecto, y acepta timestamps=true y luego lo ignora. No hay error ni aviso, solo una respuesta con únicamente text dentro. Si necesitas tiempos, pide un modelo que los devuelva y comprueba que la clave está ahí.
Cuando un modelo sí devuelve tiempos, timestamps es un objeto en lugar de una lista, y la clave que contiene depende del modelo. Whisper agrupa por frase, Scribe por palabra:
Los segmentos a nivel de frase tienen el tamaño adecuado para este trabajo. Los tiempos por palabra son útiles para subtítulos y demasiado finos para colgar una decisión de ellos. Vamos a aplanar esos segmentos en líneas con un tiempo delante de cada una, que es todo lo que el modelo necesita para citarlas después:

3. Extraer las notas

Describe las notas que quieres como un esquema, para que el resultado sea un registro en vez de prosa que tengas que parsear:
disable_thinking está ahí por la misma razón por la que pertenece a cualquier paso de extracción. El esquema ya decide la forma de la respuesta, así que pagar a un modelo con razonamiento para que delibere sobre ella no aporta nada y hace que el coste de cada ejecución sea distinto del anterior. Extraer datos estructurados de documentos mide esa diferencia. Ejecútalo sobre un standup de cincuenta y tres segundos y las notas vuelven con el reloj adjunto:
Cada spoken_at es real. Salta a los 19,6 segundos y escucharás la frase que creó la tarea.
Dale al modelo líneas sin tiempos y cada spoken_at vuelve como 0. El campo es obligatorio, el modelo no tiene nada que poner en él, y un campo obligatorio es una instrucción para producir algo, no una invitación a decir que no lo sabe. Merece la pena recordarlo cuando un esquema parece funcionar: que la forma sea correcta no es lo mismo que los valores sean correctos.

4. Nadie está etiquetado

Dos cosas en esa salida están mal, y ambas vienen del mismo sitio. El responsable del despliegue es May. Su nombre es Mei. El reconocimiento de voz es menos fiable con los nombres propios, y los nombres son exactamente lo que necesita la atribución, así que este es el fallo que deberías esperar y no la mala suerte. El último elemento es unassigned, aunque claramente alguien lo asumió. La línea fue “I’ll ask legal today and report back tomorrow”, y la transcripción registra las palabras sin registrar quién las dijo. Ese segundo caso no es un bug que puedas arreglar. Ningún modelo de transcripción de Venice hace diarización, por lo que no hay un campo speaker al que recurrir en ninguno de ellos. La transcripción es una única corriente de texto sin voces, y las tareas solo se pueden atribuir cuando se pronuncia un nombre en voz alta, como en “Tomas, can you put the deprecation notice in the changelog”. El primero sí puedes arreglarlo, diciéndole al modelo quién estaba en la sala:
May se resuelve a Mei Lin porque el modelo ahora tiene una lista corta contra la que emparejar, y los responsables son nombres completos que tu gestor de tareas puede buscar. El tercer elemento sigue sin asignar, correctamente. Una lista de asistentes corrige lo mal escuchado, y nada recupera información que la grabación nunca llevó.
Si necesitas atribución real de hablantes, captúrala aguas arriba en lugar de inferirla aguas abajo. Las herramientas de videoconferencia pueden grabar una pista por participante, y transcribir cada pista por separado te da los hablantes gratis, al coste de una petición por persona.

5. Más largo que una sola petición

Las subidas están limitadas a 25 MB, algo que llega antes de lo que pensarías para audio sin comprimir, y de todos modos una reunión larga merece la pena dividirla para que un solo fallo no te cueste toda la transcripción. Para archivos WAV, la biblioteca estándar es suficiente, no hace falta ffmpeg:
El offset es la clave. Cada trozo se transcribe como si empezara en cero, así que sus tiempos hay que desplazarlos de vuelta a la línea temporal de la grabación original antes de que el modelo los vea. Para eso está el argumento offset de timed_lines:
Divide el mismo standup en trozos de veinte segundos y el reloj sigue siendo honesto a través de las uniones. Las palabras no:
Ahí se pronunció una sola frase: “Tomas, can you put the deprecation notice in the changelog by Friday?”. El corte cayó en medio, así que el nombre acabó en una petición y la petición en otra. Whisper oyó el nombre huérfano como una pregunta, inventó un awesome. para rellenar el hueco al final del trozo y convirtió una línea en tres. Los tiempos siguen siendo correctos, y el paso de las notas sigue encontrando la tarea. Lo que pierde es el nombre, que es de lo que depende la atribución.
Dividir por duración fija corta a alguien en cada frontera. Veinte segundos es lo bastante corto para caer en una frase casi siempre; diez minutos lo hace raro pero no imposible, y acabará cayendo en la única frase que asigna el trabajo. Dividir por silencio evita el problema de la forma adecuada y necesita una herramienta que encuentre los huecos, como ffmpeg o pydub. Divide solo cuando el archivo realmente lo requiera.
Los formatos comprimidos no se pueden cortar así, porque no se puede cortar un MP3 en un límite de frame con la biblioteca estándar. Usa ffmpeg para esos:

Uniéndolo todo

Próximos pasos

Voz a texto

Referencia del endpoint de transcripciones.

Extraer datos estructurados de documentos

La misma extracción basada en esquema, aplicada a archivos.

Respuestas estructuradas

Cómo json_schema restringe una completación.

Clonación de voz

Dale al resumen una voz propia.