SuperAPI AI Directory

analyze-reference-grammar

Design & creation

View repository

Updated 10-16 08:48

About this skill

analyze-reference-grammar

Purpose

Ingest a video file and measure its editorial DNA: every cut point, the pacing curve (cuts per 10-second window), the audio mode (music-only / vo+music / speech-only), an optional word-level transcript, and the beat grid when music is present. The final output is a grammar-profile.json that characterises the video against the eight creator-grammar archetypes (see CREATOR_GRAMMAR.md §8 and generate-edit-decision-list/references/archetypes.json) and identifies the best-fit archetype with a confidence score.

Two primary use cases:

  1. Reference teardown — drop a winning competitor or reference video in; get back a structured profile you can hand to generate-edit-decision-list to replicate its pacing.
  2. Conform-mode input — re-edit an existing video to this grammar by feeding grammar-profile.json into generate-edit-decision-list (conform source mode).

Inputs

Field Required Notes
source yes Path to a video file (mp4, mov, webm, m4v).
output_dir yes Directory where all outputs are written. Created if absent.
--no-transcribe no Skip Whisper transcription (default: transcription is on). Pass this flag for speed when transcript is not needed.

CLI:

python3 skills/atoms/planning/analyze-reference-grammar/scripts/analyze_grammar.py \
  --source <video> --output-dir <dir> [--no-transcribe]

Workflow

  1. Probe — run ffprobe to extract duration, resolution (width × height), fps, and aspect ratio.
  2. Cut detection — run ffmpeg scene-detect (select='gt(scene,0.3)',showinfo) on the video and parse the frame-number / timestamp output to build a list of cut timestamps. Derive: cut_count, mean_shot_len, shortest_shot, longest_shot, cuts_per_10s[] (one integer per 10-second window across the full duration), and payoff_hold — the single longest shot and its ratio to the mean (the payoff-hold is the "money shot" per CREATOR_GRAMMAR.md §2).
  3. Audio mode — determine whether speech and/or music are present:
    • Run Whisper (whisper CLI or openai-whisper Python API) on the audio stream; if it returns words → has_speech = true.
    • Run ffmpeg volumedetect to measure mean loudness; also scan for silence intervals with silencedetect. If the video has audio but Whisper yields no words (or very few words) → infer music/ambient track → has_music = true.
    • Classify audio_mode as music-only | vo+music | speech-only using the table in CREATOR_GRAMMAR.md §6.
  4. Beat grid (best-effort) — if has_music is true, shell out to ../extract-beat-grid/scripts/extract_beats.py --source <video> --output-dir <output_dir>. Read back beat-grid.json to extract bpm. Tolerate failure (non-zero exit, missing file) — on failure set bpm: null and log a warning.
  5. Transcript — if --no-transcribe is not set and Whisper succeeded, write words.json (array of {word, start, end} objects from Whisper's word-level output).
  6. Archetype classification — score each of the 8 archetypes in archetypes.json against the measured profile:
    • Match audio_mode (exact match scores 40 points).
    • Compare mean cuts_per_10s to the archetype's cuts_per_10s.body target (closer = higher score, max 30 points).
    • Payoff-hold presence vs. archetype's payoff_hold.required (match = 20 points).
    • Aspect ratio match (9:16 is native; 16:9 or 1:1 = slight penalty, max 10 points).
    • Pick the highest-scoring archetype as archetype_match.id; normalise scores to a 0–1 confidence. Record the second-highest as runner_up.
  7. Write outputs — grammar-profile.json, optional words.json, and manifest.json.

grammar-profile.json schema

{
  "schema_version": "1.0",
  "source": "<absolute path>",
  "duration_s": 28.4,
  "resolution": "1080x1920",
  "fps": 30.0,
  "aspect": "9:16",
  "cuts": [0.0, 1.33, 2.67, 5.10, 8.45, 12.00, 15.50, 19.20, 22.80, 26.30],
  "cut_count": 9,
  "mean_shot_len": 2.84,
  "shortest_shot": 0.5,
  "longest_shot": 5.2,
  "payoff_hold": {
    "detected": true,
    "start_s": 8.45,
    "end_s": 13.65,
    "ratio": 1.83
  },
  "cuts_per_10s": [4, 3, 2],
  "audio_mode": "vo+music",
  "has_music": true,
  "has_speech": true,
  "bpm": 128.0,
  "archetype_match": {
    "id": "vo-product-demo",
    "confidence": 0.82,
    "runner_up": "brand-process-film"
  },
  "words_file": "words.json"
}

Output

  • <output_dir>/grammar-profile.json — the complete grammar measurement (schema above).
  • <output_dir>/words.json — word-level transcript array (omitted if --no-transcribe).
  • <output_dir>/manifest.json — skill run metadata (standard manifest schema).

Quality Checks

  • grammar-profile.json is valid JSON and contains all required top-level keys.
  • cut_count equals len(cuts) - 1 (the first entry is always 0.0 for the video start; each subsequent entry is a detected scene change).
  • mean_shot_len equals duration_s / cut_count within ±0.1s (or duration_s if no cuts detected).
  • payoff_hold.ratio is 2–4× the mean shot length when detected: true (per CREATOR_GRAMMAR.md §2).
  • audio_mode is one of the three valid string values.
  • archetype_match.id is one of the 8 IDs in archetypes.json.
  • archetype_match.confidence is in [0, 1].
  • manifest.json status is pass when no fatal errors occurred.

Failure Modes

  • Source not found — the script exits with a clear error before doing any work.
  • ffmpeg / ffprobe not on PATH — install via brew install ffmpeg.
  • No scene changes detected (single-shot video or very low contrast) — cut_count is 0 and cuts is [0.0]; archetype classification still runs against cuts_per_10s = [0, ...].
  • Whisper not installed — transcription is silently skipped, has_speech falls back to energy-only heuristic; a warning is added to the manifest.
  • Beat-grid extraction failure — bpm is set to null, warning logged; the rest of the profile is still written.
  • Video has no audio stream — audio_mode defaults to music-only (safest assumption); has_music and has_speech are both false; bpm is null.
  • Very short video (< 2s) — cuts_per_10s may be empty or have a single element; archetype classification scores may be low-confidence (< 0.4).