Audio transcriberen¶
Core zet een opname om in tekst met een audiomodel uit de catalogus van je organisatie. Dat kan op vier manieren:
| Je wilt | Gebruik |
|---|---|
| De tekst van een opname in je eigen applicatie, zoals de notulen van een vergadering | POST /audio/transcriptions, dat de tekst teruggeeft |
| De tekst van een lange opname, zoals een vergadering van een uur | een transcriptietaak, die Core op de achtergrond in delen knipt en transcribeert |
| Een model dat tijdens een gesprek zelf besluit een bestand te transcriberen | de transcriptietool builtin__transcribe_audio__<model> |
| Een ingesproken bericht dat het model beantwoordt alsof het getypt was | een input_audio-deel in een verzoek aan POST /responses |
Alle vier gebruiken dezelfde audiomodellen en kosten hetzelfde per seconde audio.
Voordat je begint¶
Zoek een audiomodel. GET /models?kind=audio toont de audiomodellen van je organisatie. Elke
ingang heeft een id, de plek waar het model draait (region, country), de price per minuut en
allowed: of het modelbeleid van je sleutel het model op dit moment toelaat. Bij false wordt een
transcriptie met dat model geweigerd. Is de lijst leeg, dan heeft je organisatie geen audiomodel;
vraag je beheerder er een toe te voegen.
curl -s "$CORE_URL/models?kind=audio" -H "Authorization: Bearer $CORE_KEY"
{
"items": [
{
"id": "whisper-large-v3",
"object": "model",
"kind": "audio",
"allowed": true,
"tool_name": "builtin__transcribe_audio__whisper-large-v3",
"region": "eu",
"country": "fr",
"price": {
"input_eur_per_million_tokens": null,
"output_eur_per_million_tokens": null,
"eur_per_unit": "0.003",
"effective_from": "1970-01-01T00:00:00Z",
"is_tenant_override": false
}
}
],
"next_cursor": null
}
De ingang is hier ingekort; de volledige vorm staat op Een modelaanroep
doen. Bij een audiomodel is price.eur_per_unit de prijs van één
minuut audio. Een model dat in tokens wordt afgerekend, zoals gpt-4o-transcribe, heeft daarnaast
input_eur_per_million_tokens en output_eur_per_million_tokens, de tarieven waartegen het wordt
afgerekend; zijn minuut is dan een schatting (Kosten).
Weet wat je sleutel nodig heeft. De transcriptieroute vraagt geen capability: net als bij
POST /responses beslist het beleid van je sleutel over het model. De tool vraagt daarnaast de
capability tooling en transcribe_audio tussen de systeemtools van de sleutel. Een bestand bij
zijn id noemen vraagt de capability files, omdat het bestand eerst geüpload moet zijn.
Formaten en limieten¶
Core leest het formaat af aan de bytes van de opname zelf, niet aan de bestandsnaam of het
opgegeven type. Het accepteert WAV, FLAC, MP3 (ook als mpeg en mpga), Ogg (ogg, oga), MP4
(mp4, m4a) en WebM. Al het andere wordt geweigerd voordat het ergens heen gaat. Een losse
AAC-stroom zonder container wordt niet geaccepteerd; zet die eerst in een MP4-container (m4a).
Of een MP4- of WebM-bestand wordt getranscribeerd, hangt ook af van de leverancier van het model:
kan die het niet lezen, dan mislukt de aanroep met The audio could not be transcribed. Stuur voor
de zekerheid MP3, WAV, FLAC of Ogg.
Eén opname is hoogstens 25 MiB, dezelfde grens als voor elke upload. Je beheerder kan die voor
de installatie aanpassen, en de configuratie files van je sleutel kan haar verlagen; GET /key
toont de max_bytes van je sleutel. Hoeveel tijd in 25 MiB past, hangt af van hoe de opname is
gecodeerd:
| Opname | Ongeveer |
|---|---|
| MP3 op 128 kbit/s | 27 minuten |
| MP3 op 64 kbit/s, genoeg voor spraak | 55 minuten |
| Ogg Opus op 32 kbit/s | 1 uur en 49 minuten |
| WAV, 16 kHz mono, 16-bit | 13 minuten |
| WAV, 44,1 kHz stereo, 16-bit | 2,5 minuut |
Een langere opname past niet in één bestand: comprimeer haar naar een formaat dat geschikt is voor spraak, zoals mono MP3 op 64 kbit/s of Ogg Opus; dan past een vergadering van een uur of langer.
Ook één aanroep heeft grenzen. Sommige modellen nemen in één aanroep maar een korte opname aan:
Google's chirp-3 een minuut, Azure's fast-transcription niet meer dan het tijdsbudget van de
aanroep. En elke transcriptie heeft een eigen tijdsbudget (twee minuten, tenzij je beheerder dat
veranderde); een aanroep die daaroverheen gaat, mislukt met The audio could not be transcribed.
Een opname boven de grens van haar model wordt met 422 op file geweigerd voordat er iets wordt
verstuurd. Gebruik voor een opname die niet in één aanroep past een
transcriptietaak: Core knipt haar in delen die het model
aanneemt en transcribeert die na elkaar. Laat binnen een gesprek de tool op de achtergrond
draaien, zodat de beurt niet op een lange opname wacht.
Een opname transcriberen¶
Stuur de opname als multipart/form-data naar POST /audio/transcriptions:
curl -s -X POST "$CORE_URL/audio/transcriptions" \
-H "Authorization: Bearer $CORE_KEY" \
-F "file=@vergadering.mp3" \
-F "model=whisper-large-v3" \
-F "language=nl"
{
"text": "Goedemorgen allemaal, dan beginnen we met de begroting.",
"usage": { "type": "duration", "seconds": 1312 }
}
usage.seconds is hoeveel audio deze aanroep in rekening bracht, in hele seconden, naar boven
afgerond. Een model dat in tokens wordt afgerekend, zoals gpt-4o-transcribe, antwoordt in plaats
daarvan in de tokenvorm van OpenAI:
"usage": { "type": "tokens", "input_tokens": 14, "output_tokens": 45, "total_tokens": 59 }.
| Veld | Betekenis |
|---|---|
file |
De opname. Verplicht. |
model |
Het id van een audiomodel uit GET /models?kind=audio. Verplicht. |
language |
De taal van de opname als ISO 639-1-code van twee letters, zoals nl of en. Laat je het weg, dan herkent het model de taal zelf. Met een opgegeven taal is het resultaat meestal beter. |
prompt |
Tekst die het model richting geeft: namen, spellingen of de gewenste stijl, zoals Artific, Kubernetes, Jansen. Hoogstens 4.000 tekens. |
response_format |
json (de standaard), text of verbose_json. |
temperature |
Een getal van 0 tot 1. Laat het weg als je geen reden hebt. |
text geeft alleen de tekst terug, als text/plain. verbose_json voegt task toe (altijd
transcribe), language (de taal die je opgaf, of null als je er geen opgaf) en duration (de
seconden audio die de leverancier meldde, of null bij een model dat in tokens wordt afgerekend). Core geeft geen segments of words terug, dus srt
en vtt, die daaruit worden opgebouwd, worden geweigerd met 422. Andere velden van OpenAI's
transcriptie-API, zoals timestamp_granularities[], worden genegeerd.
Met de OpenAI-SDK¶
De route neemt dezelfde velden als OpenAI's eigen transcriptie-API, dus de bibliotheek openai
werkt als je haar naar Core laat wijzen:
from openai import OpenAI
client = OpenAI(base_url="https://<jouw-installatie>/api/v1", api_key="ack_...")
with open("vergadering.mp3", "rb") as opname:
transcript = client.audio.transcriptions.create(
model="whisper-large-v3",
file=opname,
language="nl",
)
print(transcript.text)
Voor één persoon¶
Een verzoek dat een persoon noemt in X-Core-Subject, of dat met het eigen token van een persoon
binnenkomt, wordt ook aan de regels van die persoon getoetst, en de verbruiksregel draagt de
persoon (Bouwen voor personen).
Een lange opname transcriberen¶
Een vergadering van een uur is te lang voor één aanroep. Upload haar als bestand en maak een transcriptietaak: Core knipt de opname op stille momenten in delen die het model aanneemt, transcribeert die op de achtergrond na elkaar en voegt de tekst samen. Jij vraagt de taak op tot ze klaar is.
1. Upload de opname met de capability files:
curl -s -X POST "$CORE_URL/files" \
-H "Authorization: Bearer $CORE_KEY" \
-F "file=@vergadering.mp3" \
-F "purpose=assistants"
De id in het antwoord is het bestands-id, zoals file_01J.... Het bestand is hoogstens de
bestandsgrens van je sleutel (Formaten en limieten).
2. Maak de taak:
curl -s -X POST "$CORE_URL/audio/transcription-jobs" \
-H "Authorization: Bearer $CORE_KEY" \
-H "Content-Type: application/json" \
-d '{"file_id": "file_01J...", "model": "whisper-large-v3", "language": "nl"}'
Core antwoordt 202 met de taak en haar adres in Location:
{
"id": "atj_01J...",
"status": "queued",
"file_id": "file_01J...",
"model": "whisper-large-v3",
"language": "nl",
"chunks_done": 0,
"chunks_total": null,
"error": null,
"result": null,
"created_at": "2026-10-17T09:00:00Z",
"ended_at": null
}
De body neemt file_id en model, allebei verplicht, en language, prompt en temperature
zoals de route; de prompt gaat met elk deel mee. Het model, het
bestand, het beleid van je sleutel en je maandlimiet worden gecontroleerd voordat de taak bestaat,
dus een taak die wordt aangemaakt kan ook lopen: de limiet wordt gevraagd met wat de hele opname
gaat kosten.
3. Vraag de taak op met GET /audio/transcription-jobs/{id} tot status completed,
failed of cancelled is. Zolang ze loopt, is status in_progress, telt chunks_done de delen
die al getranscribeerd zijn en chunks_total hoeveel delen de opname telt. Een deel van vijf
minuten duurt meestal ruim minder dan een minuut; vraag dus ongeveer elke tien seconden.
4. Lees het transcript. Een voltooide taak draagt result:
{
"task": "transcribe",
"language": "nl",
"duration": 3612.4,
"text": "Goedemorgen allemaal, dan beginnen we met de begroting. ...",
"segments": [
{ "start": 0.0, "end": 298.7, "text": "Goedemorgen allemaal, dan beginnen we met de begroting." },
{ "start": 298.7, "end": 596.1, "text": "Het tweede punt is de planning voor het voorjaar." }
],
"usage": { "type": "duration", "seconds": 3624 }
}
text is de tekst van alle delen, gescheiden door een spatie. segments heeft één regel per
deel, met begin en einde in seconden van de oorspronkelijke opname, zodat je een passage in de
audio terugvindt. Er is geen srt of vtt: een deel van een paar minuten is geen ondertitel.
GET /audio/transcription-jobs toont de taken van je sleutel, nieuwste eerst, per cursor. Een
sleutel ziet alleen de taken die hij zelf maakte, en een subject-token alleen
die van zijn eigen persoon. POST /audio/transcription-jobs/{id}/cancel stopt een taak: de delen
die al getranscribeerd zijn blijven afgerekend, en er wordt geen volgend deel meer verstuurd.
Als een taak mislukt, zegt error waarom, met een vaste code en message:
code |
Wat er gebeurde |
|---|---|
file_unavailable |
Het bestand is verwijderd, of je sleutel kan het niet meer lezen. |
recording_unreadable, split_timeout |
Core kon de opname niet decoderen, of het decoderen duurde te lang. Zet haar om naar MP3 of FLAC en probeer het opnieuw. |
recording_too_long |
Het bestand decodeert langer dan zijn grootte bij de laagste bitrate kan bevatten, wat geen echte opname doet. De delen tot dat punt blijven afgerekend. Zet het om en probeer het opnieuw. |
transcription_refused, transcription_failed |
De leverancier weigerde een deel of het mislukte. De delen ervoor blijven afgerekend. |
usage_cap_exceeded |
Je maandlimiet werd tijdens de taak bereikt. De delen ervoor blijven afgerekend. |
model_not_available, model_not_allowed |
Het model is ingetrokken, of het beleid van je sleutel laat het niet meer toe. |
key_revoked, key_disabled, service_account_paused, tenant_unavailable |
De sleutel die de taak maakte is ingetrokken, verlopen of uitgeschakeld, het serviceaccount waarvoor ze werkt is gepauzeerd, of je organisatie is niet beschikbaar. |
reaped_too_often |
De taak liet haar worker elke keer stoppen. Vraag je beheerder. |
Het model een bestand laten transcriberen¶
Bied de transcriptietool aan als het model zelf moet beslissen of een opname gelezen moet worden, bijvoorbeeld een assistent die verwerkt wat een gebruiker heeft geüpload.
- Zet de tool aan voor je sleutel. De configuratie
toolingvan je sleutel moettranscribe_audionoemen ondersystem_tools. In de console is dat Audio transcriberen tussen de systeemtools op de pagina van de sleutel (Sleutels). Zonder die schakelaar wordt het aanbieden van de tool geweigerd met400. - Upload de opname met
POST /files(Bestanden) en bewaar haarid. Een artefact van je organisatie noem je op dezelfde manier. - Bied de tool aan en vertel het model welk bestand het moet lezen:
curl -s -X POST "$CORE_URL/responses" \
-H "Authorization: Bearer $CORE_KEY" -H "Content-Type: application/json" \
-d '{
"model": "<een chatmodel-id>",
"tools": [{"type": "tool", "name": "builtin__transcribe_audio__whisper-large-v3"}],
"input": "Vat de opname src_3Wq8... samen in vijf punten. Ze is in het Nederlands."
}'
Er is één tool per audiomodel, genoemd naar het id van het model. De naam staat in tool_name bij
GET /models?kind=audio, dus je hoeft hem niet zelf op te bouwen. Hoe de tool precies werkt, met
zijn argumenten en vaste antwoorden, staat op Tools via de
API.
Het model geeft file_id mee en eventueel language en prompt. Het krijgt het transcript terug
als resultaat van de tool. Het model stuurt de opname nooit zelf mee, en Core haalt nooit een
opname op van een webadres.
Op de achtergrond¶
Een opname kan als taak worden getranscribeerd: het gesprek gaat door terwijl de taak loopt, en het transcript komt op de thread zodra het klaar is. De tool neemt nog steeds alleen aan wat in één aanroep past; een opname boven de grens van haar model vraagt een transcriptietaak. Je organisatie staat dat per tool toe, net als bij een afbeeldingstool (Een tool op de achtergrond draaien).
Een ingesproken bericht sturen¶
Een user-bericht in POST /responses kan een opname meedragen als input_audio-deel. Core
transcribeert die voordat het model wordt aangeroepen, en het model leest de tekst alsof de
gebruiker hem had getypt. Gebruik dit voor een spraakbericht uit een app of een telefoon.
Stuur de opname inline mee, in base64 met haar formaat:
{
"model": "<een chatmodel-id>",
"input": [
{
"role": "user",
"content": [
{ "type": "input_audio", "input_audio": { "data": "<base64>", "format": "mp3" } }
]
}
]
}
of noem een bestand dat je eerder uploadde:
{ "type": "input_audio", "file_id": "src_3Wq8..." }
Geef precies één van de twee. format wordt geaccepteerd voor de compatibiliteit; Core leest het
formaat, net als op de route, af aan de bytes. Een bericht kan input_audio combineren met
input_text-delen: elke opname wordt tekst op de plek waar ze stond, en de delen worden zoals
altijd samengevoegd. Alleen een user-bericht mag input_audio bevatten.
Kies het audiomodel, of laat Core kiezen. Zet "model" in het deel om het audiomodel te noemen
dat die opname transcribeert, een id uit GET /models?kind=audio:
{ "type": "input_audio", "file_id": "src_3Wq8...", "model": "whisper-large-v3" }
Dat model transcribeert haar, of het verzoek wordt geweigerd: een id dat geen audiomodel van je
organisatie is, krijgt 400 op input, en een model dat het beleid van je sleutel niet toelaat
403. Core neemt nooit een ander model in de plaats. Laat je model weg, dan neemt Core, onder de
audiomodellen die het beleid van je sleutel voor deze beurt toelaat, het voorkeursmodel van je
operator (Whisper van Scaleway, whisper-large-v3, tenzij je operator het veranderde), anders het
eerste dat in de EU draait, anders het eerste in de catalogus van je organisatie. De
hosting.region van de beurt, als je die opgeeft, beperkt wat je sleutel toelaat. Laat je sleutel
geen van de audiomodellen toe, dan wordt het verzoek geweigerd met 403; heeft je organisatie
helemaal geen audiomodel, dan met 400 op input.
De opname wordt pas getranscribeerd als de beurt is toegelaten. Core controleert eerst het
model, het beleid, je maandlimiet en het gesprek. Een verzoek dat daar wordt geweigerd, kost geen
transcriptie. Bij een verzoek met background: true wordt de opname getranscribeerd voordat Core
antwoordt dat de run is aangenomen.
Het gesprek bewaart het transcript, niet de opname. Het bewaarde bericht bevat de tekst die de
opname werd. Een inline meegestuurde opname wordt nergens bewaard. Een opname die je met file_id
noemt, blijft het bestand dat ze al was.
Een router hoort de opname niet. Noemt je verzoek een modelrouter, dan kiest de router het model voordat de opname is getranscribeerd. Hij ziet het bericht zonder de opnames, dus een bericht dat alleen uit een opname bestaat, ziet er voor de router leeg uit.
Limieten. Elke opname valt onder de grens van 25 MiB hierboven. Een
inline opname is bovendien deel van de body van het verzoek, die hoogstens 8 MiB mag zijn. Omdat
base64 gegevens ongeveer een derde groter maakt, past er inline zo'n 6 MiB audio in: ongeveer zes
minuten MP3 op 128 kbit/s. Upload een langere opname en stuur haar file_id.
Waar input_audio wordt geweigerd:
POST /threadsenPOST /threads/{thread_id}/itemsweigeren een item metinput_audiomet422opitems, omdat die routes geen model aanroepen en niets de opname zou transcriberen. Stuur het bericht viaPOST /responses.- Het opgeslagen verzoek van een schema mag een opname alleen met
file_idnoemen. Een inline opname wordt geweigerd met422oprequest.input, omdat het schema de opname anders bij elke keer dat het afgaat zou bewaren.
Fouten¶
| Status | Melding | Wat je doet |
|---|---|---|
413 |
De opname is groter dan de bestandsgrens van je sleutel. Comprimeer haar of knip haar op (Formaten en limieten). | |
422 op model |
The model is not an audio model this organisation has. |
Kies een id uit GET /models?kind=audio. Een chatmodel en een model van een andere organisatie geven hetzelfde antwoord. |
422 op file |
The file is not a recording Core can transcribe. Accepted: ... |
Zet de opname om naar een van de genoemde formaten. |
422 op file |
The recording is longer than this model transcribes: at most ... Upload it as a file and POST /audio/transcription-jobs, which splits it into parts this model takes. |
De opname is langer dan dit model in één aanroep aanneemt. Gebruik een transcriptietaak. |
403 |
The audio model is not allowed for this key. |
Het beleid van je sleutel laat dit model niet toe. Vraag het je beheerder. |
403 |
The audio model is not hosted in a region this key allows. |
Het model draait buiten de regio's van je sleutel. Gebruik een ander audiomodel of vraag het je beheerder. |
403 |
The audio model is not hosted in the region this turn requires. |
Alleen bij input_audio: geen enkel audiomodel draait in de hosting.region van de beurt. |
429 |
Je sleutel of organisatie heeft haar maandlimiet bereikt, of deze opname zou haar erover brengen (Je maandlimiet). | |
422 |
The transcription model refused this audio. |
De leverancier wilde deze opname niet transcriberen. Opnieuw sturen helpt niet. |
503 |
The audio could not be transcribed. |
De leverancier faalde, deed er te lang over of kon het formaat niet lezen. Probeer het later opnieuw, of probeer een kortere opname of een ander formaat. |
Bij input_audio komen dezelfde zinnen in het foutobject van
POST /responses, dat 400 antwoordt waar
de route 422 antwoordt, met param op input als het probleem de opname is. Daar gelden er nog
twee: een opname boven de grens geeft An input_audio recording exceeds the size this caller may
upload., en een file_id die je sleutel niet kan lezen geeft A named input_audio file could not
be used. Core probeert een transcriptie nooit zelf opnieuw, omdat de leverancier haar misschien al
heeft getranscribeerd en in rekening gebracht.
Kosten¶
Een audiomodel heeft een prijs per minuut audio; die staat bij het model in
GET /models?kind=audio en in de console op Modellen. Elke
transcriptie die de leverancier beantwoordde, schrijft één verbruiksregel van de soort
audio_transcription, met de hele seconden audio als hoeveelheid, naar boven afgerond, en het model
(Gebruik via de API). De kosten zijn de seconden maal de
prijs per minuut, gedeeld door zestig: 90 seconden tegen EUR 0,003 per minuut kosten EUR 0,0045. Een
geweigerde of mislukte transcriptie kost niets.
Sommige modellen worden in tokens afgerekend, zoals hun leverancier ze factureert: OpenAI's
gpt-4o-transcribe en gpt-4o-mini-transcribe. Hun prijs noemt daarnaast een tarief per miljoen
invoertokens (die van de opname en van je prompt) en per miljoen uitvoertokens, en hun regel draagt
die tokens met hoeveelheid nul, dus de kosten zijn de tokens tegen die tarieven. Hun prijs per
minuut is dan een schatting, alleen gebruikt voor de maandlimiet hieronder.
Meerdere opnames in één verzoek zijn meerdere regels. Een transcriptie door de tool schrijft
daarnaast de gewone regel tool_invocation van een toolaanroep. Een transcriptietaak schrijft één
regel per deel, elk apart naar boven afgerond, dus een taak van twaalf delen kan een paar
seconden meer afrekenen dan de opname lang is, en het minimum per aanroep van een model (Groq rekent
minstens tien seconden) geldt voor elk deel. result.usage van een taak is de som van haar
regels.
De maandlimiet wordt vóór de aanroep gecontroleerd, met wat de opname gaat kosten. Core leest
hoe lang de opname is uit haar eigen headers, voordat een leverancier haar hoort, en weigert de
aanroep met 429 als zoveel seconden je sleutel of organisatie over haar limiet zouden brengen. Een
opname waarvan de headers niet zeggen hoe lang ze is (bijvoorbeeld een WebM die live in een browser
is opgenomen), telt zo lang als haar grootte toelaat bij 2 kbit/s, onder de laagste
spraakcodecs die deze formaten dragen; zo'n opname kan dus geweigerd worden waar een opname die haar
lengte noemt dat niet wordt. Een transcriptietaak wordt zo één keer gewogen bij het aanmaken, voor
de hele opname, en opnieuw vóór elk deel, tegen wat de delen ervoor al kostten. Afgerekend worden daarna de seconden die de leverancier meldt, niet de
schatting, of bij een model dat in tokens wordt afgerekend zijn tokens. Een audiomodel met prijs nul wordt nooit geweigerd.
Privacy en waar audio heen gaat¶
De opname gaat zoals ze is naar de leverancier van het model. Persoonsgegevens verbergen werkt
op tekst, en er is geen tekst totdat de leverancier de audio heeft gehoord. Ook op een sleutel met
pseudonymisation bereiken de stemmen en elke naam die in
de opname wordt uitgesproken dus de leverancier. Wat een opname beschermt, is waar ze heen gaat:
het beleid van je sleutel bepaalt welke audiomodellen het mag gebruiken en in welke regio's,
voordat er ook maar één byte wordt verstuurd (Regio's).
Kijk naar region en country bij GET /models?kind=audio voordat je iets gevoeligs stuurt.
Het transcript is tekst zoals alle andere tekst. De route geeft het je terug zoals de
leverancier het hoorde. Komt het transcript in een gesprek, via de tool of input_audio, dan
verbergt een sleutel die persoonsgegevens verbergt het voor het chatmodel, zoals hij je eigen
berichten verbergt.
Traces bevatten de audio noch de tekst. Een transcriptie staat in je traces met het model, de grootte van de opname en de afgerekende seconden. De opname en de woorden die erin stonden, worden daar nooit bewaard.