> ## Documentation Index
> Fetch the complete documentation index at: https://docs.praison.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 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.

<Tip>
  **Planning Only:** This recipe focuses on identifying and planning clips, not actual video editing. Keep dependencies minimal for maximum portability.
</Tip>

## What You'll Build

A recipe that analyzes transcripts and outputs a structured clip plan with timestamps and titles.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    Input[📝 Transcript] --> Analyze[Analyze Content]
    Analyze --> Identify[Find Highlights]
    Identify --> Plan[Create Clip Plan]
    Plan --> Output[📋 Clip Plan JSON]

    classDef input fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef process fill:#189AB4,stroke:#7C90A0,color:#fff

    class Input,Output input
    class Analyze,Identify,Plan process
```

### 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

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
export OPENAI_API_KEY=your_key_here
pip install praisonaiagents
```

## Step-by-Step Build

<Steps>
  <Step title="Create Recipe Directory">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    mkdir -p ~/.praisonai/templates/simple-video-highlights-reel-planner
    cd ~/.praisonai/templates/simple-video-highlights-reel-planner
    ```
  </Step>

  <Step title="Create TEMPLATE.yaml">
    ```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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
    ```
  </Step>

  <Step title="Create recipe.py">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # 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
    ```
  </Step>

  <Step title="Create test_recipe.py">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # 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
    ```
  </Step>
</Steps>

## Run Locally

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# 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

<Tabs>
  <Tab title="Model 1: Embedded SDK">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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}")
    ```
  </Tab>

  <Tab title="Model 2: CLI Invocation">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praison recipes run simple-video-highlights-reel-planner \
      --input '{"transcript_text": "..."}' \
      --json | jq '.clip_plan_json'
    ```
  </Tab>

  <Tab title="Model 3: Plugin Mode">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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}
            )
    ```
  </Tab>

  <Tab title="Model 4: Local HTTP Sidecar">
    ```javascript theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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
      })
    });
    ```
  </Tab>

  <Tab title="Model 5: Remote Managed Runner">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    response = requests.post(
        "https://api.video-tools.com/highlights",
        headers={"Authorization": f"Bearer {api_key}"},
        json={"transcript_text": transcript, "max_clips": 10}
    )
    ```
  </Tab>

  <Tab title="Model 6: Event-Driven">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    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"
        })
    ```
  </Tab>
</Tabs>

## Troubleshooting

<AccordionGroup>
  <Accordion title="No highlights found">
    Ensure your transcript includes timestamps. The recipe needs timing information to plan clips.
  </Accordion>

  <Accordion title="Clips too long or short">
    The recipe targets 15-60 second clips. For different durations, adjust the instructions in a custom fork.
  </Accordion>
</AccordionGroup>

## Next Steps

* **[YouTube Chapter Generator](/docs/examples/recipe-examples/youtube-chapter-generator)** - Generate chapters for full videos
* **[Video Caption Generator](/docs/examples/recipe-examples/video-caption-generator)** - Generate transcripts first
