Home → Blog → How to transcribe a recording that does not fit one request
How to transcribe a recording that does not fit one request
A four-hour conference recording, a day-long dictation dump, a webinar with screen capture — none of them fit into a single request. The job breaks into three steps: compress, split on pauses, merge the text back. Here is the working recipe with code.
Compress before you split
Try compression first; it is often enough on its own. An hour of speech in opus is about 11 MB, so a two-hour recording fits the limit whole:
ffmpeg -i conference.wav -vn -ac 1 -ar 16000 -c:a libopus -b:a 24k conference.ogg
Splitting only makes sense when the compressed file is still too large, or when you want parallel processing for speed.
Where to cut so nothing breaks
Cutting at fixed intervals is easy and will sooner or later slice a word in half, leaving garbage at the seam. Cutting on silence is safer. First find the pauses:
ffmpeg -i long.ogg -af silencedetect=noise=-35dB:d=1 -f null - 2>&1 | grep silence_end
Then cut at the pause nearest your target length:
ffmpeg -i long.ogg -ss 0 -to 912.4 -c copy part001.ogg
A practical compromise is 10–15 minute chunks: convenient to send in parallel, and a bad seam costs very little.
Process chunks in parallel
Chunks are independent, so send them at once and keep order by filename:
import concurrent.futures as cf, pathlib
from openai import OpenAI
client = OpenAI(base_url="https://voicesscribe.com/v1", api_key="your key")
def one(path):
with path.open("rb") as f:
return path.name, client.audio.transcriptions.create(model="whisper-1", file=f).text
parts = sorted(pathlib.Path(".").glob("part*.ogg"))
with cf.ThreadPoolExecutor(max_workers=4) as pool:
result = dict(pool.map(one, parts))
full = "\n".join(result[p.name] for p in parts)
pathlib.Path("conference.txt").write_text(full, encoding="utf-8")
Match the worker count to the request-rate limit of your plan: overshoot it and you collect 429 responses and repeat the work.
Continuous timestamps
If you need navigation rather than plain text, ask for segments and add each chunk's offset:
offset = 0.0
for path in parts:
with path.open("rb") as f:
r = client.audio.transcriptions.create(
model="whisper-1", file=f, response_format="verbose_json")
for seg in r.segments:
print(round(seg["start"] + offset, 1), seg["text"].strip())
offset += r.duration
Timestamps then stay aligned with the original recording and can drive a player.
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
What is the file size limit?
25 MB per request. In opus that is roughly two hours of speech, so compression alone usually removes the need to split.
What does a 413 error mean?
The file exceeds the allowed size. Compress to opus or a low-bitrate mp3, or split it into parts.
Is meaning lost at chunk boundaries?
Not if you cut on silence. Fixed-interval cuts can drop a word at the seam, which is why finding pauses is worth the extra step.
Can chunks be processed at the same time?
Yes, they are independent. The only constraint is the requests-per-second limit of your plan.
Related reading
- Preparing audio for transcription: ffmpeg recipes — Copy-paste ffmpeg commands for speech recognition: extract audio from video, downmix to mono, trim silence, split on pauses and separate stereo channels.
- 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.
- Transcription API errors and what they actually mean — A walkthrough of transcription API status codes: why 401, 400, 413, 429 and 502 happen, how to fix each one and which failures are worth retrying.