Audio & Video

Generating Video Summaries From Transcripts

⏱ 15 min

Back to confirmed, solid ground after the previous lesson’s honest workaround. There is no dedicated “watch this video and summarize it” method in the WordPress AI Client SDK, and this lesson doesn’t need one: a video’s transcript, whether it came from the previous lesson’s direct provider call or from a caption file that already exists (a .vtt or .srt file uploaded alongside the video, which many editors already have from their video hosting workflow), is just text. Summarizing text is exactly what generate_text() does, and it’s been confirmed and covered in depth since Course 5. This lesson applies it specifically to transcripts and caption files, and produces a summary worth actually storing and searching against.

What you'll learn in this lesson
Reading a caption file as plain text
Stripping timestamps and cue numbers out of a .vtt or .srt file before summarizing it.
Summarizing a transcript with generate_text()
A prompt shaped for a summary, not a rewrite.
Storing the summary as searchable content
Post meta versus post content, and why meta usually wins here.
A pointer to Course 10 for embeddings
Making a stored summary genuinely searchable by meaning, not just by keyword.
Prerequisites

Course 5’s text generation lessons, in particular the generate_text() builder chain and how to pass a longer block of text as the prompt input. The previous lesson in this course if you’re working from a freshly transcribed audio track rather than an existing caption file.

Step 1: Getting plain text out of a caption file

Caption files carry more than just words, cue numbers, timestamps, and formatting markup that would confuse a summarization prompt if passed through unmodified. A simple strip works for both common formats:

// File: my-plugin/class-video-summary.php
function my_plugin_extract_caption_text( string $file_path ): string {
	$contents = file_get_contents( $file_path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents

	if ( false === $contents ) {
		return '';
	}

	$lines = explode( "\n", $contents );
	$text_lines = array();

	foreach ( $lines as $line ) {
		$line = trim( $line );

		// Skip blank lines, WEBVTT headers, cue numbers, and timestamp lines.
		if (
			'' === $line
			|| 'WEBVTT' === $line
			|| preg_match( '/^\d+$/', $line )
			|| preg_match( '/-->/', $line )
		) {
			continue;
		}

		$text_lines[] = $line;
	}

	return implode( ' ', $text_lines );
}

This handles the common structure of both .vtt and .srt files well enough for summarization purposes, it doesn’t need to be a fully correct parser of either format, just needs to strip out the parts that aren’t spoken words.

Step 2: Summarizing with generate_text()

With plain text in hand, summarizing it is the same generate_text() call covered in Course 5, shaped with a prompt specific to the job:

// File: my-plugin/class-video-summary.php
function my_plugin_summarize_transcript( string $transcript ): string {
	return wp_ai_client_prompt(
		"Summarize the following video transcript in 3 to 5 sentences, written for " .
		"someone deciding whether to watch the full video. Focus on what the video " .
		"covers, not how it's structured. Transcript follows:\n\n" . $transcript
	)->generate_text();
}

Being specific about the summary’s purpose, “deciding whether to watch,” steers the model away from a generic play-by-play recap and toward something actually useful as a substitute preview. Adjust the instruction for your own use case: a summary meant for an internal training-video index reads differently than one meant as public-facing marketing copy.

Long transcripts may need chunking

A short video’s transcript fits comfortably within a single prompt. A multi-hour recording’s transcript might not, depending on the model’s context window. If you’re regularly summarizing long-form content, split the transcript into chunks, summarize each chunk, then summarize the summaries, the same divide-and-conquer approach used for any long-document summarization task, not something specific to video.

Step 3: Storing the summary

A generated summary is metadata about the video, not the video’s own content, post meta on the attachment (or on a post that embeds the video) is the natural place for it:

// File: my-plugin/class-video-summary.php
function my_plugin_save_video_summary( int $attachment_id, string $summary ): void {
	update_post_meta( $attachment_id, '_my_plugin_video_summary', wp_kses_post( $summary ) );
}

Storing it as meta rather than appending it into post_content keeps it out of the way of the actual post editing experience, while still making it available anywhere you query the attachment, in an admin list table column, a REST API response, or a front-end video player’s description area.

Step 4: Making the summary genuinely searchable

A summary sitting in post meta is already searchable by keyword through a meta_query. For search that understands meaning rather than exact words, “find videos about budgeting” matching a summary that never uses the word “budgeting,” embed the summary the same way Course 10 does for full posts:

// File: my-plugin/class-video-summary.php
use WordPress\AiClient\AiClient;

$values = AiClient::input( $summary )->generateEmbedding()->getValues();
update_post_meta( $attachment_id, '_my_plugin_video_summary_embedding', wp_json_encode( $values ) );

This is the same AiClient::input()->generateEmbedding() method covered in Course 5’s embeddings lesson, a separate class from the wp_ai_client_prompt() used for the summary text itself, applied here to a video summary instead of a post body. If building real semantic search on top of stored embeddings like this is new territory, Course 10: RAG & Knowledge Bases in WordPress covers embeddings and retrieval in full depth, this lesson only needs the single call above to make a video summary a candidate for that kind of search.

Test it: summarize a real caption file

wp-env run cli wp eval '
$text = my_plugin_extract_caption_text( "/path/to/a/real-captions.vtt" );
$summary = my_plugin_summarize_transcript( $text );
echo $summary . "\n";
'

You should see a short, coherent summary that reflects the actual content of that specific caption file, not a generic placeholder paragraph.

A caption file with no real speech produces a weak summary

Auto-generated captions on some hosting platforms are wrong often enough to matter, mangled names, dropped words, or entire sections of silence rendered as garbled text. A summary built on a bad transcript will be confidently wrong in the same places the transcript was, worth a quick human skim of the summary before publishing it anywhere a reader would trust it as accurate.

Recap

A video transcript, however you got it, from a direct provider call in the previous lesson or from an existing caption file, is just text once you’ve stripped out timestamps and cue markup. Summarizing it is an ordinary generate_text() call with a prompt aimed at “should I watch this,” and storing the result as post meta keeps it available for display and, with one more AiClient::input()->generateEmbedding() call, for real semantic search covered in full in Course 10.

Resources & further reading

← Audio Transcription Auto-Tagging and Organizing the Media Library With AI →