Diarization
Attribute each word to a speaker in multi-speaker audio, and read the speaker field on each word.
Overview
Diarization attributes each transcribed word to a speaker. Turn it on and each attributed word carries a speaker label. Use it for interviews, meetings, and two-party calls.
Request
curl https://api.sprag.ai/v1/audio/transcriptions \
-H "Authorization: Bearer $SPRAG_API_KEY" \
-F [email protected] \
-F model=rhythm \
-F response_format=verbose_json \
-F speaker_labels=true \
-F num_speakers=2| Field | Type | Default | Notes |
|---|---|---|---|
response_format | string | json | Must be verbose_json. |
speaker_labels | boolean | false | Turns diarization on. |
num_speakers | integer | unset | The number of speakers, when you know it. |
Speaker labels live on the word objects, which only the verbose response
carries, so send response_format=verbose_json. You do not need
timestamp_granularities[] as well; if you do send one, keep word in it.
See timestamps for that payload.
Pass num_speakers when you know the count. It makes attribution more
reliable on noisy audio than leaving the count to be inferred.
Response
Each attributed word gains a speaker, a 0-indexed integer.
{
"text": "So how did the migration go? Better than expected.",
"duration": 3.4,
"words": [
{ "word": "So", "start": 0.10, "end": 0.22, "speaker": 0 },
{ "word": "how", "start": 0.22, "end": 0.36, "speaker": 0 },
{ "word": "Better", "start": 1.51, "end": 1.88, "speaker": 1 },
{ "word": "than", "start": 1.88, "end": 2.02, "speaker": 1 }
],
"usage": { "input": { "audio": { "duration": "3" } } }
}Speaker indexes are assigned per request, so the same person in two separate files will not reliably get the same index. Do not carry an index across requests as a speaker identity.
Reading the speaker field
speaker is present on a word that was attributed to a speaker and absent on
one that was not. Expect a few unattributed words inside an otherwise diarized
transcript where speech overlaps or segments are very short.
Test for the key, not the value. Speaker 0 is a valid label and reads as
falsy, so a check like if (word.speaker) drops it.
if (!("speaker" in word)) {
// unattributed
} else {
// word.speaker is the 0-indexed label
}Grouping words into turns
The API returns per-word labels, not turns, so collapse runs of the same speaker client-side. Decide there how to handle unattributed words: joining them to the surrounding run usually reads better than emitting a one-word turn with no speaker.
Realtime
Diarization is available over REST. A realtime session delivers transcripts as input-transcription events without speaker labels.