Video Highlights Reel Planner
Plan video highlight clips from transcripts without heavy video editing
Video Highlights Reel Planner
Plan video highlight clips from transcripts—identify the best moments without heavy video editing.
Problem Statement
Who: Video editors, content creators, social media managers
Why: Finding highlight-worthy moments in long videos is time-consuming. AI can identify key moments from transcripts.
What You’ll Build
A recipe that analyzes transcripts and outputs a structured clip plan with timestamps and titles.
Input/Output Contract
| Input | Type | Required | Description |
|---|---|---|---|
transcript_text | string | Yes* | Transcript with timestamps |
video_path | string | Yes* | Path to video (alternative) |
highlight_goal | string | No | What to highlight (default: engaging) |
max_clips | integer | No | Maximum clips to identify (default: 10) |
*One of transcript_text or video_path is required.
| Output | Type | Description |
|---|---|---|
clip_plan_json | array | Planned clips with timestamps |
title_suggestions | array | Suggested titles for each clip |
ok | boolean | Success indicator |
Prerequisites
export OPENAI_API_KEY=your_key_here
pip install praisonaiagentsStep-by-Step Build
- Create Recipe Directory
bash mkdir -p ~/.praisonai/templates/simple-video-highlights-reel-planner cd ~/.praisonai/templates/simple-video-highlights-reel-planner - Create TEMPLATE.yaml
yaml name: simple-video-highlights-reel-planner version: "1.0.0" description: "Plan video highlight clips from transcripts" author: "PraisonAI" license: "MIT" tags: - video - highlights - planning - content requires: env: - OPENAI_API_KEY packages: - praisonaiagents inputs: transcript_text: type: string description: "Transcript text with timestamps" required: false video_path: type: string description: "Path to video file (alternative)" required: false highlight_goal: type: string description: "What type of highlights to find" required: false default: "engaging" enum: - engaging - educational - funny - emotional - actionable max_clips: type: integer description: "Maximum number of clips to identify" required: false default: 10 minimum: 1 maximum: 50 outputs: clip_plan_json: type: array description: "Planned clips with timestamps and descriptions" title_suggestions: type: array description: "Suggested titles for clips" ok: type: boolean description: "Success indicator" cli: command: "praison recipes run simple-video-highlights-reel-planner" examples: - 'praison recipes run simple-video-highlights-reel-planner --input ''{"transcript_text": "00:00 Welcome..."}''' safety: dry_run_default: false requires_consent: false overwrites_files: false network_access: true pii_handling: false - Create recipe.py
python # recipe.py import os import json import re from praisonaiagents import Agent, Task, AgentTeam def run(input_data: dict, config: dict = None) -> dict: """Plan video highlight clips from transcript.""" transcript_text = input_data.get("transcript_text") video_path = input_data.get("video_path") highlight_goal = input_data.get("highlight_goal", "engaging") max_clips = input_data.get("max_clips", 10) if not transcript_text and not video_path: return {"ok": False, "error": {"code": "MISSING_INPUT", "message": "Either transcript_text or video_path is required"}} if video_path and not transcript_text: if not os.path.exists(video_path): return {"ok": False, "error": {"code": "FILE_NOT_FOUND", "message": f"Video not found: {video_path}"}} return {"ok": False, "error": {"code": "NOT_IMPLEMENTED", "message": "Video transcription not implemented. Provide transcript_text."}} try: goal_guidelines = { "engaging": "Find moments that grab attention, surprising reveals, or compelling stories", "educational": "Find clear explanations, key insights, and teachable moments", "funny": "Find humorous moments, jokes, and entertaining segments", "emotional": "Find touching moments, inspiring stories, and emotional peaks", "actionable": "Find practical tips, how-to segments, and advice" } # Create highlight finder agent finder = Agent( name="Highlight Finder", role="Video Content Analyst", goal=f"Find the most {highlight_goal} moments", instructions=f""" You are a video content analyst specializing in finding highlights. Goal: {highlight_goal} - {goal_guidelines[highlight_goal]} For each highlight: - Identify start and end timestamps - Explain why it's highlight-worthy - Suggest a clip duration (15-60 seconds ideal) - Rate engagement potential (1-10) Find up to {max_clips} highlights. """, ) # Create title generator titler = Agent( name="Title Generator", role="Social Media Specialist", goal="Create compelling clip titles", instructions=""" You are a social media specialist. - Create catchy, clickable titles - Keep titles under 60 characters - Use power words and hooks - Match the content tone """, ) # Define tasks find_task = Task( name="find_highlights", description=f""" Analyze this transcript and find up to {max_clips} {highlight_goal} highlights: {transcript_text[:10000]} Output as JSON array: [{{ "start_time": "MM:SS", "end_time": "MM:SS", "description": "What happens", "why_highlight": "Why it's engaging", "engagement_score": 8 }}] """, expected_output="JSON array of highlight clips", agent=finder, ) title_task = Task( name="generate_titles", description="Generate compelling titles for each highlight clip", expected_output="List of titles matching each clip", agent=titler, context=[find_task], ) # Execute agents = AgentTeam( agents=[finder, titler], tasks=[find_task, title_task], ) result = agents.start() # Parse clips clips_text = result.get("find_highlights", "[]") clips = parse_clips(clips_text) # Parse titles titles_text = result.get("generate_titles", "") titles = [t.strip() for t in titles_text.split("\n") if t.strip() and len(t.strip()) > 5] return { "ok": True, "clip_plan_json": clips[:max_clips], "title_suggestions": titles[:max_clips], "artifacts": [], "warnings": [], } except Exception as e: return {"ok": False, "error": {"code": "PROCESSING_ERROR", "message": str(e)}} def parse_clips(text: str) -> list: """Parse clip plan from agent output.""" try: match = re.search(r'\[.*\]', text, re.DOTALL) if match: return json.loads(match.group()) except json.JSONDecodeError: pass # Fallback parsing clips = [] current_clip = {} for line in text.split('\n'): if 'start' in line.lower() and ':' in line: time_match = re.search(r'(\d{1,2}:\d{2}(?::\d{2})?)', line) if time_match: current_clip['start_time'] = time_match.group(1) elif 'end' in line.lower() and ':' in line: time_match = re.search(r'(\d{1,2}:\d{2}(?::\d{2})?)', line) if time_match: current_clip['end_time'] = time_match.group(1) elif 'description' in line.lower(): current_clip['description'] = line.split(':', 1)[-1].strip() if current_clip.get('start_time') and current_clip.get('end_time'): clips.append(current_clip) current_clip = {} return clips - Create test_recipe.py
python # test_recipe.py import pytest from recipe import run, parse_clips def test_missing_input(): result = run({}) assert result["ok"] is False assert result["error"]["code"] == "MISSING_INPUT" def test_parse_clips_json(): text = '[{"start_time": "00:30", "end_time": "01:00", "description": "Key moment"}]' clips = parse_clips(text) assert len(clips) == 1 assert clips[0]["start_time"] == "00:30" def test_highlight_goals(): valid_goals = ["engaging", "educational", "funny", "emotional", "actionable"] for goal in valid_goals: assert goal in valid_goals @pytest.mark.integration def test_end_to_end(): transcript = """ 00:00 Welcome to today's video about productivity tips. 02:30 Here's the number one tip that changed my life. 05:00 Let me show you exactly how to implement this. 10:00 The results were incredible - I saved 10 hours per week. 15:00 Thanks for watching, don't forget to subscribe! """ result = run({ "transcript_text": transcript, "highlight_goal": "actionable", "max_clips": 5 }) assert result["ok"] is True assert len(result["clip_plan_json"]) > 0
Run Locally
# Basic usage
praison recipes run simple-video-highlights-reel-planner \
--input '{"transcript_text": "00:00 Welcome..."}'
# Find funny moments
praison recipes run simple-video-highlights-reel-planner \
--input '{"transcript_text": "...", "highlight_goal": "funny", "max_clips": 5}'Deploy & Integrate: 6 Integration Models
Model 1: Embedded SDK
from praisonai import recipe
# Load or define transcript
transcript = "00:00 Introduction to the topic..."
result = recipe.run(
"simple-video-highlights-reel-planner",
input={
"transcript_text": transcript,
"highlight_goal": "engaging",
"max_clips": 10
}
)
if result.ok:
for i, clip in enumerate(result.output["clip_plan_json"]):
title = result.output["title_suggestions"][i] if i < len(result.output["title_suggestions"]) else "Untitled"
print(f"{clip['start_time']} - {clip['end_time']}: {title}")Model 2: CLI Invocation
praison recipes run simple-video-highlights-reel-planner \
--input '{"transcript_text": "..."}' \
--json | jq '.clip_plan_json'Model 3: Plugin Mode
class HighlightsPlugin:
def find_highlights(self, transcript, goal="engaging"):
from praisonai import recipe
return recipe.run(
"simple-video-highlights-reel-planner",
input={"transcript_text": transcript, "highlight_goal": goal}
)Model 4: Local HTTP Sidecar
const response = await fetch('http://localhost:8765/recipes/simple-video-highlights-reel-planner/run', {
method: 'POST',
body: JSON.stringify({
transcript_text: transcript,
highlight_goal: 'funny',
max_clips: 5
})
});Model 5: Remote Managed Runner
response = requests.post(
"https://api.video-tools.com/highlights",
headers={"Authorization": f"Bearer {api_key}"},
json={"transcript_text": transcript, "max_clips": 10}
)Model 6: Event-Driven
def on_video_transcribed(event):
import queue as q
job_queue = q.Queue() # Replace with SQS/RabbitMQ in production
job_queue.put({
"recipe": "simple-video-highlights-reel-planner",
"input": {
"transcript_text": event['transcript'],
"highlight_goal": "engaging"
},
"callback_url": f"https://api.example.com/videos/{event['video_id']}/highlights"
})Troubleshooting
No highlights found
Ensure your transcript includes timestamps. The recipe needs timing information to plan clips.
Clips too long or short
The recipe targets 15-60 second clips. For different durations, adjust the instructions in a custom fork.
Next Steps
- YouTube Chapter Generator – Generate chapters for full videos
- Video Caption Generator – Generate transcripts first