Video Caption
Extract video audio, request timestamped subtitles, and embed captions with MoviePyVideoTools.
"""
Video Caption
=============================
Please install dependencies using:.
"""
from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.tools.moviepy_video import MoviePyVideoTools
from agno.tools.openai import OpenAITools
video_tools = MoviePyVideoTools(
enable_process_video=True, enable_generate_captions=True, enable_embed_captions=True
)
openai_tools = OpenAITools()
# ---------------------------------------------------------------------------
# Create Agent
# ---------------------------------------------------------------------------
video_caption_agent = Agent(
name="Video Caption Generator Agent",
model=OpenAIResponses(
id="gpt-5.6-luna",
),
tools=[video_tools, openai_tools],
description="You are an AI agent that can generate and embed captions for videos.",
instructions=[
"When a user provides a video, process it to generate captions.",
"Use the video processing tools in this sequence:",
"1. Extract audio from the video using extract_audio",
"2. Transcribe the audio using transcribe_audio",
"3. Generate SRT captions using create_srt",
"4. Embed captions into the video using embed_captions",
],
markdown=True,
)
# ---------------------------------------------------------------------------
# Run Agent
# ---------------------------------------------------------------------------
if __name__ == "__main__":
video_caption_agent.print_response(
"Generate captions for {video with location} and embed them in the video"
)Request timestamped subtitles
OpenAITools.transcribe_audio in the archived program requests plain text, while create_srt only writes the supplied text and embed_captions expects timed SRT blocks. Use this replacement program as caption_video.py to request provider timestamps and check them before embedding. It calls the toolkit directly so an intermediate model cannot invent or rewrite the timing.
import argparse
import math
from pathlib import Path
from tempfile import TemporaryDirectory
from agno.tools.moviepy_video import MoviePyVideoTools
from moviepy import VideoFileClip
from openai import OpenAI
def caption_video(video_path: Path, output_path: Path) -> None:
if not video_path.is_file():
raise FileNotFoundError(video_path)
tools = MoviePyVideoTools(enable_embed_captions=True)
output_path.parent.mkdir(parents=True, exist_ok=True)
with TemporaryDirectory() as directory:
audio_path = Path(directory) / "audio.mp3"
with VideoFileClip(str(video_path)) as video:
if video.audio is None:
raise ValueError("Video has no audio track")
video.audio.write_audiofile(str(audio_path))
with OpenAI() as client, audio_path.open("rb") as audio_file:
subtitles = client.audio.transcriptions.create(
model="whisper-1",
file=audio_file,
response_format="srt",
)
if not isinstance(subtitles, str):
raise RuntimeError("Transcription did not return SRT text")
words = tools.parse_srt(subtitles)
if not words or any(
not math.isfinite(word["start"])
or not math.isfinite(word["end"])
or word["start"] < 0
or word["end"] <= word["start"]
for word in words
):
raise ValueError("Transcription has no usable subtitle timing")
srt_path = Path(directory) / "captions.srt"
srt_path.write_text(subtitles, encoding="utf-8")
result = tools.embed_captions(
video_path=str(video_path),
srt_path=str(srt_path),
output_path=str(output_path),
)
if result != str(output_path) or not output_path.is_file():
raise RuntimeError(f"Caption export failed: {result}")
print(f"Saved {output_path}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("video", type=Path)
parser.add_argument("output", type=Path)
args = parser.parse_args()
caption_video(args.video, args.output)Whisper supplies segment timings. MoviePyVideoTools distributes words evenly within each segment for highlighting; those word times are approximate. Check the transcription against the recording before sharing it. MoviePy also requires a working FFmpeg installation and a font usable by its caption renderer. The toolkit's default caption font is Arial.
The OpenAI transcription API supports SRT for whisper-1. Its announced shutdown is February 26, 2027; verify timestamp-format support when migrating models.
Run the Example
Set up your virtual environment
uv venv --python 3.12
source .venv/bin/activateInstall dependencies
uv pip install -U agno moviepy openaiExport your OpenAI API key
export OPENAI_API_KEY="your_openai_api_key_here"Set the video path
Choose a local video with an audio track. The command below uses input.mp4 and writes a separate output-captioned.mp4; replace both paths as needed.
Run the example
Save the replacement program above as caption_video.py, then run:
python caption_video.py input.mp4 output-captioned.mp4Full source: cookbook/02_agents/12_multimodal/video_caption.py