text field is raw transcript text only — it does not include timestamps or speaker labels. To build a custom text export in a format such as [Speaker] timecode -> text, enable speaker labels and construct the output from the utterances array (which contains speaker, start, end, and text for each utterance). See the Timestamped transcripts guide and the Create subtitles with speaker labels cookbook for examples.
Export SRT or VTT caption files
You can export completed transcripts in SRT or VTT format, which can be used for subtitles and closed captions in videos. You can also customize the maximum number of characters per caption by specifying thechars_per_caption parameter.
import assemblyai as aai
aai.settings.api_key = "<YOUR_API_KEY>"
# audio_file = "./local_file.mp3"
audio_file = "https://assembly.ai/wildfires.mp3"
config = aai.TranscriptionConfig(
language_detection=True
)
transcript = aai.Transcriber(config=config).transcribe(audio_file)
if transcript.status == "error":
raise RuntimeError(f"Transcription failed: {transcript.error}")
srt = transcript.export_subtitles_srt(
# Optional: Customize the maximum number of characters per caption
chars_per_caption=32
)
with open(f"transcript_{transcript.id}.srt", "w") as srt_file:
srt_file.write(srt)
# vtt = transcript.export_subtitles_vtt()
# with open(f"transcript_{transcript_id}.vtt", "w") as vtt_file:
# vtt_file.write(vtt)
import requests
import time
base_url = "https://api.assemblyai.com"
headers = {
"authorization": "<YOUR_API_KEY>"
}
with open("./my-audio.mp3", "rb") as f:
response = requests.post(base_url + "/v2/upload",
headers=headers,
data=f)
upload_url = response.json()["upload_url"]
data = {
"audio_url": upload_url, # You can also use a URL to an audio or video file on the web
"language_detection": True
}
url = base_url + "/v2/transcript"
response = requests.post(url, json=data, headers=headers)
transcript_id = response.json()['id']
polling_endpoint = base_url + "/v2/transcript/" + transcript_id
while True:
transcription_result = requests.get(polling_endpoint, headers=headers).json()
if transcription_result['status'] == 'completed':
print(f"Transcript ID: {transcript_id}")
break
elif transcription_result['status'] == 'error':
raise RuntimeError(f"Transcription failed: {transcription_result['error']}")
else:
time.sleep(3)
# chars_per_caption is optional
srt_response = requests.get(f"{polling_endpoint}/srt?chars_per_caption=32", headers=headers)
with open(f"transcript_{transcript_id}.srt", "w") as srt_file:
srt_file.write(srt_response.text)
# vtt_response = requests.get(f"{polling_endpoint}/vtt", headers=headers)
# with open(f"transcript_{transcript_id}.vtt", "w") as vtt_file:
# vtt_file.write(vtt_response.text)
import { AssemblyAI } from "assemblyai";
import fs from "fs";
const client = new AssemblyAI({
apiKey: "<YOUR_API_KEY>",
});
// const audioFile = './local_file.mp3'
const audioFile = "https://assembly.ai/wildfires.mp3";
const params = {
audio: audioFile,
language_detection: true,
};
const run = async () => {
const transcript = await client.transcripts.transcribe(params);
let srt = await client.transcripts.subtitles(transcript.id, "srt", 32);
fs.writeFileSync(`transcript_${transcript.id}.srt`, srt);
// let vtt = await client.transcripts.subtitles(transcript.id, 'vtt', 32)
// fs.writeFileSync(`transcript_${transcript.id}.vtt`, vtt)
};
run();
import fs from "fs-extra";
const baseUrl = "https://api.assemblyai.com";
const headers = {
authorization: "<YOUR_API_KEY>",
};
const path = "./my-audio.mp3";
const audioData = await fs.readFile(path);
let res = await fetch(`${baseUrl}/v2/upload`, {
method: "POST",
headers,
body: audioData,
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const uploadResponse = await res.json();
const uploadUrl = uploadResponse.upload_url;
const data = {
audio_url: uploadUrl, // You can also use a URL to an audio or video file on the web
language_detection: true,
};
const url = `${baseUrl}/v2/transcript`;
res = await fetch(url, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const response = await res.json();
const transcriptId = response.id;
const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;
while (true) {
res = await fetch(pollingEndpoint, { headers });
if (!res.ok) throw new Error(`Error: ${res.status}`);
const transcriptionResult = await res.json();
if (transcriptionResult.status === "completed") {
console.log(transcriptionResult.text);
break;
} else if (transcriptionResult.status === "error") {
throw new Error(`Transcription failed: ${transcriptionResult.error}`);
} else {
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
const srtEndpoint = `${baseUrl}/v2/transcript/${transcriptId}/srt?chars_per_caption=32`;
res = await fetch(srtEndpoint, { headers });
if (!res.ok) throw new Error(`Error: ${res.status}`);
const srt = await res.text();
fs.writeFileSync(`transcript_${transcriptId}.srt`, srt);
// const vttEndpoint = `${baseUrl}/v2/transcript/${transcriptId}/vtt?chars_per_caption=32`
// const vtt = await fetch(vttEndpoint, { headers }).then(res => res.text())
// fs.writeFileSync(`transcript_${transcriptId}.vtt`, vtt)
Export paragraphs
You can retrieve transcripts that are automatically segmented into paragraphs. The text of the transcript is broken down by paragraphs, along with additional metadata.import assemblyai as aai
aai.settings.api_key = "<YOUR_API_KEY>"
# audio_file = "./local_file.mp3"
audio_file = "https://assembly.ai/wildfires.mp3"
config = aai.TranscriptionConfig(
language_detection=True
)
transcript = aai.Transcriber(config=config).transcribe(audio_file)
if transcript.status == "error":
raise RuntimeError(f"Transcription failed: {transcript.error}")
paragraphs = transcript.get_paragraphs()
for paragraph in paragraphs:
print(paragraph.text)
print()
import requests
import time
base_url = "https://api.assemblyai.com"
headers = {
"authorization": "<YOUR_API_KEY>"
}
with open("./my-audio.mp3", "rb") as f:
response = requests.post(base_url + "/v2/upload",
headers=headers,
data=f)
upload_url = response.json()["upload_url"]
data = {
"audio_url": upload_url, # You can also use a URL to an audio or video file on the web
"language_detection": True
}
url = base_url + "/v2/transcript"
response = requests.post(url, json=data, headers=headers)
transcript_id = response.json()['id']
polling_endpoint = base_url + "/v2/transcript/" + transcript_id
while True:
transcription_result = requests.get(polling_endpoint, headers=headers).json()
if transcription_result['status'] == 'completed':
print(f"Transcript ID: {transcript_id}")
break
elif transcription_result['status'] == 'error':
raise RuntimeError(f"Transcription failed: {transcription_result['error']}")
else:
time.sleep(3)
paragraphs = requests.get(polling_endpoint + '/paragraphs', headers=headers).json()['paragraphs']
for paragraph in paragraphs:
print(paragraph['text'])
print()
import { AssemblyAI } from "assemblyai";
const client = new AssemblyAI({
apiKey: "<YOUR_API_KEY>",
});
// const audioFile = './local_file.mp3'
const audioFile = "https://assembly.ai/wildfires.mp3";
const params = {
audio: audioFile,
language_detection: true,
};
const run = async () => {
const transcript = await client.transcripts.transcribe(params);
const { paragraphs } = await client.transcripts.paragraphs(transcript.id);
for (const paragraph of paragraphs) {
console.log(paragraph.text);
}
};
run();
import fs from "fs-extra";
const baseUrl = "https://api.assemblyai.com";
const headers = {
authorization: "<YOUR_API_KEY>",
};
const path = "./my-audio.mp3";
const audioData = await fs.readFile(path);
let res = await fetch(`${baseUrl}/v2/upload`, {
method: "POST",
headers,
body: audioData,
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const uploadResponse = await res.json();
const uploadUrl = uploadResponse.upload_url;
const data = {
audio_url: uploadUrl, // You can also use a URL to an audio or video file on the web
language_detection: true,
};
const url = `${baseUrl}/v2/transcript`;
res = await fetch(url, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const response = await res.json();
const transcriptId = response.id;
const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;
while (true) {
res = await fetch(pollingEndpoint, { headers });
if (!res.ok) throw new Error(`Error: ${res.status}`);
const transcriptionResult = await res.json();
if (transcriptionResult.status === "completed") {
console.log(transcriptionResult.text);
break;
} else if (transcriptionResult.status === "error") {
throw new Error(`Transcription failed: ${transcriptionResult.error}`);
} else {
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
const paragraphsEndpoint = `${baseUrl}/v2/transcript/${transcriptId}/paragraphs`;
res = await fetch(paragraphsEndpoint, { headers });
if (!res.ok) throw new Error(`Error: ${res.status}`);
const paragraphsResponse = await res.json();
const paragraphs = paragraphsResponse.paragraphs;
for (const paragraph of paragraphs) {
console.log(paragraph.text);
console.log();
}
Export sentences
You can retrieve transcripts that are automatically segmented into sentences, for a more reader-friendly experience. The text of the transcript is broken down by sentences, along with additional metadata.import assemblyai as aai
aai.settings.api_key = "<YOUR_API_KEY>"
# audio_file = "./local_file.mp3"
audio_file = "https://assembly.ai/wildfires.mp3"
config = aai.TranscriptionConfig(
language_detection=True
)
transcript = aai.Transcriber(config=config).transcribe(audio_file)
if transcript.status == "error":
raise RuntimeError(f"Transcription failed: {transcript.error}")
sentences = transcript.get_sentences()
for sentence in sentences:
print(sentence.text)
print()
import requests
import time
base_url = "https://api.assemblyai.com"
headers = {
"authorization": "<YOUR_API_KEY>"
}
with open("./my-audio.mp3", "rb") as f:
response = requests.post(base_url + "/v2/upload",
headers=headers,
data=f)
upload_url = response.json()["upload_url"]
data = {
"audio_url": upload_url, # You can also use a URL to an audio or video file on the web
"language_detection": True
}
url = base_url + "/v2/transcript"
response = requests.post(url, json=data, headers=headers)
transcript_id = response.json()['id']
polling_endpoint = base_url + "/v2/transcript/" + transcript_id
while True:
transcription_result = requests.get(polling_endpoint, headers=headers).json()
if transcription_result['status'] == 'completed':
print(f"Transcript ID: {transcript_id}")
break
elif transcription_result['status'] == 'error':
raise RuntimeError(f"Transcription failed: {transcription_result['error']}")
else:
time.sleep(3)
sentences = requests.get(polling_endpoint + '/sentences', headers=headers).json()['sentences']
for sentence in sentences:
print(sentence['text'])
print()
import { AssemblyAI } from "assemblyai";
const client = new AssemblyAI({
apiKey: "<YOUR_API_KEY>",
});
// const audioFile = './local_file.mp3'
const audioFile = "https://assembly.ai/wildfires.mp3";
const params = {
audio: audioFile,
language_detection: true,
};
const run = async () => {
const transcript = await client.transcripts.transcribe(params);
const { sentences } = await client.transcripts.sentences(transcript.id);
for (const sentence of sentences) {
console.log(sentence.text);
}
};
run();
import fs from "fs-extra";
const baseUrl = "https://api.assemblyai.com";
const headers = {
authorization: "<YOUR_API_KEY>",
};
const path = "./my-audio.mp3";
const audioData = await fs.readFile(path);
let res = await fetch(`${baseUrl}/v2/upload`, {
method: "POST",
headers,
body: audioData,
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const uploadResponse = await res.json();
const uploadUrl = uploadResponse.upload_url;
const data = {
audio_url: uploadUrl, // You can also use a URL to an audio or video file on the web
language_detection: true,
};
const url = `${baseUrl}/v2/transcript`;
res = await fetch(url, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const response = await res.json();
const transcriptId = response.id;
const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;
while (true) {
res = await fetch(pollingEndpoint, { headers });
if (!res.ok) throw new Error(`Error: ${res.status}`);
const transcriptionResult = await res.json();
if (transcriptionResult.status === "completed") {
console.log(transcriptionResult.text);
break;
} else if (transcriptionResult.status === "error") {
throw new Error(`Transcription failed: ${transcriptionResult.error}`);
} else {
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
const sentencesEndpoint = `${baseUrl}/v2/transcript/${transcriptId}/sentences`;
res = await fetch(sentencesEndpoint, { headers });
if (!res.ok) throw new Error(`Error: ${res.status}`);
const sentencesResponse = await res.json();
const sentences = sentencesResponse.sentences;
for (const sentence of sentences) {
console.log(sentence.text);
console.log();
}
Word-level timestamps
The response also includes an array with information about each word:import assemblyai as aai
aai.settings.api_key = "<YOUR_API_KEY>"
# audio_file = "./local_file.mp3"
audio_file = "https://assembly.ai/wildfires.mp3"
config = aai.TranscriptionConfig(
language_detection=True
)
transcript = aai.Transcriber().transcribe(audio_file, config)
for word in transcript.words:
print(f"Word: {word.text}, Start: {word.start}, End: {word.end}, Confidence: {word.confidence}")
import requests
import time
base_url = "https://api.assemblyai.com"
headers = {
"authorization": "<YOUR_API_KEY>"
}
with open("./my-audio.mp3", "rb") as f:
response = requests.post(base_url + "/v2/upload",
headers=headers,
data=f)
upload_url = response.json()["upload_url"]
data = {
"audio_url": upload_url, # You can also use a URL to an audio or video file on the web
"language_detection": True
}
url = base_url + "/v2/transcript"
response = requests.post(url, json=data, headers=headers)
transcript_id = response.json()['id']
polling_endpoint = base_url + "/v2/transcript/" + transcript_id
while True:
transcription_result = requests.get(polling_endpoint, headers=headers).json()
if transcription_result['status'] == 'completed':
for word in transcription_result['words']:
print(f"Word: {word['text']}, Start: {word['start']}, End: {word['end']}, Confidence: {word['confidence']}")
break
elif transcription_result['status'] == 'error':
raise RuntimeError(f"Transcription failed: {transcription_result['error']}")
else:
time.sleep(3)
import { AssemblyAI } from "assemblyai";
const client = new AssemblyAI({
apiKey: "<YOUR_API_KEY>",
});
// const audioFile = './local_file.mp3'
const audioFile = "https://assembly.ai/wildfires.mp3";
const params = {
audio: audioFile,
language_detection: true,
};
const run = async () => {
const transcript = await client.transcripts.transcribe(params);
console.log(transcript.text);
// Print word-level details
for (const word of transcript.words) {
console.log(
`Word: ${word.text}, Start: ${word.start}, End: ${word.end}, Confidence: ${word.confidence}`
);
}
};
run();
import fs from "fs-extra";
const baseUrl = "https://api.assemblyai.com";
const headers = {
authorization: "<YOUR_API_KEY>",
};
const path = "./my-audio.mp3";
const audioData = await fs.readFile(path);
let res = await fetch(`${baseUrl}/v2/upload`, {
method: "POST",
headers,
body: audioData,
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const uploadResponse = await res.json();
const uploadUrl = uploadResponse.upload_url;
const data = {
audio_url: uploadUrl, // You can also use a URL to an audio or video file on the web
language_detection: true,
};
const url = `${baseUrl}/v2/transcript`;
res = await fetch(url, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json" },
body: JSON.stringify(data),
});
if (!res.ok) throw new Error(`Error: ${res.status}`);
const response = await res.json();
const transcriptId = response.id;
const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;
while (true) {
res = await fetch(pollingEndpoint, { headers });
if (!res.ok) throw new Error(`Error: ${res.status}`);
const transcriptionResult = await res.json();
if (transcriptionResult.status === "completed") {
console.log(transcriptionResult.text);
// Print word-level details
for (const word of transcriptionResult.words) {
console.log(
`Word: ${word.text}, Start: ${word.start}, End: ${word.end}, Confidence: ${word.confidence}`
);
}
break;
} else if (transcriptionResult.status === "error") {
throw new Error(`Transcription failed: ${transcriptionResult.error}`);
} else {
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
API Reference
{
words: [
{
text: "Smoke",
start: 240,
end: 640,
confidence: 0.70473,
speaker: null,
},
{
text: "from",
start: 680,
end: 968,
confidence: 0.99967,
speaker: null,
},
{
text: "hundreds",
start: 1024,
end: 1416,
confidence: 0.99795,
speaker: null,
},
{
text: "of",
start: 1448,
end: 1592,
confidence: 0.99926,
speaker: null,
},
{
text: "wildfires",
start: 1616,
end: 2248,
confidence: 0.99838,
speaker: null,
},
{
text: "in",
start: 2264,
end: 2440,
confidence: 0.99782,
speaker: null,
},
{
text: "Canada",
start: 2480,
end: 2968,
confidence: 0.99977,
speaker: null,
},
],
}
Additional resources
Is there a way to generate SRT or VTT captions with speaker labels?
Learn how to create caption files that include speaker identification.