Back in 2018, when me and my wife were settling down in Vienna, Austria, my wife was getting on-and-off gigs doing transcriptions, mostly meetings and anthropological fieldwork recordings. Sometimes I was helping her when she had more work than she could manage in a reasonable timeframe.
And here's the thing. I loved it.
Transcribing audio recordings is a perfect task for non-very-imaginative individuals who are somehow capable of zoning out and honing in on a task at the same time. Plus, some of the recordings were fascinating; especially anthropological interviews were really a blast to deal with.
Plus, while poorly paid, it was an easy piece of bread, and one you could get really good at. It's really the matter of bumping up your typing speed and being attentive enough when listening to the recording; and yeah, sometimes the recordings were pretty bad.
It is quite devastating to see this kind of jobs being taken over by AI solutions. Yeah, I guess it wasn't maintainable long term, and yeah, while taking away many opportunities, AI is opening plenty more. But all the new opportunities are open only for the exceptional, for the experimenters, entrepreneurs, and, increasingly, people with some spare funds to sink into a new venture. Somehow the scope for normal people---the not very imaginative individuals who are somehow capable of zoning out and honing in on a task at the same time---seem to be going away. I guess we are a dying breed.
In any case, the year is 2025 now, and my wife is studying cinematography. As we've accumulated quite some hours of interviews, both audio and video, for a project she's doing now, and as I don't really have time to transcribe them and translate them by hand (my Tamil is not nearly good enough, and the recordings are in Tamil), using some of the OpenAI APIs was the next easiest option.
The present script is a simple Python program to plug in openAI API, point at a folder with your recordings, and generate both transcripts and translations. The command I used last and which gave pretty good result was:
python batch_av2text.py "audio/oct11" --model gpt-4o-transcribe --target-lang en --translate-model gpt-5 --translate-context-prompt "This is an interview with a Chennai fishermonger discussing fish market operations, life history, and spirituality. Preserve Tamil fish names, market terminology, and religious terms accurately." --audio-bitrate 192 --audio-sample-rate 16000 --chunk-duration 60 --chunk-overlap 10 --timestamps chunk --stt-prompt-max-tokens 1800 --stt-prompt-prefix "இது சென்னை மீனம்மாவின் நேர்காணல் மற்றும் மீன் சந்தை பதிவுகள். பேச்சுவழக்கு தமிழ். மீன் சந்தை சூழல்: ஏலம், விலை பேச்சுவார்த்தை, மீன் வகைகள், வாடிக்கையாளர் உரையாடல்கள். நேர்காணல் தலைப்புகள்: வாழ்க்கை வரலாறு, மீன் வியாபாரம், ஆன்மீகம், அன்றாட." --output-dir transcriptsYeah, the prompt prefix was in Tamil, I guess it could've been in English as well but where's the swag in that? It saves output in the same folders as the recordings, and you can optionally save the transcripts and translations in a separate folder for easy sharing.
Delimiting chunks (and I set them at 60 sec usually) is for the purpose of definite timestamps, as 4o-translate has a problem with these. Whisper-1 can do timestamps, but in my experience (and my experience was in colloquial Tamil) it has worse performance.
Transcriptions still malfunction when there's no discernible dialogue in a given chunk, there's some hallucinations then, so be wary of that.
Otherwise, the quality of transcriptions is surprisingly good. Translations are OK, and can be nicely optimized by prompt optimization, --translate-context-prompt.
I didn't test it yet on video recordings, though the script theoretically should be able to handle these. Let me know if you do test these and how it went.
Script was mostly vibe-coded and while it took some finetuning, feel free to use it for your own nefarious purposes. I have a few ideas at the back of my head on how to potentially develop this into a more interesting project (maybe even commercially viable), but these developments will be entirely dependent on the time I will have on my hands in the coming weeks.
Some AI-handled documentation follows. If you use the script and find it helpful, just let me know somehow, would be amazing to know if someone found it useful.
Also, remember to add your OpenAI API key somewhere , most likely in an .env file (OPENAI_API_KEY).
A Python command-line tool that converts audio and video into text using OpenAI's transcription models, and optionally translates the result into your target language.
Works with both gpt-4o-transcribe and whisper-1, supports video input via
ffmpeg, handles large files through intelligent chunking, and can export .txt,
.srt, and .vtt subtitles with configurable timestamp modes.
- Accepts audio or video (
.mp3,.wav,.m4a,.mp4,.mov,.mkv, etc.) - Auto-extracts audio from video via
ffmpeg - Transcribes with gpt-4o-transcribe (preferred) or whisper-1
- Detects spoken language automatically or accepts language hints
- Translates transcripts via OpenAI's text models (chunked for long content)
- Saves transcript as
.txt, optional.srtand.vtt - Handles multiple input files in one go
- Size-aware preprocessing: Converts to 16 kHz mono Opus to stay under API limits
- Automatic chunking: Splits large files (>24 MB) into manageable segments
- Flexible timestamps: Three modes for adding time markers
proportional: Fast, works with gpt-4o-transcribewhisper: Exact timestamps using whisper-1's word-level timingoff: No timestamps
- Prompt optimization: Guide transcription with domain-specific context
- Batch processing: Process entire directory trees with resume capability
- Preserve structure: Maintains folder hierarchy in output
- Translation model selection: Choose between gpt-4o-mini (fast/cheap), gpt-4o (better quality), or gpt-5 (best quality)
-
Python ≥ 3.9
-
ffmpeg (must be on your PATH)
# macOS brew install ffmpeg # Ubuntu/Debian sudo apt install ffmpeg # Windows # Download from https://ffmpeg.org/download.html
pip install openai python-dotenv tqdmexport OPENAI_API_KEY="sk-..." # or put it in a .env fileBasic transcription:
python av2text.py interview.mp4 --model gpt-4o-transcribe --target-lang enWith timestamps every 60 seconds:
python av2text.py recording.wav \
--model gpt-4o-transcribe \
--timestamps proportional \
--timestamp-interval 60 \
--target-lang enWith exact whisper timestamps and GPT-5 translation:
python av2text.py meeting.mp4 \
--timestamps whisper \
--timestamp-interval 60 \
--source-lang ta \
--target-lang en \
--translate-model gpt-5Process entire directory trees:
python batch_av2text.py audio/ \
--model gpt-4o-transcribe \
--target-lang en \
--source-lang ta \
--output-dir transcripts/With resume capability and GPT-5 translation:
python batch_av2text.py audio/ \
--model gpt-4o-transcribe \
--target-lang en \
--translate-model gpt-5 \
--resume \
--skip-existing| Option | Default | Description |
|---|---|---|
--model |
gpt-4o-transcribe |
STT model (whisper-1 also works) |
--target-lang |
en |
Desired output language (ISO code) |
--source-lang |
— | Source language hint for whisper (e.g., ta, es) |
--force-translate |
— | Always translate, even if target matches source |
--skip-translate |
— | Write only .orig.txt (no translation) |
--timestamps |
proportional |
Timestamp mode: off, proportional, whisper |
--timestamp-interval |
60 |
Seconds between timestamp marks (0 to disable) |
--make-srt |
— | Create SRT subtitles |
--make-vtt |
— | Create VTT subtitles |
--segment-seconds |
600 |
Chunk length for large files (seconds) |
--max-single-mb |
24 |
Max file size before chunking (MB) |
--translate-chunk-chars |
7000 |
Max characters per translation chunk |
--asr-prompt |
— | Context prompt to improve transcription accuracy |
--asr-temperature |
0.0 |
Whisper decoding temperature (0.0-1.0) |
--translate-model |
gpt-4o-mini |
Model for translation: gpt-4o-mini, gpt-4o, gpt-5 |
| Option | Default | Description |
|---|---|---|
directory |
— | Root directory to search for media files |
--output-dir |
— | Copy all transcripts to this directory (maintains structure) |
--skip-existing |
— | Skip files that already have transcripts |
--resume |
— | Resume from previous log file |
--log |
logs/batch_log_TIMESTAMP.json |
Custom log file path (saved in logs/ folder) |
--translate-model |
gpt-4o-mini |
Model for translation: gpt-4o-mini, gpt-4o, gpt-5 |
| (all av2text.py options) | — | All single-file options are supported |
The --asr-prompt flag is critical for domain-specific accuracy. A
well-crafted prompt helps the model understand:
- Content context (interviews, conversations, technical content)
- Specialized vocabulary (medical terms, regional dialects, technical jargon)
- Expected audio quality and speaking style
For transcribing Tamil interviews with a Chennai fishermonger about life history and spirituality:
python av2text.py interview.wav \
--model gpt-4o-transcribe \
--source-lang ta \
--target-lang en \
--translate-model gpt-5 \
--asr-prompt "இது சென்னை மீனம்மாவின் நேர்காணல் மற்றும் மீன் சந்தை பதிவுகள். பேச்சுவழக்கு தமிழ். மீன் சந்தை சூழல்: ஏலம், விலை பேச்சுவார்த்தை, மீன் வகைகள், வாடிக்கையாளர் உரையாடல்கள். நேர்காணல் தலைப்புகள்: வாழ்க்கை வரலாறு, மீன் வியாபாரம், ஆன்மீகம், அன்றாட அனுபவங்கள். விளம்பரங்கள் இல்லை. உண்மையான உரையாடல்கள். மீன் பெயர்கள், சந்தை சொற்கள், சமயம் தொடர்பான வார்த்தைகள் சரியாக எழுத வேண்டும்."Translation: "These are interview and fish market recordings of Meenamma from Chennai. Colloquial Tamil. Fish market context: auctions, price negotiations, fish varieties, customer conversations. Interview topics: life history, fish trade, spirituality, daily experiences. No advertisements. Authentic conversations. Fish names, market terminology, religious terms must be transcribed accurately."
- Use the source language for the prompt when transcribing non-English content
- Be specific about context: What type of content? What's the setting?
- List specialized vocabulary domains: technical terms, regional dialects, proper nouns
- Mention speaking style: formal interview, casual conversation, lecture, etc.
- Keep it concise: 2-3 sentences covering context, content type, and key vocabulary
Medical interviews (Spanish):
--asr-prompt "Entrevista médica en español. Terminología clínica: diagnósticos, medicamentos, procedimientos. Conversación profesional entre médico y paciente."
Technical podcast (English):
--asr-prompt "Software engineering podcast discussing cloud architecture, microservices, Kubernetes, and DevOps practices. Technical terminology should be transcribed accurately."
Legal deposition (French):
--asr-prompt "Déposition juridique en français. Vocabulaire légal: articles de loi, procédures judiciaires, termes contractuels. Format formel avec questions et réponses."
The batch script (batch_av2text.py) is designed for processing large
collections of audio/video files with robustness and resumability.
- Recursive directory traversal: Finds all media files in nested folders
- Dual output: Transcripts stay with source files AND get copied to a central location
- Progress logging: JSON log tracks success/failure of each file (saved in
logs/folder) - Resume capability: Pick up where you left off after interruptions
- Skip existing: Avoid reprocessing files that already have transcripts
# Initial run with GPT-5 translation
python batch_av2text.py research_audio/ \
--model gpt-4o-transcribe \
--target-lang en \
--source-lang ta \
--translate-model gpt-5 \
--output-dir transcripts/ \
--asr-prompt "Your optimized prompt here"
# If interrupted, resume from log
python batch_av2text.py research_audio/ \
--resume \
--log logs/batch_log_20250118_143022.json
# Process only new files added since last run
python batch_av2text.py research_audio/ \
--skip-existing \
--output-dir transcripts/Before:
research_audio/
├── interviews/
│ ├── day1/
│ │ ├── morning.wav
│ │ └── afternoon.wav
│ └── day2/
│ └── evening.wav
└── market_recordings/
├── auction1.mp3
└── auction2.mp3
After (with --output-dir transcripts/):
research_audio/
├── interviews/
│ ├── day1/
│ │ ├── morning.wav
│ │ ├── morning.orig.txt # Original Tamil
│ │ ├── morning.en.txt # English translation
│ │ └── afternoon.wav
│ │ ├── afternoon.orig.txt
│ │ └── afternoon.en.txt
│ └── ...
transcripts/ # Centralized copy
├── interviews/
│ ├── day1/
│ │ ├── morning.orig.txt
│ │ ├── morning.en.txt
│ │ ├── afternoon.orig.txt
│ │ └── afternoon.en.txt
│ └── ...
logs/ # Processing logs
└── batch_log_20250118_143022.json
The batch processor creates a detailed JSON log in the logs/ folder:
{
"started": "2025-01-18T14:30:22",
"config": {
"model": "gpt-4o-transcribe",
"target_lang": "en",
"source_lang": "ta",
"translate_model": "gpt-5"
},
"results": [
{
"file": "/path/to/morning.wav",
"relative_path": "interviews/day1/morning.wav",
"success": true,
"message": "Success",
"timestamp": "2025-01-18T14:35:48"
},
{
"file": "/path/to/afternoon.wav",
"relative_path": "interviews/day1/afternoon.wav",
"success": false,
"message": "Timeout (>1 hour)",
"timestamp": "2025-01-18T15:40:12"
}
],
"completed": "2025-01-18T16:22:05"
}Transcribe Tamil interviews with optimal settings and GPT-5 translation:
python av2text.py interview.wav \
--model gpt-4o-transcribe \
--timestamps proportional \
--timestamp-interval 60 \
--source-lang ta \
--target-lang en \
--translate-model gpt-5 \
--asr-prompt "தமிழ் நேர்காணல். ஆராய்ச்சி சூழல். நேர்த்தியான பேச்சு."Process 100+ interviews overnight with GPT-5 for highest quality translation:
python batch_av2text.py fieldwork_2024/ \
--model gpt-4o-transcribe \
--target-lang en \
--source-lang ta \
--translate-model gpt-5 \
--output-dir transcripts_2024/ \
--timestamps proportional \
--asr-prompt "Your detailed prompt here"Generate both transcript and subtitles:
python av2text.py presentation.mp4 \
--target-lang en \
--make-srt --make-vtt \
--timestamps offTranscribe Spanish podcast and translate to English with GPT-4o:
python av2text.py podcast_ep1.mp3 \
--source-lang es \
--target-lang en \
--force-translate \
--translate-model gpt-4o \
--timestamps proportional-
Audio Extraction (for video files)
- ffmpeg extracts audio track
- Converts to 16 kHz mono Opus for efficient processing
- Keeps file size under API limits
-
Size Check & Segmentation
- Files under 24 MB: process as single file
- Larger files: automatically split into 10-minute chunks
- Each chunk processed separately, then reassembled
-
Transcription
- Calls OpenAI's Speech-to-Text API
- Uses
gpt-4o-transcribefor best accuracy (falls back towhisper-1) - Applies custom prompt if provided
- Cleans up artifacts and normalizes text
-
Timestamp Insertion (optional)
- Proportional mode: Estimates positions for minute markers
- Whisper mode: Uses exact word-level timestamps from whisper-1
- Inserts
[HH:MM:SS]markers at specified intervals
-
Translation (if needed)
- For English targets: can use direct speech→English translation
- For other languages: chunks text and translates via selected model (gpt-4o-mini, gpt-4o, or gpt-5)
- Preserves paragraph structure and timestamp markers
-
Output Generation
.orig.txt: Original language transcript with timestamps.{lang}.txt: Translated transcript.{lang}.srt/.{lang}.vtt: Subtitle files (if requested)
gpt-4o-transcribe (recommended for transcription):
- Higher accuracy, especially for accented or noisy audio
- Better handling of specialized vocabulary
- Faster processing
- Works well with proportional timestamps
whisper-1 (for transcription):
- Required for exact word-level timestamps
- Good multilingual support
- More established, widely tested
- Slightly slower but very reliable
Translation Models:
- gpt-4o-mini (default): Fast, cheap, good for straightforward translation
- gpt-4o: Better quality, handles nuance and context better
- gpt-5: Highest quality, best for complex/technical content, cultural nuance
Local Whisper (not currently supported, but possible):
- This script uses OpenAI's API, but you could adapt it to use local Whisper models
- Run models on your own hardware (no API costs, full privacy)
- Requires significant GPU resources for reasonable speed
- WARNING: Local inference is MUCH slower (10-100x depending on hardware)
- For local Whisper, check out faster-whisper or whisper.cpp
- Best for: privacy-sensitive projects, offline work, or cost optimization with powerful local GPUs
gpt-4o-transcribetypically provides 15-20% better accuracy thanwhisper-1for challenging audio- For batch processing, expect roughly 1 minute of processing per 10 minutes of audio
- Large files are automatically chunked, but manual pre-segmentation can sometimes improve quality at natural break points
- Always provide
--source-langhint for non-English audio - Craft specific
--asr-promptfor domain terminology - Use
--asr-temperature 0.0for consistent, deterministic transcriptions - Consider
--timestamps whisperfor precise timing if needed for analysis - Use
--translate-model gpt-5for research-quality translations
- The built-in SRT/VTT generation uses uniform chunking (not synchronized to speech)
- For production-quality subtitles, use word-level timestamps from
whisper-1or consider WhisperX - Current implementation: ~8 seconds per subtitle block, ~900 characters max
- Transcription:
- gpt-4o-transcribe: ~$0.10 per minute of audio
- whisper-1: ~$0.006 per minute of audio
- Translation:
- gpt-4o-mini: negligible cost (default) - ~$0.15 per 1M input tokens
- gpt-4o: ~$2.50 per 1M input tokens, ~$10 per 1M output tokens
- gpt-5: ~$5.00 per 1M input tokens, ~$20 per 1M output tokens (highest quality)
- Batch processing examples:
- 100 hours with gpt-4o-transcribe + gpt-4o-mini: ~$600
- 100 hours with whisper-1 + gpt-4o-mini: ~$36
- 100 hours with gpt-4o-transcribe + gpt-5: ~$600 + translation costs (varies by length, expect ~$50-200 extra)
- Original transcripts always save alongside source files
- Use
--output-dirin batch mode for centralized backup - Log files automatically saved in
logs/folder to keep project root clean
"ffmpeg not found"
- Install ffmpeg and ensure it's in your PATH
- Test with:
ffmpeg -version
"OPENAI_API_KEY not set"
- Create
.envfile withOPENAI_API_KEY=sk-... - Or export as environment variable
Translation fails with gpt-5
- The script may need updating to support GPT-5 via the correct API endpoint
- Try
gpt-4oas alternative for high-quality translation - Check OpenAI API documentation for current model availability
Transcription fails with timeout
- Very long files (>2 hours) may hit API timeouts
- Solution: Pre-segment file or reduce
--segment-seconds
Poor transcription quality
- Add
--source-langhint - Craft domain-specific
--asr-prompt - Try gpt-4o-transcribe instead of whisper-1
- Check audio quality (low noise, clear speech)
Batch processing stops mid-run
- Use
--resumeto continue from log file inlogs/folder - Check log for specific file errors
- Consider
--skip-existingto avoid reprocessing
Files show "Success" but no transcripts created
- Check the actual audio directory for .orig.txt and .en.txt files
- Look at the log file in
logs/folder for detailed error messages - Try running a single file manually to see actual errors
- Verify your OpenAI API key has sufficient credits
av2text/
├── av2text.py # Core transcription script
├── batch_av2text.py # Batch processing wrapper
├── logs/ # Processing logs (auto-created)
│ └── batch_log_*.json
├── README.md # This file
└── .env.example # Template for API key
MIT License — use it for research, production, or whatever you need. Just don't blame the bot if ffmpeg eats your file or OpenAI's API decides to take a nap.
Built with:
- OpenAI API for transcription and translation
- FFmpeg for audio/video processing
- Python's amazing ecosystem
Happy transcribing! 🎉
For questions, issues, or improvements, feel free to open an issue or submit a PR.