Skip to content

Instantly share code, notes, and snippets.

@ZanSara
Created May 20, 2025 22:52
Show Gist options
  • Select an option

  • Save ZanSara/4bab5db89376d595128e0688804d694c to your computer and use it in GitHub Desktop.

Select an option

Save ZanSara/4bab5db89376d595128e0688804d694c to your computer and use it in GitHub Desktop.
Video to SRT with Deepgram
#!/usr/bin/env python3
"""
Video to SRT Converter using Deepgram API
This script extracts audio from a video file and uses Deepgram's API to generate
subtitles in SRT format.
Requirements:
deepgram-sdk>=3.11.0
ffmpeg-python>=0.2.0
httpx>=0.24.0
# Video to SRT Converter
A Python script that extracts audio from video files and uses Deepgram's speech recognition API to generate accurate subtitles in SRT format.
## Features
- Extracts audio from video files using FFmpeg
- Transcribes audio using Deepgram's API
- Generates properly formatted SRT subtitle files
- Supports timestamp formatting for dialogue
- Command-line interface for easy usage
## Requirements
- Python 3.7 or higher
- FFmpeg installed on your system
- Deepgram API key
## Installation
1. Clone or download this repository
2. Install the required Python packages:
```bash
pip install -r requirements.txt
```
3. Make sure FFmpeg is installed on your system:
- On Ubuntu/Debian: `sudo apt install ffmpeg`
- On macOS (with Homebrew): `brew install ffmpeg`
- On Windows: Download from [FFmpeg's official website](https://ffmpeg.org/download.html)
4. Get a Deepgram API key:
- Sign up at [Deepgram](https://console.deepgram.com/signup)
- Create a new API key in your dashboard
## Usage
You can use the script from the command line:
```bash
python video_to_srt.py your_video.mp4 --api-key YOUR_DEEPGRAM_API_KEY
```
Or set the API key as an environment variable:
```bash
# Set the API key as an environment variable
export DEEPGRAM_API_KEY=your_deepgram_api_key
# Run the script
python video_to_srt.py your_video.mp4
```
### Command-line options
```
usage: video_to_srt.py [-h] [-o OUTPUT] [-k API_KEY] [--keep-audio] video_path
Convert video to SRT subtitles using Deepgram API
positional arguments:
video_path Path to the video file
optional arguments:
-h, --help show this help message and exit
-o OUTPUT, --output OUTPUT
Path to save the SRT file (default: same as video with .srt extension)
-k API_KEY, --api-key API_KEY
Deepgram API key (can also be set with DEEPGRAM_API_KEY environment variable)
--keep-audio Keep the extracted audio file (default: False)
```
## Example
```bash
python video_to_srt.py interview.mp4 -o interview_subtitles.srt
```
This will:
1. Extract audio from `interview.mp4`
2. Transcribe the audio using Deepgram
3. Create `interview_subtitles.srt` with properly formatted subtitles
## Notes
- The script uses Deepgram's Nova-2 model by default, which provides accurate transcription for English.
- For non-English videos, you can modify the language parameter in the `transcribe_audio` function.
- The audio extraction creates a temporary file that is deleted after processing unless you use the `--keep-audio` flag.
## License
This project is licensed under the MIT License - see the LICENSE file for details.
## Acknowledgments
- [Deepgram](https://deepgram.com/) for their speech recognition API
- [FFmpeg](https://ffmpeg.org/) for audio/video processing capabilities
"""
import os
import sys
import argparse
import datetime
import tempfile
from pathlib import Path
from typing import Dict, List, Optional, Any
import ffmpeg
import httpx
from deepgram import DeepgramClient, PrerecordedOptions, FileSource, DeepgramClientOptions
def extract_audio(video_path: str, output_path: Optional[str] = None) -> str:
"""
Extract audio from a video file using ffmpeg.
Args:
video_path: Path to the video file
output_path: Optional path for the output audio file
Returns:
Path to the extracted audio file
"""
output_path = (output_path or "audio") + ".wav"
try:
# Use ffmpeg to extract audio
(
ffmpeg
.input(video_path)
.output(output_path, acodec='pcm_s16le', ar='16000', ac=1)
.global_args('-y') # Overwrite output file if it exists
.run(quiet=True, capture_stdout=True, capture_stderr=True)
)
return output_path
except ffmpeg.Error as e:
print(f"Error extracting audio: {e.stderr.decode()}")
if os.path.exists(output_path):
os.remove(output_path)
sys.exit(1)
def transcribe_audio(audio_path: str, api_key: str) -> Any:
"""
Transcribe audio using Deepgram API.
Args:
audio_path: Path to the audio file
api_key: Deepgram API key
Returns:
Deepgram response object
"""
try:
# Initialize the Deepgram client
deepgram = DeepgramClient(api_key)
# Set up options for the transcription
options = PrerecordedOptions(
model="nova-3",
smart_format=True,
utterances=True,
punctuate=True,
diarize=True,
language="multi",
filler_words=True
)
# Read the audio file
with open(audio_path, "rb") as audio:
buffer_data = audio.read()
# Create the file source payload
payload = {
"buffer": buffer_data
}
# Send the audio to Deepgram for transcription
response = deepgram.listen.rest.v("1").transcribe_file(
payload, options, timeout=httpx.Timeout(300.0, connect=10.0)
)
print(response)
return response
except Exception as e:
print(f"Error during transcription: {str(e)}")
sys.exit(1)
def format_time(seconds: float) -> str:
"""
Format time in SRT format (HH:MM:SS,mmm).
Args:
seconds: Time in seconds
Returns:
Formatted time string
"""
# Convert seconds to a timedelta
time_obj = datetime.timedelta(seconds=seconds)
# Extract hours, minutes, seconds, and milliseconds
hours = int(time_obj.total_seconds() // 3600)
minutes = int((time_obj.total_seconds() % 3600) // 60)
seconds = int(time_obj.total_seconds() % 60)
milliseconds = int((time_obj.total_seconds() % 1) * 1000)
# Format the time in SRT format
return f"{hours:02d}:{minutes:02d}:{seconds:02d},{milliseconds:03d}"
def create_srt(response: Any, output_path: str) -> None:
"""
Create an SRT file from a Deepgram response.
Args:
response: Deepgram transcription response
output_path: Path to save the SRT file
"""
try:
if hasattr(response, 'to_dict'):
response_dict = response.to_dict()
else:
response_dict = response
# Check for utterances in the response
if 'results' in response_dict and 'utterances' in response_dict['results']:
utterances = response_dict['results']['utterances']
with open(output_path, 'w', encoding='utf-8') as srt_file:
for i, utterance in enumerate(utterances):
start_time = utterance['start']
end_time = utterance['end']
text = utterance['transcript']
# Write the subtitle entry to the SRT file
srt_file.write(f"{i+1}\n")
srt_file.write(f"{format_time(start_time)} --> {format_time(end_time)}\n")
srt_file.write(f"{text}\n\n")
print(f"SRT file saved to {output_path}")
# Handle the alternative response structure
elif 'results' in response_dict and 'channels' in response_dict['results'] and response_dict['results']['channels']:
channel = response_dict['results']['channels'][0]
if 'alternatives' in channel and channel['alternatives']:
alternative = channel['alternatives'][0]
# Check if words are available
if 'words' in alternative and alternative['words']:
words = alternative['words']
with open(output_path, 'w', encoding='utf-8') as srt_file:
# Group words into sentences or chunks of reasonable length
chunks = []
current_chunk = []
for word in words:
current_chunk.append(word)
# Start a new chunk after punctuation or when chunk gets too long
if word['word'][-1] in '.!?' or len(current_chunk) >= 10:
chunks.append(current_chunk)
current_chunk = []
# Add any remaining words as a chunk
if current_chunk:
chunks.append(current_chunk)
# Write each chunk as a subtitle entry
for i, chunk in enumerate(chunks):
if chunk:
start_time = chunk[0]['start']
end_time = chunk[-1]['end']
text = ' '.join(word['word'] for word in chunk)
# Write the subtitle entry to the SRT file
srt_file.write(f"{i+1}\n")
srt_file.write(f"{format_time(start_time)} --> {format_time(end_time)}\n")
srt_file.write(f"{text}\n\n")
print(f"SRT file saved to {output_path}")
# Handle case where transcript is available but not word-level timestamps
elif 'transcript' in alternative:
transcript = alternative['transcript']
with open(output_path, 'w', encoding='utf-8') as srt_file:
# Add entire transcript as a single subtitle
srt_file.write("1\n")
srt_file.write("00:00:00,000 --> 99:59:59,999\n") # Full duration
srt_file.write(f"{transcript}\n\n")
print(f"SRT file saved to {output_path} (full transcript only, no timestamps)")
else:
print("Error: No transcript or words found in the response")
sys.exit(1)
else:
print("Error: No alternatives found in the response")
sys.exit(1)
else:
print("Error: Unexpected response format from Deepgram API")
sys.exit(1)
except Exception as e:
print(f"Error creating SRT file: {str(e)}")
sys.exit(1)
def main():
# Set up command line argument parsing
parser = argparse.ArgumentParser(description="Convert video to SRT subtitles using Deepgram API")
parser.add_argument("video_path", help="Path to the video file")
parser.add_argument(
"-o", "--output",
help="Path to save the SRT file (default: same as video with .srt extension)"
)
parser.add_argument(
"-k", "--api-key",
help="Deepgram API key (can also be set with DEEPGRAM_API_KEY environment variable)"
)
parser.add_argument(
"-l", "--language", default="pt",
help="Language code for transcription (default: pt for Portuguese)"
)
parser.add_argument(
"--keep-audio", action="store_true",
help="Keep the extracted audio file (default: False)"
)
parser.add_argument(
"--verbose", action="store_true",
help="Enable verbose logging (default: False)"
)
args = parser.parse_args()
# Check if the video file exists
if not os.path.isfile(args.video_path):
print(f"Error: Video file '{args.video_path}' not found")
sys.exit(1)
# Get the API key
api_key = args.api_key or os.environ.get("DEEPGRAM_API_KEY")
if not api_key:
print("Error: Deepgram API key not provided")
print("Please provide the API key using the -k/--api-key option or set the DEEPGRAM_API_KEY environment variable")
sys.exit(1)
# Set the output path for the SRT file
video_path = Path(args.video_path)
if args.output:
srt_path = args.output
else:
srt_path = str(video_path.with_suffix('.srt'))
# Extract audio from the video
print(f"Extracting audio from {args.video_path}...")
audio_path = extract_audio(args.video_path, args.video_path)
try:
# Transcribe the audio
print("Transcribing audio using Deepgram API...")
response = transcribe_audio(audio_path, api_key)
# Create the SRT file
print("Creating SRT file...")
create_srt(response, srt_path)
finally:
# Clean up the temporary audio file if not keeping it
if not args.keep_audio and audio_path:
os.remove(audio_path)
print(f"Temporary audio file removed")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment