Speech to text
Transcripts of audio files with POST /v1/audio/transcriptions, with word and segment timestamps.
Access: Keys with the media:read or media:generate scope, on an account with media access granted by Albastar Corp.
POST /v1/audio/transcriptions takes a multipart upload of an audio file and a model, and returns the transcript.
The request shape is OpenAI's, so OpenAI SDKs work with the base URL changed. The key needs the media:generate
scope. The model is parakeet, which transcribes 25 European languages:
Transcription models.
Transcribe with word timestamps
response_format=verbose_json returns the transcript with timings. timestamp_granularities[] picks segment
(the default), word, or both. The example downloads the
reference clip of Narrator A, a
synthetic voice, and 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"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()
t = client.audio.transcriptions.create(
model="parakeet",
file=("reference.mp3", clip.content),
response_format="verbose_json",
timestamp_granularities=["word"],
)
for w in t.words:
print(f"{w.start:6.2f} {w.end:6.2f} {w.word}")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()}`);
for (const w of (await res.json()).words) {
console.log(w.start.toFixed(2), w.end.toFixed(2), w.word);
}The response Parakeet returned for the clip:
{
"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. With segment,
segments lists each segment with start, end and text. 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 formats
response_format | Content type | Body |
|---|---|---|
json | application/json | {"text": "..."}; the default |
text | text/plain | The transcript and a newline |
verbose_json | application/json | task, language, duration, text, and segments, words or both |
The file is WAV, MP3, M4A, Ogg, WebM or FLAC, 20 MB at most.
Language
language takes auto (the default) or one of Parakeet's 25 language codes, such as en or de; another value
fails with 400 bad-param. A code other than auto goes to the model with the audio as a hint; Parakeet detects the
spoken language itself. 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. The codes:
GET /v1/media/models?kind=transcription.
OpenAI model name
whisper-1 runs as parakeet, so code written for OpenAI transcribes without changes in Parakeet's 25 European
languages. Audio in another language, such as Japanese or Arabic, is outside those 25 languages. prompt and
temperature are accepted and ignored; stream takes false only, because the transcript arrives whole.
Transcription jobs
POST /v1/media/jobs with kind transcription transcribes a file already on the account, or an https:// URL,
without a second upload. params.audio takes an upload up_…, a job result job:<id>/<i>, a saved voice vo_… or
an https:// URL; params.timestamps true adds word timings. The result entry carries the whole transcript in
text. The example uploads the reference clip, then transcribes the upload as a job.
curl -o reference.mp3 \
https://api.albastov.com/v1/media/samples/reference-848c3d555461736a.mp3
UPLOAD=$(curl -s https://api.albastov.com/v1/media/uploads \
-H "Authorization: Bearer $ALBASTAR_API_KEY" \
-H "Content-Type: audio/mpeg" \
--data-binary @reference.mp3 \
| python3 -c 'import json, sys; print(json.load(sys.stdin)["id"])')
curl -s "https://api.albastov.com/v1/media/jobs?wait=30" \
-H "Authorization: Bearer $ALBASTAR_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"kind\": \"transcription\", \"model\": \"parakeet\",
\"params\": {\"audio\": \"$UPLOAD\"}}" \
| python3 -c '
import json, sys
job = json.load(sys.stdin)
print(job["state"], job["results"][0]["text"])'done Okay, so here's the plan. We land just after sunset, grab the bags, …The output above is shortened; the whole transcript is the text of the response above. A transcription waits in
the queue up to its queue_timeout_s, 60 s. On POST /v1/audio/transcriptions, a job not done in time answers 503
with code queued and job_id, as on the speech route:
Waiting for a result.
Reference
- Transcriptions reference: every parameter, header and
error of
POST /v1/audio/transcriptions. - Media jobs reference: transcription jobs and
?wait. - Uploads reference:
POST /v1/media/uploads.