opencode Skill

muapi-ai-clipping

Turn a long video into N viral-ready short clips with a single managed API call. Wraps muapi.ai's `/ai-clipping` endpoint, which handles transcription, highlight ranking through a virality framework (hook / emotional peak / opinion bomb / revelation / conflict / quotable / story

LLM Mart · 0 points · 10 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download samuraigpt-generative-media-skills-library_edit_ai-clipping-74df8cb.zip · 5 KB
Part of samuraigpt/generative-media-skills — 72 skills

Install

skills CLI npx skills add https://github.com/SamurAIGPT/Generative-Media-Skills/tree/main/library/edit/ai-clipping
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install samuraigpt-generative-media-skills@llmmart
Git git clone https://github.com/SamurAIGPT/Generative-Media-Skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole samuraigpt/generative-media-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

AI Clipping

One API call: long video in → ranked vertical short clips out.

Each clip ships with a viral score (0–100), an opening hook line, a one-sentence "why it works" reason, and a hosted mp4 URL.

Underlying API: https://muapi.ai/playground/ai-clipping Reference implementation (open source): https://github.com/SamurAIGPT/AI-Youtube-Shorts-Generator


When to Use

  • Auto-clip a podcast, interview, lecture, vlog, or stream into TikTok / Reels / Shorts.
  • Extract the best 30–75s moments from any hosted video URL.
  • Get face-tracked vertical (9:16), square (1:1), or portrait (4:5) crops without running ffmpeg locally.

If you only need raw timestamps for your own renderer, set --coords-only to skip cropping and just get the highlight ranges.


Agent Execution Protocol

Step 1 — Collect Inputs

Input Required Default Notes
--video yes — Hosted mp4 URL, or local file path (auto-uploaded), or YouTube URL (if backend supports it)
--num-clips no 3 Number of highlights to extract
--aspect-ratio no 9:16 9:16 | 1:1 | 4:5
--coords-only no off Return just the highlight time ranges, skip cropping

If the user gave only a video URL, run with defaults — don't block on questions.


Step 2 — Verify Prerequisites

  • muapi-cli installed and authed (muapi auth configure)
  • MUAPI_API_KEY available (env var or muapi auth status passes)

That's it. No ffmpeg, no Python, no Whisper install, no LLM keys. Everything runs server-side.


Step 3 — Run the Skill

bash library/edit/ai-clipping/scripts/run-ai-clipping.sh \
  --video "https://example.com/podcast.mp4" \
  --num-clips 5 \
  --aspect-ratio 9:16 \
  --view

The script:

  1. Resolves --video to a hosted URL (uploads local files via muapi upload file if needed).
  2. Calls muapi edit clipping with the supported parameters.
  3. Polls until the job is done (or returns the request_id immediately under --async).
  4. Prints a ranked summary and, if --output-json is set, writes the full result.

What Happens Server-Side

The /ai-clipping endpoint internally runs the full pipeline so the agent doesn't have to:

  • Transcribe with Whisper.
  • Classify content type (podcast / interview / tutorial / vlog / lecture / monologue).
  • Rank highlights through the virality framework:
    • Hook moments — strong opening line that stops the scroll
    • Emotional peaks — laughter, anger, vulnerability, awe
    • Opinion bombs — spicy, contrarian, debate-bait takes
    • Revelation moments — "wait, what?" reframes
    • Conflict — disagreement, tension, callouts
    • Quotable lines — tight, screenshot-worthy phrasing
    • Story peaks — climax of a narrative arc
    • Practical value — actionable insight a viewer will save
  • Dedupe overlapping candidates by score.
  • Top-N select and face-track auto-crop to the requested aspect ratio.

This is why the skill is small: the heavy lifting is on the API.


Quick Invocation Patterns

Defaults — three 9:16 clips:

bash run-ai-clipping.sh --video "https://example.com/long.mp4"

Podcast — more clips, view in player:

bash run-ai-clipping.sh --video "<URL>" --num-clips 8 --view

Square clips for Instagram feed:

bash run-ai-clipping.sh --video "<URL>" --aspect-ratio 1:1 --num-clips 3

Just the timestamps (build your own renderer):

bash run-ai-clipping.sh --video "<URL>" --coords-only --output-json result.json

Async submit (returns request_id, poll later):

REQUEST_ID=$(bash run-ai-clipping.sh --video "<URL>" --async --output-json - | jq -r '.request_id')
muapi predict wait "$REQUEST_ID" --download ./outputs

Local file:

bash run-ai-clipping.sh --video ./recording.mp4 --num-clips 5 --view

Batch — urls.txt with one URL per line:

xargs -a urls.txt -I{} bash run-ai-clipping.sh --video "{}"

Aspect Ratio Picker

Platform Ratio Sweet-spot duration
TikTok / Reels / YouTube Shorts 9:16 30–75s
Instagram Feed 1:1 15–45s
Pinterest / portrait 4:5 30–60s

Default to 9:16 unless the platform is specified.


Output Schema

{
  "source_video_url": "...",
  "shorts": [
    {
      "title": "The one mistake that cost me $50K",
      "start_time": 124.3,
      "end_time": 187.6,
      "score": 92,
      "hook_sentence": "Nobody talks about this, but it killed my first startup...",
      "virality_reason": "Opens with a number + regret, peaks on a contrarian lesson",
      "clip_url": "https://.../short_1.mp4"
    }
  ]
}

When --coords-only is set, each entry has start_time/end_time but no clip_url — render locally with ffmpeg.

When reporting back to the user, surface for each clip: rank, score, time range, title, hook, and clip URL.


Common Mistakes to Avoid

  1. Wrong aspect ratio for the platform — Shorts / TikTok / Reels are 9:16. Default to that.
  2. Padding to hit num_clips — if the API returns fewer survivors than requested, return what you have. Don't pretend.
  3. Re-running on a 404'd clip URL — the same request_id can be re-fetched with muapi predict wait <id> rather than re-clipping.
  4. Trying to tune Whisper / chunk size / LLM prompts — those knobs aren't exposed; the endpoint handles them.

Failure Modes

  • API key missing or rejected — surface the exact error; never fabricate a key.
  • Job timed out — bump poll timeout (--poll-timeout) and retry.
  • Source URL not reachable from the backend — upload locally with muapi upload file <path> first, then pass the returned URL.
  • Fewer clips returned than requested — the source had fewer rankable highlights. Return what came back with a note.

Done Criteria

The skill is done when:

  1. result.shorts has up to num_clips entries, each with a working clip_url (or start_time/end_time under --coords-only).
  2. The user has been shown the ranked list (score, time range, title, hook, URL).
  3. If --output-json was set, the file exists and parses.
Files (generative-media-skills)
  • scripts
    • run-ai-clipping.sh 6.8 KB
      #!/bin/bash
      # AI Clipping — Direct wrapper around muapi.ai's /ai-clipping endpoint.
      #
      # Long video in → ranked vertical short clips out, in one managed API call.
      # Transcription, highlight ranking, dedupe, and face-tracked auto-crop all run
      # server-side. No local Whisper, no local LLM, no GPU.
      #
      # Usage:
      #   bash run-ai-clipping.sh --video "<URL>" [options]
      #
      # Requires: bash 3.2+, jq, muapi-cli
      
      set -euo pipefail
      
      # ============================================================
      # Locate skills root (works regardless of CWD when invoked)
      # ============================================================
      SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
      SKILLS_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
      
      # Load .env from skills root if present
      if [ -f "$SKILLS_ROOT/.env" ]; then
          set +u; source "$SKILLS_ROOT/.env" 2>/dev/null || true; set -u
      fi
      
      # ============================================================
      # Defaults
      # ============================================================
      VIDEO=""
      NUM_CLIPS=3
      ASPECT_RATIO="9:16"
      COORDS_ONLY=false
      OUTPUT_JSON=""
      VIEW=false
      ASYNC=false
      POLL_INTERVAL="${MUAPI_POLL_INTERVAL:-5}"
      POLL_TIMEOUT="${MUAPI_POLL_TIMEOUT:-1800}"
      DOWNLOAD_DIR=""
      
      # ============================================================
      # Argument parsing
      # ============================================================
      while [[ $# -gt 0 ]]; do
          case $1 in
              --video|-v)         VIDEO="$2";         shift 2 ;;
              --num-clips|-n)     NUM_CLIPS="$2";     shift 2 ;;
              --aspect-ratio|-a)  ASPECT_RATIO="$2";  shift 2 ;;
              --coords-only)      COORDS_ONLY=true;   shift   ;;
              --output-json|-o)   OUTPUT_JSON="$2";   shift 2 ;;
              --download)         DOWNLOAD_DIR="$2";  shift 2 ;;
              --view)             VIEW=true;          shift   ;;
              --async)            ASYNC=true;         shift   ;;
              --poll-interval)    POLL_INTERVAL="$2"; shift 2 ;;
              --poll-timeout)     POLL_TIMEOUT="$2";  shift 2 ;;
              --help|-h)
                  cat <<'HELP'
      AI Clipping — long video → ranked vertical clips via muapi.ai's /ai-clipping
      Usage: bash run-ai-clipping.sh --video "<URL>" [options]
      
      REQUIRED
        --video, -v URL_OR_PATH   Hosted mp4 URL, local file path (auto-uploaded), or YouTube URL
      
      OPTIONS
        --num-clips, -n N         Number of highlights to extract (default: 3)
        --aspect-ratio, -a RATIO  9:16 | 1:1 | 4:5  (default: 9:16)
        --coords-only             Return highlight time ranges only, skip cropping
        --output-json, -o PATH    Dump full result here (use "-" for stdout)
        --download DIR            Download generated clips into DIR
        --view                    Download clips and open in system viewer (macOS)
        --async                   Submit and return request_id without polling
        --poll-interval SEC       Seconds between job-status polls (default: 5)
        --poll-timeout SEC        Give up after this long (default: 1800)
      
      EXAMPLES
        # Defaults — three 9:16 clips from a hosted URL
        bash run-ai-clipping.sh --video "https://example.com/podcast.mp4"
      
        # 8 clips, view in player
        bash run-ai-clipping.sh -v "<URL>" -n 8 --view
      
        # Square Instagram-feed clips, dump full result JSON
        bash run-ai-clipping.sh -v "<URL>" -a 1:1 -n 3 -o result.json
      
        # Just timestamps — render locally yourself
        bash run-ai-clipping.sh -v "<URL>" --coords-only -o result.json
      
        # Async — fire-and-forget, poll later
        REQUEST_ID=$(bash run-ai-clipping.sh -v "<URL>" --async -o - | jq -r '.request_id')
        muapi predict wait "$REQUEST_ID" --download ./outputs
      
        # Local file
        bash run-ai-clipping.sh -v ./recording.mp4 -n 5 --view
      HELP
                  exit 0
                  ;;
              *)  echo "Unknown flag: $1" >&2; exit 2 ;;
          esac
      done
      
      # ============================================================
      # Validation
      # ============================================================
      if [[ -z "$VIDEO" ]]; then
          echo "ERROR: --video is required" >&2
          exit 2
      fi
      case "$ASPECT_RATIO" in
          9:16|1:1|4:5) ;;
          *) echo "ERROR: --aspect-ratio must be one of: 9:16, 1:1, 4:5 (got: $ASPECT_RATIO)" >&2; exit 2 ;;
      esac
      if ! command -v muapi >/dev/null 2>&1; then
          echo "ERROR: muapi-cli not found. Install with: npm install -g muapi-cli" >&2
          exit 3
      fi
      if ! command -v jq >/dev/null 2>&1; then
          echo "ERROR: jq not found on PATH" >&2
          exit 3
      fi
      if [[ -z "${MUAPI_API_KEY:-}" ]]; then
          if ! muapi auth status >/dev/null 2>&1; then
              echo "ERROR: MUAPI_API_KEY not set and muapi-cli not authenticated. Run: muapi auth configure" >&2
              exit 3
          fi
      fi
      
      # ============================================================
      # Stage 1 — Resolve --video to a hosted URL
      # ============================================================
      VIDEO_URL=""
      case "$VIDEO" in
          http*://*)
              VIDEO_URL="$VIDEO"
              ;;
          *)
              if [[ ! -f "$VIDEO" ]]; then
                  echo "ERROR: local file not found: $VIDEO" >&2
                  exit 2
              fi
              echo ">> Uploading local file"
              VIDEO_URL=$(muapi upload file "$VIDEO" --output-json --jq '.url' | tr -d '"')
              ;;
      esac
      echo ">> Source: $VIDEO_URL"
      
      # ============================================================
      # Stage 2 — Call /ai-clipping
      # ============================================================
      ARGS=(
          edit clipping
          --video "$VIDEO_URL"
          --num-highlights "$NUM_CLIPS"
          --aspect-ratio "$ASPECT_RATIO"
          --poll-interval "$POLL_INTERVAL"
          --poll-timeout "$POLL_TIMEOUT"
          --output-json
      )
      [[ "$COORDS_ONLY" == true ]] && ARGS+=(--return-coordinates-only)
      [[ "$ASYNC"       == true ]] && ARGS+=(--no-wait)
      if [[ "$VIEW" == true || -n "$DOWNLOAD_DIR" ]]; then
          DOWNLOAD_DIR="${DOWNLOAD_DIR:-./ai-clipping-output}"
          ARGS+=(--download "$DOWNLOAD_DIR")
      fi
      [[ "$VIEW" == true ]] && ARGS+=(--view)
      
      echo ">> Calling muapi edit clipping (num=$NUM_CLIPS, ratio=$ASPECT_RATIO)"
      RAW_RESULT=$(muapi "${ARGS[@]}")
      
      if [[ "$ASYNC" == true ]]; then
          echo "$RAW_RESULT"
          exit 0
      fi
      
      # ============================================================
      # Stage 3 — Report
      # ============================================================
      SHORTS_COUNT=$(echo "$RAW_RESULT" | jq '(.shorts // []) | length')
      echo ""
      echo "========================================================================"
      echo "AI Clipping:   $SHORTS_COUNT clip(s) returned"
      echo "========================================================================"
      echo ""
      
      echo "$RAW_RESULT" | jq -r '
          (.shorts // [])
          | to_entries[]
          | "#\(.key + 1)  score=\(.value.score // "?")  \(.value.start_time)s → \(.value.end_time)s
           title:  \(.value.title // "—")
           hook:   \"\(.value.hook_sentence // "")\"
           reason: \(.value.virality_reason // "—")
           clip:   \(.value.clip_url // "(coords-only)")
      "'
      
      if [[ -n "$OUTPUT_JSON" ]]; then
          if [[ "$OUTPUT_JSON" == "-" ]]; then
              echo "$RAW_RESULT"
          else
              echo "$RAW_RESULT" > "$OUTPUT_JSON"
              echo "Full result written to: $OUTPUT_JSON"
          fi
      fi
      
  • SKILL.md 6.7 KB
    ---
    slug: muapi-ai-clipping
    name: muapi-ai-clipping
    version: "1.0.0"
    description: Turn a long video into N viral-ready short clips with a single managed API call. Wraps muapi.ai's `/ai-clipping` endpoint, which handles transcription, highlight ranking through a virality framework (hook / emotional peak / opinion bomb / revelation / conflict / quotable / story peak / practical value), overlap dedupe, and vertical face-tracking auto-crop server-side. No local Whisper, no local LLM, no GPU.
    acceptLicenseTerms: true
    ---
    
    # AI Clipping
    
    **One API call: long video in → ranked vertical short clips out.**
    
    Each clip ships with a viral score (0–100), an opening hook line, a one-sentence "why it works" reason, and a hosted mp4 URL.
    
    Underlying API: https://muapi.ai/playground/ai-clipping
    Reference implementation (open source): https://github.com/SamurAIGPT/AI-Youtube-Shorts-Generator
    
    ---
    
    ## When to Use
    
    - Auto-clip a podcast, interview, lecture, vlog, or stream into TikTok / Reels / Shorts.
    - Extract the best 30–75s moments from any hosted video URL.
    - Get face-tracked vertical (9:16), square (1:1), or portrait (4:5) crops without running ffmpeg locally.
    
    If you only need raw timestamps for your own renderer, set `--coords-only` to skip cropping and just get the highlight ranges.
    
    ---
    
    ## Agent Execution Protocol
    
    ### Step 1 — Collect Inputs
    
    | Input | Required | Default | Notes |
    |:---|:---|:---|:---|
    | `--video` | yes | — | Hosted mp4 URL, or local file path (auto-uploaded), or YouTube URL (if backend supports it) |
    | `--num-clips` | no | `3` | Number of highlights to extract |
    | `--aspect-ratio` | no | `9:16` | `9:16` \| `1:1` \| `4:5` |
    | `--coords-only` | no | off | Return just the highlight time ranges, skip cropping |
    
    If the user gave only a video URL, run with defaults — don't block on questions.
    
    ---
    
    ### Step 2 — Verify Prerequisites
    
    - `muapi-cli` installed and authed (`muapi auth configure`)
    - `MUAPI_API_KEY` available (env var or `muapi auth status` passes)
    
    That's it. No `ffmpeg`, no Python, no Whisper install, no LLM keys. Everything runs server-side.
    
    ---
    
    ### Step 3 — Run the Skill
    
    ```bash
    bash library/edit/ai-clipping/scripts/run-ai-clipping.sh \
      --video "https://example.com/podcast.mp4" \
      --num-clips 5 \
      --aspect-ratio 9:16 \
      --view
    ```
    
    The script:
    1. Resolves `--video` to a hosted URL (uploads local files via `muapi upload file` if needed).
    2. Calls `muapi edit clipping` with the supported parameters.
    3. Polls until the job is done (or returns the `request_id` immediately under `--async`).
    4. Prints a ranked summary and, if `--output-json` is set, writes the full result.
    
    ---
    
    ## What Happens Server-Side
    
    The `/ai-clipping` endpoint internally runs the full pipeline so the agent doesn't have to:
    
    - **Transcribe** with Whisper.
    - **Classify content type** (podcast / interview / tutorial / vlog / lecture / monologue).
    - **Rank highlights** through the virality framework:
      - **Hook moments** — strong opening line that stops the scroll
      - **Emotional peaks** — laughter, anger, vulnerability, awe
      - **Opinion bombs** — spicy, contrarian, debate-bait takes
      - **Revelation moments** — "wait, what?" reframes
      - **Conflict** — disagreement, tension, callouts
      - **Quotable lines** — tight, screenshot-worthy phrasing
      - **Story peaks** — climax of a narrative arc
      - **Practical value** — actionable insight a viewer will save
    - **Dedupe** overlapping candidates by score.
    - **Top-N select** and **face-track auto-crop** to the requested aspect ratio.
    
    This is why the skill is small: the heavy lifting is on the API.
    
    ---
    
    ## Quick Invocation Patterns
    
    **Defaults — three 9:16 clips:**
    ```bash
    bash run-ai-clipping.sh --video "https://example.com/long.mp4"
    ```
    
    **Podcast — more clips, view in player:**
    ```bash
    bash run-ai-clipping.sh --video "<URL>" --num-clips 8 --view
    ```
    
    **Square clips for Instagram feed:**
    ```bash
    bash run-ai-clipping.sh --video "<URL>" --aspect-ratio 1:1 --num-clips 3
    ```
    
    **Just the timestamps (build your own renderer):**
    ```bash
    bash run-ai-clipping.sh --video "<URL>" --coords-only --output-json result.json
    ```
    
    **Async submit (returns request_id, poll later):**
    ```bash
    REQUEST_ID=$(bash run-ai-clipping.sh --video "<URL>" --async --output-json - | jq -r '.request_id')
    muapi predict wait "$REQUEST_ID" --download ./outputs
    ```
    
    **Local file:**
    ```bash
    bash run-ai-clipping.sh --video ./recording.mp4 --num-clips 5 --view
    ```
    
    **Batch — `urls.txt` with one URL per line:**
    ```bash
    xargs -a urls.txt -I{} bash run-ai-clipping.sh --video "{}"
    ```
    
    ---
    
    ## Aspect Ratio Picker
    
    | Platform | Ratio | Sweet-spot duration |
    |:---|:---|:---|
    | TikTok / Reels / YouTube Shorts | `9:16` | 30–75s |
    | Instagram Feed | `1:1` | 15–45s |
    | Pinterest / portrait | `4:5` | 30–60s |
    
    Default to `9:16` unless the platform is specified.
    
    ---
    
    ## Output Schema
    
    ```json
    {
      "source_video_url": "...",
      "shorts": [
        {
          "title": "The one mistake that cost me $50K",
          "start_time": 124.3,
          "end_time": 187.6,
          "score": 92,
          "hook_sentence": "Nobody talks about this, but it killed my first startup...",
          "virality_reason": "Opens with a number + regret, peaks on a contrarian lesson",
          "clip_url": "https://.../short_1.mp4"
        }
      ]
    }
    ```
    
    When `--coords-only` is set, each entry has `start_time`/`end_time` but no `clip_url` — render locally with ffmpeg.
    
    When reporting back to the user, surface for each clip: rank, score, time range, title, hook, and clip URL.
    
    ---
    
    ## Common Mistakes to Avoid
    
    1. **Wrong aspect ratio for the platform** — Shorts / TikTok / Reels are `9:16`. Default to that.
    2. **Padding to hit `num_clips`** — if the API returns fewer survivors than requested, return what you have. Don't pretend.
    3. **Re-running on a 404'd clip URL** — the same `request_id` can be re-fetched with `muapi predict wait <id>` rather than re-clipping.
    4. **Trying to tune Whisper / chunk size / LLM prompts** — those knobs aren't exposed; the endpoint handles them.
    
    ---
    
    ## Failure Modes
    
    - **API key missing or rejected** — surface the exact error; never fabricate a key.
    - **Job timed out** — bump poll timeout (`--poll-timeout`) and retry.
    - **Source URL not reachable from the backend** — upload locally with `muapi upload file <path>` first, then pass the returned URL.
    - **Fewer clips returned than requested** — the source had fewer rankable highlights. Return what came back with a note.
    
    ---
    
    ## Done Criteria
    
    The skill is done when:
    1. `result.shorts` has up to `num_clips` entries, each with a working `clip_url` (or `start_time`/`end_time` under `--coords-only`).
    2. The user has been shown the ranked list (score, time range, title, hook, URL).
    3. If `--output-json` was set, the file exists and parses.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related