nur-stt-v1 and ask for
verbose_json.
There is one transcription id, and it is the diarizing model:
nur-stt-v1
returns speakers for a voice note and for an hour of meeting alike. Ask for
verbose_json and they are there — no second id to opt into.The payload
S01, S02, …) are consistent inside one file and anonymous.
They identify voices, not people, and they reset between files — the first voice
heard in an upload is S01 in that upload and nowhere else.
Words
words is a flat, OpenAI-shaped array. Each entry carries segment_id and
speaker, so you can regroup it into turns without a second pass.
Word timing is on by default. Send
timestamp_granularities[]=segment to skip
the alignment pass, which is worth a few seconds of GPU on a long file. When
alignment was asked for and could not run, the payload says so with
words_unavailable: true rather than omitting the key — an absent key is
indistinguishable from an older backend, and that ambiguity once hid a GPU
out-of-memory behind a transcript that otherwise looked perfect.
Audibility: which lines you can quote
Faint off-mic speech — a question from behind the camera, crew direction bleeding into a take — sits 30 dB or more under the dialogue. Whole-file loudness normalization cannot recover it, because integrated loudness is dominated by the loud material. This service normalizes adaptively in short frames instead, which does recover it: an utterance 35 dB down transcribes word-perfect and with the right speaker. That creates a second problem. After normalization every level looks the same, so the transcript alone cannot tell you which lines were actually on mic. The level is therefore measured on the pre-normalization signal, against the file’s own noise floor.
In the payload above the presenter reads 41.4 dB SNR (
on_mic) and the
off-camera request reads 3.3 dB (faint). Both are fully transcribed, and
afterwards you can tell them apart — which is what lets you quote one and not
the other.
Silence, pace, language
A silent upload — b-roll, room tone — is answered by a voice-activity gate
before the GPU is occupied:
"text": "", empty segments, and
"no_speech": true.
Sound events
Alongside the transcript the whole file is swept with an audio tagger and returned asscene: what sound occurs when, for the entire duration, rather
than one dominant label per asset.
label is one of music, speech, crowd, ambience, room_tone, sfx;
raw_label is the strongest underlying class in that region; role applies to
music only, bed when dialogue runs across it and featured otherwise.
Events overlap on purpose. Dialogue over a music bed in a room with traffic
outside is three simultaneous answers, and a timeline reporting one winner per
moment throws two of them away — a speech clip mixed with broadband noise came
back as 100% ambience, the speech erased. So each bucket gets its own run of
events, and music and speech covering the same seconds is the normal case.
Shares in scene_summary overlap for the same reason and sum above 1.
Keeping a run
POST /v1/audio/transcriptions is a pure relay: it returns the result and keeps
nothing. POST /v1/speech/transcriptions is the library — one upload that both
transcribes and files the run, so it has a row, its audio, and a place to come
back to.
stream defaults
to true here; pass stream=false for a single JSON body.
Naming the speakers
S01 is not a name. Operator names are stored beside the model’s own labels,
never over them, so re-running or re-reading the result never loses either:
speaker_names next to result, and it is yours to
render.
Deleting a run erases the uploaded audio first and the row second. If storage
refuses, nothing is deleted and the delete can be retried — the other order
would strand an audio object that nothing references and nothing can find
again.
When the library fails
/v1/speech/* is not one of the OpenAI-shaped routes, so it answers in two
envelopes rather than one. The gates it shares with /v1/audio/transcriptions
keep the OpenAI envelope; everything the route raises itself uses FastAPI’s
plain {"detail": …}. A bad form field here is a 422, not the 400 you get
one endpoint over.
Creating a run applies the same gates as the OpenAI-compatible route, and those
keep the OpenAI envelope:
rate_limit_exceeded, free_tier_daily_limit
and insufficient_quota at 429, plus model_not_found at 404 and
model_unavailable at 503. A client here needs to read both shapes.
Limits
Next
Transcribe a meeting
The recipe end to end, including saving and naming.
Speech to text
Plain transcription, and the request fields you share with it.
Sessions
The other kind of record: live conversations.
Compliance
Recording and consent duties that come with keeping audio.