NL ▾
API-sleutel aanvragen

LLM API-vergadernotulen: Transcript naar samenvatting in Python

Voor LLM API-vergadernotulen stuur je het transcript naar een chat completions endpoint met een korte system prompt en lees je het antwoord. De onderdelen die de kwaliteit bepalen zijn de prompt, een vaste output-indeling en hoe je lange opnames verwerkt.

Bijgewerkt

Isometrische vergadertafel met spreekbellen die samenklonteren tot een checklist-kaart erboven

Belangrijkste punten

  • Eén chat-completieverzoek zet een transcript om in notities; JSON-modus geeft je een vaste structuur.
  • Een contextvenster van 100.000 tokens bevat de meeste vergaderingstranscripten zonder chunking.
  • Geef het model de instructie null te schrijven voor ontbrekende eigenaren en data, zodat het ze niet verzinnebeeldt.
  • Een volledige sleutel staat 8 gelijktijdige verzoeken toe, genoeg om een dag aan vergaderingen parallel te verwerken.

De pipeline in vier stappen

  1. Neem op en transcribeer. Gebruik een spraak-naar-teksttool. Deze API is alleen voor tekst en accepteert geen audio.
  2. Bereid de tekst voor. Voeg een header toe met de vergaderingstitel, datum en namen van de deelnemers. Sprekerslabels, als je die hebt, helpen veel.
  3. Roep het model op. Stuur het transcript met een systeemprompt die de secties definieert die je wilt.
  4. Bewaar en deel het resultaat. Sla de JSON op, render het als Markdown of HTML en plaats het waar het team de notulen leest.

De endpoint is POST /v1/chat/completions op https://api.whisperapis.com/v1, de model-ID is uncensored, en elke OpenAI SDK werkt nadat je de base URL en sleutel hebt gewijzigd. Als je eerst spraak-naar-tekst moet instellen, dekken de quickstart-documentatie de tekstkant en kan elke Whisper-compatible server het transcript leveren.

Krijg gestructureerde notulen met JSON-modus

Vrije samenvattingen zijn prima om te lezen, maar een pipeline wil velden die hij kan opslaan en filteren. JSON-modus, ingeschakeld met response_format ingesteld op {"type": "json_object"}, zorgt ervoor dat het model één JSON-object retourneert. Beschrijf de sleutels in de system prompt en noem het woord JSON daar, want de prompt bepaalt de indeling.

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"])

Twee regels in die prompt doen het meeste werk. "Gebruik alleen wat het transcript zegt" voorkomt dat het model aannemelijke details toevoegt. "Schrijf null als een eigenaar of datum niet wordt genoemd" geeft het model een legale manier om aan te geven dat het het niet weet, wat beter is dan een verzonnen naam. Een lage temperatuur zoals 0,2 vermindert de variatie tussen runs, wat je wilt als hetzelfde transcript mogelijk twee keer wordt verwerkt.

Parse altijd voorzichtig. Wrap json.loads in een try-blok, en bij een fout opnieuw proberen. Mislukte verzoeken worden niet in rekening gebracht, en één retry lost de meeste eenmalige formatteringsfouten op.

Stream het resultaat naar de persoon die wacht

Als iemand op een knop klikt en wacht op de notities, toon tekst terwijl deze aankomt. Stel stream in op true en de API stuurt server-sent events; het gebruik wordt aan het einde van de stream vermeld.

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)

Streaming heeft één operationeel detail: een gestreamd verzoek houdt zijn concurrency slot vast tot de stream eindigt. Een volledige sleutel staat 8 tegelijk toe, een trial-sleutel 2. Als een browsertabblad sluit en je server blijft lezen, blijft dat slot bezet, dus annuleer het upstream-verzoek als de client disconnecteert.

Voor batchtaken die niemand bekijkt, sla streaming over. Een gewoon verzoek is eenvoudiger en je krijgt het hele antwoord in één object.

Lange vergaderingen en het 100k-venster

Het contextvenster is 100.000 tokens, tellend de prompt en het antwoord samen. Een vergadering van een uur is ongeveer 9.000 woorden, of ongeveer 12.000 tokens, dus zelfs een hele workshop past in één verzoek. Dit verwijdert het gebruikelijke map-and-reduce ontwerp waarbij je een transcript splitst, elk deel samenvat en vervolgens de samenvattingen samenvat. Elke pass van dat ontwerp verliest details, en een beslissing genomen op minuut 5 en herzien op minuut 50 is makkelijk verkeerd te rapporteren.

Controleer nog steeds de grootte voordat je verstuurt. Een ruwe controle is tekens gedeeld door vier voor Engelse tekst. Als je dicht bij de limiet zit, zijn er twee nette opties:

  • Splits bij natuurlijke breukpunten zoals agendapunten, vat elk samen en stuur de gedeeltelijke notities naar een laatste verzoek die ze samenvoegt.
  • Verwijder inhoud die er niet toe doet, zoals lange stukken klein gepraat voordat de vergadering begint.

De maximale request body is 8 MB, wat geen praktische limiet is voor tekst. Prompts worden niet gebruikt voor training, wat belangrijk is als opnames interne plannen of klantnamen bevatten.

Promptdetails die de output beïnvloeden

Geef aan waar de notulen voor zijn

"Notities voor een ingenieur die de vergadering miste" krijgt een ander detailniveau dan "een een-paragraaf update voor het executive team". Schrijf de lezer in de systeemprompt.

Geef het model de deelnemerslijst

Speech-to-text verwarpt vaak namen. Een regel zoals "Deelnemers: Priya Nair (PM), Tom Ortiz (backend), Lena Fischer (design)" stelt het model in staat een transcript dat "Tom Ortis" bevat te herstellen en taken aan de juiste persoon toe te wijzen.

Vraag om beslissingen en acties gescheiden

Een beslissing is iets waar de groep het over eens was. Een actie is iets dat één persoon zal doen. Als beide in één lijst staan, slaan lezers ze over. Gescheiden sleutels maken het onderscheid expliciet, en het model volgt dit consistent.

Houd de gevoelige informatie in

Echte vergaderingen bevatten ruwe taal, klachten over benoemde personen, juridische zorgen en hitige discussies. Het model hier is afgestemd om te antwoorden zonder inhoudsweigeringen voor wettelijk volwassen gebruik, dus het vat samen wat er gezegd is in plaats van te weigeren. Je bent nog steeds eigenaar van de output, dus controleer notities voordat ze naar mensen gaan die niet in de kamer waren.

Een hele dag vergaderingen runnen

Een team dat zes vergaderingen per dag opneemt, kan ze parallel verwerken. Met 8 gelijktijdige verzoeken, stuur tot acht tegelijk; een kleine werkerspool met een semaphore doet het werk. De per-minuut limiet voor een volledige sleutel is 300 verzoeken, wat een vergadering pipeline niet zal bereiken.

Node werkt op dezelfde manier als Python. Hier is de niet-gestreamde versie:

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);

Als je HTTP 429 ontvangt, lees de foutcode. concurrency betekent te veel verzoeken tegelijk, dus verlaag de grootte van de pool. rate_limited betekent te veel per minuut. Een 429 met een Retry-After: 5 header signaleert tijdelijke overbelasting; wacht vijf seconden en probeer opnieuw.

Notulen controleren voordat je ze vertrouwt

Gegenereerde notities lezen zelfverzekerd, zelfs als ze fout zijn, dus bouw een paar goedkope controles in de pipeline in plaats van te vertrouwen op een mens om het op te merken.

  • Citaatcontrole. Vraag om een korte ondersteunende quote bij elk actiepunt, zoek daarnaar in het transcript. Een citaat dat niet verschijnt, is een teken dat het item verzonnen is.
  • Eigenaarcontrole. Vergelijk elke eigenaar met je deelnemerslijst en markeer namen die er niet op staan.
  • Controle op lege waarden. Een vergadering zonder beslissingen is mogelijk, maar een resultaat met alle lege arrays op een transcript van 40 minuten betekent meestal dat de input afgekapt was of het verkeerde bestand.
  • Controle op lengte. Notulen langer dan ongeveer een vijfde van het transcript zijn geen notulen; verscherp de prompt of stel max_tokens in.

Log de X-Request-Id response header naast elk opgeslagen resultaat. Als iemand zegt dat een actiepunt fout is, stelt die identifier je in staat het verzoek te vinden en het te vergelijken met het transcript. Het originele transcript naast de notulen bewaren is goedkoop en lost de meeste geschillen snel op.

Kosten en een eerste test

De prijs is $0,15 per miljoen input tokens en $0,50 per miljoen output tokens. Een vergadering van één uur met een transcript van 12.000 tokens en een set notities van 800 tokens kost $0,0018 voor input en $0,0004 voor output, dus $0,0022 in totaal. Bij dat tarief dekt $1 ongeveer 454 dergelijke vergaderingen. Zie de pricing page voor top-ups, die beginnen bij $20 en betaald kunnen worden met kaart of crypto.

Om het te proberen, meld je aan en open de API key page. Een one-click trial van $0,50 is beschikbaar één keer per persoon, geldig voor 7 dagen, geen kaart nodig. Voer het Python script hierboven uit op één echt transcript, lees de JSON en pas de prompt aan tot de action items overeenkomen met wat er in de vergadering gebeurde. Loop daarna over de rest.

Vragen en antwoorden

Kan ik audio-opnames direct versturen?

Nee. De API accepteert alleen tekst. Transcribeer de opname eerst met een spraak-naar-teksttool en stuur daarna het transcript.

Hoe zorg ik voor een consistente uitvoerindeling?

Gebruik JSON-modus met een systeemprompt die elke sleutel noemt, en stel een lage temperature in. Parse het resultaat in een try-blok en probeer opnieuw bij een fout.

Hoe lang een transcript past in één verzoek?

Het contextvenster is 100.000 tokens voor prompt plus antwoord. Dit dekt in de meeste gevallen een hele workshop van een dag.

Worden mijn transcripten gebruikt voor training?

Nee, prompts worden niet gebruikt voor training.

Wat kost het per vergadering?

Een vergadering van een uur met een transcript van 12.000 tokens en een samenvatting van 800 tokens kost ongeveer $0,0022 bij $0,15 en $0,50 per miljoen input- en output-tokens.

Je sleutel is nog maar één veld verwijderd

Maak een account aan, kopieer de sleutel, pas de base URL aan. Dat is de hele setup.

API-sleutel aanvragen