Transcriptions
POST /v1/audio/transcriptions returns the transcript of an audio file, with optional timestamps.
Access: Keys with the media:generate scope, on an account with media access granted by Albastar Corp.
POST /v1/audio/transcriptions returns the transcript of an uploaded audio file. The request and response shapes
are OpenAI's.
Parameters
A multipart/form-data body. A field outside the list fails with 400 bad-param.
| Name | Type | Description |
|---|---|---|
file required | file | WAV, MP3, M4A, Ogg, WebM or FLAC audio, 20 MB at most |
model required | string | parakeet, or OpenAI's whisper-1, which runs as parakeet |
language | string | auto (default) or one of Parakeet's 25 language codes, such as en or de; another value fails with 400 bad-param. Parakeet detects the spoken language itself and does not use the code |
response_format | string | json (default), text or verbose_json |
timestamp_granularities[] | string | With verbose_json: segment (default), word, or both as two fields |
prompt | string | Accepted and ignored |
temperature | number | Accepted and ignored |
stream | string | false only: the transcript arrives whole |
Transcription models, each model's parameters and the 25 language codes: GET /v1/media/models?kind=transcription
(Media jobs reference).
Headers
| Name | Description |
|---|---|
Idempotency-Key | Request. A request of the same key with the same Idempotency-Key, fields and file returns the same job's transcript, or the same job's error. Without the header, an identical request of the same key in the same 10-minute window returns the first request's job, unless that job failed, expired or was cancelled: then the request runs as a new job. The windows start at :00, :10, :20, :30, :40 and :50 past the hour, UTC |
X-Queue-Timeout | Request. Seconds the job may wait in the queue, a whole number of 1 or more; a value above the kind's queue timeout is lowered to the queue timeout |
X-Job-Id | Response. The media job mj_… that made the transcript |
X-Trace-Id | Response, with X-Job-Id. The job's trace_id, 32 lowercase hex characters |
Server-Timing | Response, with X-Job-Id. One entry <name>;dur=<ms>: whole milliseconds from the request's arrival to its job being queued |
X-Queue-Timeout | Response. The job's queue timeout in seconds |
Retry-After | Response, on 503. 5 |
X-Should-Retry | Response, on 503 queued and 503 queue-timeout. false: OpenAI SDKs do not repeat the request |
Request
The example downloads the reference clip of Narrator A, a synthetic voice, then transcribes the clip with word timestamps.
curl
curl -o reference.mp3 \
https://api.albastov.com/v1/media/samples/reference-848c3d555461736a.mp3
curl https://api.albastov.com/v1/audio/transcriptions \
-H "Authorization: Bearer $ALBASTAR_API_KEY" \
-F model=parakeet \
-F [email protected] \
-F response_format=verbose_json \
-F "timestamp_granularities[]=word" \
--dump-header -Python
import os
import httpx
from openai import OpenAI
CLIP = (
"https://api.albastov.com/v1/media/samples/"
"reference-848c3d555461736a.mp3"
)
client = OpenAI(
base_url="https://api.albastov.com/v1",
api_key=os.environ["ALBASTAR_API_KEY"],
)
clip = httpx.get(CLIP)
clip.raise_for_status()
res = client.audio.transcriptions.with_raw_response.create(
model="parakeet",
file=("reference.mp3", clip.content),
response_format="verbose_json",
timestamp_granularities=["word"],
)
t = res.parse()
print(res.headers["x-job-id"], t.text, len(t.words))JavaScript
const base = "https://api.albastov.com/v1";
const clip = await fetch(
`${base}/media/samples/reference-848c3d555461736a.mp3`,
);
if (!clip.ok) throw new Error(`${clip.status} ${await clip.text()}`);
const form = new FormData();
form.append("model", "parakeet");
form.append("file", await clip.blob(), "reference.mp3");
form.append("response_format", "verbose_json");
form.append("timestamp_granularities[]", "word");
const res = await fetch(`${base}/audio/transcriptions`, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.ALBASTAR_API_KEY}` },
body: form,
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const t = await res.json();
console.log(res.headers.get("x-job-id"), t.text, t.words.length);Response
200 with the transcript. The response Parakeet returned for the reference clip, with the header
X-Job-Id: mj_qUCsYGCBLSxwrxRjJZUffq:
{
"duration": 13.975,
"language": "auto",
"task": "transcribe",
"text": "Okay, so here's the plan. We land just after sunset, …",
"words": [
{"end": 0.72, "start": 0.16, "word": "Okay,"},
{"end": 0.96, "start": 0.72, "word": "so"},
{"end": 1.28, "start": 0.96, "word": "here's"},
{"end": 1.6, "start": 1.28, "word": "the"},
{"end": 2.08, "start": 1.6, "word": "plan."}
]
}The response above is shortened: text holds the whole transcript, and words lists all 41 words. The whole
text, wrapped at 76 characters:
Okay, so here's the plan. We land just after sunset, grab the bags, and head
straight for the harbor. If the ferry's late again, and honestly, it usually
is, we'll get dinner by the water and wait it out. Sound good.response_format | Body |
|---|---|
json | {"text": "..."} as application/json |
text | The transcript and a newline, as text/plain |
verbose_json | task, language, duration in seconds, text; segments unless only word was asked for; words when word was asked for |
language in verbose_json is the language the model reports, else the language sent: for the reference clip,
sent without language, the value was auto. A segment has id, start, end and text, plus OpenAI's seek,
tokens, temperature, avg_logprob, compression_ratio and no_speech_prob, which are always 0 or empty. A
word has word, start and end in seconds.
The request waits for its job up to the job's queue timeout while the job is queued (60 s for transcription), and at
most 85 s from arrival. An account holds 16 waiting requests at most; past that, the route answers 503 queued at
once.
Errors
Errors use OpenAI's shape, {"error": {"message", "type", "param", "code"}}, plus job_id when a job exists.
Branch on code.
| Status | Code | Meaning |
|---|---|---|
| 400 | bad-param | A field is missing, unknown or out of range; param names the field (file, model, language, response_format, timestamp_granularities, stream, X-Queue-Timeout) |
| 400 | bad-upload | The multipart body has no boundary or did not arrive whole |
| 413 | too-large | The file is over 20 MB |
| 415 | multipart-only | The body is not multipart/form-data |
| 415 | not-audio | The file is not WAV, MP3, M4A, Ogg, WebM or FLAC |
| 429 | budget-exhausted | The account's daily generation time is used up: That would go over today's generation time. It starts over at midnight UTC.; resets_at is the next 00:00 UTC |
| 429 | too-many-open | The key has 1,000 jobs queued or running, the limit per key: You have 1000 jobs queued or running; that's the limit. |
| 502 | The job's error code | The job failed or was cancelled; job_id names the job |
| 503 | queued | The job is still queued: The job is still queued. It stays in /v1/media/jobs; poll GET /v1/media/jobs/<id>?wait=30 for it.; job_id names the job |
| 503 | queue-timeout | The job waited in the queue past its queue timeout and has expired. |
Key, scope and rate-limit errors: Errors.