Notas de reuniones LLM API: de transcripción a resumen en Python
Para obtener notas de reuniones LLM API envías la transcripción a un endpoint de chat completions con un prompt de sistema corto y lees la respuesta. Las piezas que determinan la calidad son el prompt, una forma de salida fija y cómo manejas grabaciones largas.
Actualizado

Puntos clave
- Una llamada de chat completions convierte una transcripción en notas; el modo JSON te da una forma fija.
- Una ventana de 100.000 tokens contiene la mayoría de las transcripciones de reuniones sin fragmentación.
- Indica al modelo que escriba null para los responsables y fechas faltantes, para que no los invente.
- Una clave completa permite 8 peticiones simultáneas, suficientes para procesar un día de reuniones en paralelo.
La canalización en cuatro pasos
- Graba y transcribe. Usa cualquier herramienta de voz a texto. Esta API es solo de texto y no acepta audio.
- Prepara el texto. Añade un encabezado con el título de la reunión, la fecha y los nombres de los asistentes. Las etiquetas de hablante, si las tienes, ayudan mucho.
- Llama al modelo. Envía la transcripción con un prompt de sistema que defina las secciones que deseas.
- Guarda y comparte el resultado. Guarda el JSON, renderízalo como Markdown o HTML, publícalo donde el equipo lo lea.
El endpoint es POST /v1/chat/completions en https://api.whisperapis.com/v1, el ID del modelo es uncensored, y cualquier SDK de OpenAI funciona después de cambiar la URL base y la clave. Si necesitas configurar primero la conversión de voz a texto, los documentos de inicio rápido cubren la parte de texto y cualquier servidor compatible con Whisper puede proporcionar la transcripción.
Obtén notas estructuradas con modo JSON
Los resúmenes libres son adecuados para leer, pero una tubería necesita campos que pueda almacenar y filtrar. El modo JSON, habilitado con response_format establecido en {"type": "json_object"}, hace que el modelo devuelva un único objeto JSON. Describe las claves en el prompt de sistema y di la palabra JSON allí, porque el prompt es lo que define la forma.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.whisperapis.com/v1", api_key="YOUR_KEY")
SYSTEM = """You write meeting notes from raw transcripts.
Use only what the transcript says. If an owner or a date is not stated, write null.
Reply with a JSON object with the keys: summary (string), decisions (array of strings),
action_items (array of objects with task, owner, due), open_questions (array of strings)."""
transcript = open("standup.txt", encoding="utf-8").read()
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": "Transcript:\n\n" + transcript},
],
response_format={"type": "json_object"},
temperature=0.2,
)
notes = json.loads(resp.choices[0].message.content)
for item in notes["action_items"]:
print(item["owner"], "->", item["task"], item["due"])Dos líneas en ese prompt hacen la mayor parte del trabajo. "Usa solo lo que dice la transcripción" evita que el modelo añada detalles plausibles. "Si no se menciona un responsable o una fecha, escribe null" le da una forma legal de decir que no lo sabe, lo cual es mejor que un nombre inventado. Una temperatura baja como 0,2 reduce la variación entre ejecuciones, lo que deseas cuando la misma transcripción podría procesarse dos veces.
Analiza siempre de forma defensiva. Envuelve json.loads en un bloque try y, en caso de fallo, reintenta una vez. Las peticiones fallidas no se cobran y un único reintento corrige la mayoría de los errores de formato puntuales.
Transmite el resultado a la persona que espera
Si alguien hace clic en un botón y espera las notas, muestra el texto a medida que llega. Establece stream a true y la API envía eventos enviados por el servidor; el consumo se incluye al final del flujo.
from openai import OpenAI
client = OpenAI(base_url="https://api.whisperapis.com/v1", api_key="YOUR_KEY")
transcript = open("standup.txt", encoding="utf-8").read()
stream = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "Write concise meeting notes in Markdown with headings: Summary, Decisions, Actions."},
{"role": "user", "content": transcript},
],
stream=True,
temperature=0.3,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)El streaming tiene un detalle operativo: una petición en streaming mantiene su ranura de concurrencia hasta que finaliza. Una clave completa permite 8 a la vez, una clave de prueba 2. Si una pestaña del navegador se cierra y tu servidor sigue leyendo, esa ranura permanece ocupada, así que cancela la petición remota cuando el cliente se desconecte.
Para trabajos por lotes que nadie vigila, omite el streaming. Una petición normal es más sencilla y obtienes toda la respuesta en un solo objeto.
Reuniones largas y la ventana de 100k
La ventana de contexto es de 100.000 tokens, contando el prompt y la respuesta juntos. Una reunión de una hora tiene aproximadamente 9.000 palabras, o unos 12.000 tokens, así que incluso un taller de todo el día cabe en una petición. Eso elimina el diseño habitual de mapa y reducción donde divides una transcripción, resumas cada parte y luego resumas los resúmenes. Cada pasada de ese diseño pierde detalles, y una decisión tomada en el minuto 5 y revisada en el minuto 50 es fácil de informar incorrectamente.
Aún así, verifica el tamaño antes de enviar. Una comprobación rudimentaria es dividir los caracteres por cuatro para texto en inglés. Si estás cerca del límite, hay dos opciones limpias:
- Divide en interrupciones naturales como los puntos de la agenda, resume cada uno y pasa las notas parciales a una llamada final que las fusione.
- Elimina el contenido que no importa, como largos tramos de charla antes de que comience la reunión.
El cuerpo máximo de la petición es de 8 MB, que no es un límite práctico para texto. Los prompts no se usan para entrenamiento, lo cual importa si las grabaciones incluyen planes internos o nombres de clientes.
Detalles del prompt que cambian la salida
Di para quién son las notas
"Notas para un ingeniero que se perdió la reunión" obtiene diferentes detalles que "una actualización de un párrafo para el equipo directivo". Escribe al lector en el prompt de sistema.
Proporciona al modelo la lista de asistentes
La conversión de voz a texto a menudo distorsiona los nombres. Una línea como "Asistentes: Priya Nair (PM), Tom Ortiz (backend), Lena Fischer (diseño)" permite al modelo reparar una transcripción que dice "Tom Ortis" y adjuntar tareas a la persona correcta.
Pide decisiones y acciones por separado
Una decisión es algo en lo que el grupo estuvo de acuerdo. Una acción es algo que hará una persona. Cuando ambas viven en una sola lista, los lectores la omiten. Claves separadas hacen explícita la distinción y el modelo la sigue consistentemente.
Mantén lo sensible dentro
Las reuniones reales contienen lenguaje directo, quejas sobre personas nombradas, preocupaciones legales y disputas acaloradas. El modelo aquí está ajustado para responder sin rechazos de contenido para uso adulto legal, así que resume lo que se dijo en lugar de rechazar. Tú sigues siendo dueño de la salida, así que revisa las notas antes de que se envíen a personas que no estaban en la sala.
Ejecutar todo un día de reuniones
Un equipo que graba seis reuniones al día puede procesarlas en paralelo. Con 8 peticiones simultáneas, envía hasta ocho a la vez; un pequeño grupo de trabajadores con un semáforo hace el trabajo. El límite por minuto para una clave completa es de 300 peticiones, lo que una tubería de reuniones no alcanzará.
Node funciona de la misma manera que Python. Aquí está la versión sin streaming:
import OpenAI from "openai";
import { readFileSync } from "node:fs";
const client = new OpenAI({
baseURL: "https://api.whisperapis.com/v1",
apiKey: process.env.API_KEY,
});
const transcript = readFileSync("standup.txt", "utf8");
const resp = await client.chat.completions.create({
model: "uncensored",
messages: [
{ role: "system", content: "Summarize the meeting in five bullets, then list action items with owners." },
{ role: "user", content: transcript },
],
temperature: 0.2,
});
console.log(resp.choices[0].message.content);Si recibes HTTP 429, lee el código de error. concurrency significa demasiadas peticiones a la vez, así que reduce el tamaño del grupo. rate_limited significa demasiadas por minuto. Un 429 con un encabezado Retry-After: 5 señala una sobrecarga temporal; espera cinco segundos y vuelve a intentarlo.
Comprobando las notas antes de confiar en ellas
Las notas generadas leen con confianza incluso cuando están equivocadas, así que integra algunas comprobaciones baratas en la tubería en lugar de depender de que un humano se dé cuenta.
- Comprobación de citas. Pide una breve cita de apoyo con cada elemento de acción, luego busca la transcripción por ella. Una cita que no aparece es una señal de que el elemento fue inventado.
- Comprobación de responsables. Compara cada responsable con tu lista de asistentes y marca los nombres que no estén en ella.
- Comprobación de vacío. Es posible tener una reunión sin decisiones, pero un resultado con todas las matrices vacías en una transcripción de 40 minutos generalmente significa que la entrada se truncó o el archivo era incorrecto.
- Comprobación de longitud. Las notas más largas que aproximadamente una quinta parte de la transcripción no son notas; ajusta el prompt o establece
max_tokens.
Registra el encabezado de respuesta X-Request-Id junto a cada resultado guardado. Cuando alguien dice que un elemento de acción es incorrecto, ese identificador te permite encontrar la petición y compararla con la transcripción. Mantener la transcripción original junto con las notas es barato y resuelve la mayoría de las disputas rápidamente.
Costo y una primera prueba
El precio es $0,15 por millón de tokens de entrada y $0,50 por millón de tokens de salida. Una reunión de una hora con una transcripción de 12.000 tokens y un conjunto de notas de 800 tokens cuesta $0,0018 para entrada y $0,0004 para salida, es decir, $0,0022 en total. A ese ritmo, $1 cubre aproximadamente 454 reuniones de este tipo. Consulta la página de precios para recargas, que comienzan en $20 y pueden pagarse con tarjeta o cripto.
Para probarlo, regístrate y abre la página de clave de API. Hay una prueba de un clic de $0,50 disponible una vez por persona, válida por 7 días, sin necesidad de tarjeta. Ejecuta el script de Python anterior en una transcripción real, lee el JSON y ajusta el prompt hasta que los elementos de acción coincidan con lo que ocurrió en la reunión. Luego repite el proceso con el resto.
Más guías
Preguntas y respuestas
¿Puedo enviar grabaciones de audio directamente?
No. La API solo acepta texto. Transcribe la grabación con una herramienta de voz a texto primero, y luego envía la transcripción.
¿Cómo hago para que el formato de salida sea consistente?
Usa el modo JSON con un prompt del sistema que nombre cada clave, y establece una temperatura baja. Analiza el resultado en un bloque try y reintenta una vez en caso de fallo.
¿Qué tan larga puede ser una transcripción para caber en una sola petición?
La ventana de contexto es de 100.000 tokens para el prompt más la respuesta. Eso cubre un taller de un día completo en la mayoría de los casos.
¿Se usan mis transcripciones para entrenamiento?
No, los prompts no se usan para el entrenamiento.
¿Cuánto cuesta por reunión?
Una reunión de una hora con una transcripción de 12.000 tokens y un resumen de 800 tokens cuesta aproximadamente $0,0022 a $0,15 y $0,50 por millón de tokens de entrada y salida.
Tu clave está a un formulario de distancia
Crea una cuenta, copia la clave, cambia la URL base. Esa es toda la configuración.