Home → Blog → Speech to text in Python: from one file to a working script
Speech to text in Python: from one file to a working script
Speech-to-text in Python is four lines of code. Everything else in this guide is about the parts that are not obvious: which response format to ask for, what to do when the file is too big, and why your first script will be slower than it needs to be.
Install and first request
One dependency — the official OpenAI SDK. The API is protocol-compatible, so no special client is needed:
pip install openai
from openai import OpenAI
client = OpenAI(base_url="https://voicesscribe.com/v1", api_key="your key")
with open("audio.mp3", "rb") as f:
result = client.audio.transcriptions.create(model="whisper-1", file=f)
print(result.text)
That is the whole thing. Keep the key in an environment variable rather than in the source:
import os
client = OpenAI(base_url="https://voicesscribe.com/v1", api_key=os.environ["VS_KEY"])Choosing the response format
The default returns an object with a text field. Three other formats matter:
| Format | What you get | Use it when |
|---|---|---|
json | Object with .text | Default; you only need the words |
verbose_json | Segments, timings, detected language | Timestamps, chapters, quality checks |
srt / vtt | Ready subtitle file as a string | Captions for video |
text | Bare string, no wrapper | Piping into another tool |
With verbose_json the response also carries the detected language and its probability, which is the cheapest quality signal you will get:
r = client.audio.transcriptions.create(
model="whisper-1", file=f, response_format="verbose_json",
)
for s in r.segments:
print(f"[{s.start:6.1f}] {s.text.strip()}")
if r.language_probability < 0.6:
print("suspicious recording — worth a manual check")Handling errors properly
The SDK raises typed exceptions, so handling them is straightforward. The distinction that matters: some errors are worth retrying, some will fail identically forever.
from openai import APIStatusError, APIConnectionError
try:
r = client.audio.transcriptions.create(model="whisper-1", file=f)
except APIConnectionError:
... # network — retrying makes sense
except APIStatusError as e:
if e.status_code == 401:
raise RuntimeError("invalid API key")
if e.status_code == 413:
raise RuntimeError("file over 25 MB — re-encode or split it")
if e.status_code == 429:
... # rate limit or minutes — back off
raise
A 400 usually means the file is empty or corrupted. Check that it opens in a player before blaming the API.
Files larger than 25 MB
The request limit is 25 MB. Two ways past it, in order of preference.
Re-encode first. Most oversized files are oversized because they are wav or high-bitrate stereo. Mono at 16 kHz is what the model uses internally anyway:
ffmpeg -i input.wav -ac 1 -ar 16000 -b:a 48k output.mp3
That turns an hour of audio into roughly 25 MB — most files stop needing to be split at all.
Then split, if still needed. Cut on pauses rather than at fixed minutes, so sentences stay intact:
ffmpeg -i long.mp3 -f segment -segment_time 1800 -c copy part%03d.mp3Making it faster
The first script everyone writes processes files one at a time and spends almost all of its wall-clock waiting on the network. Transcription is IO-bound, so threads fix it:
from concurrent.futures import ThreadPoolExecutor
def transcribe(path):
with open(path, "rb") as f:
return client.audio.transcriptions.create(model="whisper-1", file=f).text
with ThreadPoolExecutor(max_workers=4) as pool:
texts = list(pool.map(transcribe, paths))
Set max_workers from your plan's requests-per-second limit, not from the number of CPU cores. Going wider than the limit converts successful requests into 429s.
Improving accuracy on your own vocabulary
The single most underused parameter is prompt. It does not appear in the output — it biases recognition towards the words you list:
r = client.audio.transcriptions.create(
model="whisper-1", file=f,
prompt="Products: Kestrel, Hawknest. Speakers: Duarte, Ivanova.",
language="en",
)
Twenty to forty terms that actually occur in your audio work well; a paragraph of general description does nothing. Adding language when the audio is single-language removes detection mistakes on short clips.
Mistakes that cost the most time
- Reading the whole file into memory to pass it as bytes. Pass the file object — the SDK streams it.
- Retrying an empty result. An empty string means there was no speech, not that something failed. Retrying only spends minutes.
- Leaving the default timeout on long files. The client default suits short clips; raise it for hour-long recordings.
- Upsampling 8 kHz phone audio to 44 kHz hoping for better accuracy. It adds bytes, not information.
Try it on your own recordings. Sign-up takes a minute, and the free minutes are enough to judge the quality.
Get a free API keyFrequently asked questions
Do I need a special Python library?
No, the official openai package works as is — the API is protocol-compatible. Only the base URL and the key differ from the OpenAI defaults.
Which audio formats does Python need to prepare?
None specifically: ogg, opus, mp3, wav, m4a and webm are accepted as they are. Converting to mono 16 kHz mp3 is only about staying under the 25 MB request limit.
How do I get timestamps in Python?
Ask for response_format=verbose_json — the response contains segments with start and end times, plus the detected language and its probability.
Can I transcribe many files in parallel?
Yes, with a ThreadPoolExecutor. Transcription waits on the network, so threads are the right tool; size the pool below your plan's requests-per-second limit.
What should I do about files over 25 MB?
Re-encode to mono 16 kHz first — that alone fixes most cases. If the file is still too large, split it on pauses and merge the results.
Related reading
- Speech to text in Node.js: working code and the usual pitfalls — How to transcribe audio from Node.js: the official SDK, streams and FormData, handling uploads in Express, timeouts and retries — with code you can paste.
- How to build a batch transcription pipeline for an audio archive — Transcribing thousands of recordings without losing any: a work queue, concurrency, retries, resuming after a crash and keeping the bill under control.
- How to improve speech-to-text accuracy: eight practical fixes — Eight changes that actually move transcription quality: audio preparation, language hints, the prompt parameter, chunking, formats, and how to measure word error rate.