Guide

A tested prompt gets Gemma 4 on Workers AI to pick clips with a hook, a complete thought and a payoff, for under 1 cent per 10-minute podcast. clipsdk ranks and renders every clip for $0.03 per source minute.

Find viral moments in a transcript with an LLM

A clip works on its own when it has 3 things, a hook in the first line, one complete thought and a payoff at the end, so our prompt to Gemma 4 asks for exactly that.

GuidesUpdated

Or one API call

$0.03per source minute

  • Every clip included, up to 1080p60 and 20 Mb/s
  • $1 free to start, 33 minutes of video
  • Prepaid credit, no subscription
See pricing

Same prompt, thinking on and off

Same prompt, thinking on and off
RunTimeCompletion tokensCostPicks that passed
Gemma 4, thinking on (default)96 sAbout 8,200Under 1 centAll 3
Gemma 4, thinking off6 sAbout 270Under a tenth of a centNone
clipsdk, ranked and rendered92 sIncludedAbout $0.293 clips

Both Gemma 4 runs read the same transcript of a 10-minute podcast. Workers AI prices Gemma 4 at $0.10 per million input tokens and $0.30 per million output tokens.

Pick moments with an LLM in 4 steps

You need a transcript with word timestamps; our OpusClip clone guide gets one from Whisper and has the small workers_ai.py helper these files import. Everything below ran on NASA's Rocket Ranch podcast.

  1. Number the transcript

    Give the model numbered lines with times, and ask for line numbers back. Numbers are easy to check, while times the model types itself can drift. A line ends at a full stop, a question mark or a pause over 0.7 s.

    lines.py
    import json
    
    words = json.load(open("words.json"))
    
    # One numbered line per sentence, or per stretch of speech that ends in a pause
    lines, current = [], []
    for i, word in enumerate(words):
        current.append(word)
        next_start = words[i + 1]["start"] if i + 1 < len(words) else None
        if word["word"][-1] in ".?!" or next_start is None or next_start - word["end"] > 0.7:
            lines.append({
                "id": len(lines),
                "start": current[0]["start"],
                "end": word["end"],
                "text": " ".join(w["word"] for w in current),
            })
            current = []
    
    json.dump(lines, open("lines.json", "w"))
    print(len(lines), "lines")
    for line in lines[60:63]:
        print(f'[{line["id"]}] {line["start"]:.1f}-{line["end"]:.1f}: {line["text"]}')
    
    # $ python3 lines.py
    # 158 lines
    # [60] 236.7-237.9: Now the science begins.
    # [61] 237.9-246.9: The scary part of getting off the earth, traveling, you know, 300 million miles and landing on the surface is over, now the science can begin.
    # [62] 247.9-260.0: You know, one of the things I think of when they do the EDL, when it lands, is that I think, I don't know if it was during Curiosity or one of the recent missions where, I believe there was a choreographed dance move.
    
  2. Ask for hook, complete thought and payoff

    The prompt names the 3 things a clip needs, the length in seconds and the rules, and a JSON schema makes the answer parse every time. The model also returns its hook and payoff lines, so you can see why it picked each clip.

    pick.py
    import json
    from workers_ai import run
    
    lines = json.load(open("lines.json"))
    transcript = "\n".join(f'[{l["id"]}] {l["start"]:.1f}-{l["end"]:.1f}: {l["text"]}' for l in lines)
    
    prompt = f"""Below is a podcast transcript. Each line is [id] start-end seconds: text.
    
    Pick the 3 best moments to post as standalone clips on TikTok, Reels and Shorts.
    A good clip has all three of these:
    1. Hook: the first line makes a stranger stop scrolling (a question, a bold claim, a surprise).
    2. Complete thought: it makes sense without the rest of the episode.
    3. Payoff: it ends on the answer, the punchline or the conclusion, never mid-thought.
    
    Rules:
    - A clip is a run of whole lines, from first_line to last_line.
    - A clip lasts 20 to 60 seconds: last line's end minus first line's start.
    - Clips must not overlap.
    - Skip intros, outros, thank-yous and plugs.
    - Score each clip 0 to 100 for how well it works on its own.
    
    Transcript:
    {transcript}"""
    
    schema = {
        "type": "object",
        "properties": {
            "clips": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "first_line": {"type": "integer"},
                        "last_line": {"type": "integer"},
                        "hook": {"type": "string"},
                        "payoff": {"type": "string"},
                        "score": {"type": "integer"},
                    },
                    "required": ["first_line", "last_line", "hook", "payoff", "score"],
                },
            }
        },
        "required": ["clips"],
    }
    
    result = run("@cf/google/gemma-4-26b-a4b-it", {
        "messages": [{"role": "user", "content": prompt}],
        "response_format": {"type": "json_schema", "json_schema": {"name": "clips", "schema": schema, "strict": True}},
    })
    
    picks = json.loads(result["choices"][0]["message"]["content"])["clips"]
    json.dump(picks, open("picks.json", "w"), indent=2)
    print(json.dumps(picks, indent=2))
    print(result["usage"]["prompt_tokens"], "prompt tokens,", result["usage"]["completion_tokens"], "completion tokens")
    
    # $ time python3 pick.py
    # [
    #   {
    #     "first_line": 22,
    #     "last_line": 34,
    #     "hook": "It's a big deal. It is. So much so they call it the seven minutes of terror.",
    #     "payoff": "I mean, all of these things have to happen right.",
    #     "score": 95
    #   },
    #   {
    #     "first_line": 53,
    #     "last_line": 60,
    #     "hook": "Why do you see people jumping for joy and hugging each other and crying?",
    #     "payoff": "Now the science begins.",
    #     "score": 90
    #   },
    #   {
    #     "first_line": 113,
    #     "last_line": 119,
    #     "hook": "I mean, what would be a sign of ancient life?",
    #     "payoff": "So there are these biosignatures that really hint more strongly at the fact that it comes from something that was living.",
    #     "score": 88
    #   }
    # ]
    # 5194 prompt tokens, 8186 completion tokens
    #
    # real	1m35.817s
    # user	0m0.090s
    # sys	0m0.023s
    
  3. Check every pick

    Don't cut what the model says without checking it. This script drops picks with missing line numbers, picks outside 20 to 60 s and picks that overlap a better one. All 3 of ours passed.

    check.py
    import json
    
    lines = {l["id"]: l for l in json.load(open("lines.json"))}
    picks = json.load(open("picks.json"))
    
    # Turn line ids into times, then drop anything the rules forbid
    kept = []
    for pick in sorted(picks, key=lambda p: -p["score"]):
        first, last = lines.get(pick["first_line"]), lines.get(pick["last_line"])
        if first is None or last is None or last["id"] < first["id"]:
            print("bad line ids:", pick)
            continue
        start, end = first["start"], last["end"]
        if not 20 <= end - start <= 60:
            print(f"wrong length ({end - start:.1f} s):", pick["hook"])
            continue
        if any(start < k["end"] and k["start"] < end for k in kept):
            print("overlaps a better clip:", pick["hook"])
            continue
        kept.append({"start": start, "end": end, "score": pick["score"], "hook": pick["hook"]})
    
    for clip in kept:
        print(f'{clip["start"]:.1f}-{clip["end"]:.1f} s ({clip["end"] - clip["start"]:.1f} s) score {clip["score"]}: {clip["hook"]}')
    json.dump(kept, open("clips.json", "w"), indent=2)
    
    # $ python3 check.py
    # 76.9-123.6 s (46.7 s) score 95: It's a big deal. It is. So much so they call it the seven minutes of terror.
    # 187.8-237.9 s (50.1 s) score 90: Why do you see people jumping for joy and hugging each other and crying?
    # 421.7-462.1 s (40.4 s) score 88: I mean, what would be a sign of ancient life?
    
  4. Keep the model's thinking on

    Turning thinking off brought the answer back in about 6 seconds instead of 96, but none of its 3 picks passed: one ran backwards from line 79 to line 34, and two named lines past the end of the transcript.

    thinking-off.txt
    # pick_fast.py is pick.py with one more field in the request,
    # and it writes picks_fast.json:
    #     "chat_template_kwargs": {"enable_thinking": False},
    # check_fast.py is check.py reading picks_fast.json
    
    $ time python3 pick_fast.py
    [
      {
        "first_line": 79,
        "last_line": 34,
        "hook": "So much so they call it the seven minutes of terror.",
        "payoff": "I mean, all of these things have to happen right.",
        "score": 95
      },
      {
        "first_line": 337,
        "last_line": 394,
        "hook": "Yeah, so even down to the drill, if you look at prior rovers, like the Curiosity rover, it has a drill that's meant to grind the soil and the dirt and the rocks into a fine powder.",
        "payoff": "It's about 10 centimeters long.",
        "score": 88
      },
      {
        "first_line": 549,
        "last_line": 570,
        "hook": "Do you think there might be ancient life on Mars?",
        "payoff": "It doesn't matter what I think. Let's see what the data says.",
        "score": 92
      }
    ]
    5191 prompt tokens, 272 completion tokens
    
    real	0m5.937s
    user	0m0.078s
    sys	0m0.024s
    
    $ python3 check_fast.py
    bad line ids: {'first_line': 79, 'last_line': 34, 'hook': 'So much so they call it the seven minutes of terror.', 'payoff': 'I mean, all of these things have to happen right.', 'score': 95}
    bad line ids: {'first_line': 549, 'last_line': 570, 'hook': 'Do you think there might be ancient life on Mars?', 'payoff': "It doesn't matter what I think. Let's see what the data says.", 'score': 92}
    bad line ids: {'first_line': 337, 'last_line': 394, 'hook': "Yeah, so even down to the drill, if you look at prior rovers, like the Curiosity rover, it has a drill that's meant to grind the soil and the dirt and the rocks into a fine powder.", 'payoff': "It's about 10 centimeters long.", 'score': 88}
    

Or send one request

clipsdk takes an optional prompt of up to 500 characters that says what to look for. We asked the same podcast for moments about the search for life on Mars and got 3 clips back in about a minute and a half.

The top one, scored 92, asks whether life could exist on Mars; the others cover biosignatures and how NASA keeps Earth life off the rover. Each clip comes back with a title, a reason, its transcript and SRT and VTT files.

POST/v1/clipsTry it
curl https://api.clipsdk.com/v1/clips \
  -H "Authorization: Bearer $CLIPSDK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://api.clipsdk.com/f/lib/demo/rocket-ranch-podcast.mp4",
    "clips": 3,
    "aspect": "9:16",
    "captions": "bold",
    "prompt": "moments about the search for life on Mars"
  }'
Top clip for this prompt, 22 seconds, score 92: Could life exist on Mars?clip-1.mp4clip-1.jpg

How clipsdk ranks moments

clipsdk does the same job with the checks built in.

  • The model's clips start and end on whole sentences. A sentence ends at its full stop, at a 0.8 s pause or after 40 words.
  • Gemma 4 26B on Workers AI scores each candidate from 0 to 100, and Qwen3 30B takes over if Gemma 4 fails. 80 and up is strong; under 50 is weak.
  • Up to 20 minutes of source go in one call. Longer videos split into 15 minute windows that overlap by 90 s, then one more call puts the best 40 candidates side by side on the same rubric.
  • A clip that overlaps a better one by more than 30% is dropped, and each clip gets up to 0.25 s of lead-in and 0.5 s at the end.
  • Clips the code adds itself, rather than the model, score 49 at most and always rank below the model's picks.
  • Your prompt and the speech each sit in their own fenced block, so a quote in the video can't pass itself off as your request.

What it costs

The ranking call cost under 1 cent on Workers AI, almost all of it thinking tokens, and it fits inside the free 10,000 neurons a day. Transcribing is extra, and so is cutting, reframing and rendering the clips.

clipsdk charged about $0.29 for the episode, just under 10 minutes at $0.03 per source minute, for 3 rendered clips. See pricing for the clip minute floor and the volume rate.

Questions, answered

Can an LLM find the best moments in a video?

Yes, from a transcript. Give it numbered lines with timestamps, ask for a hook, one complete thought and a payoff, and have it answer with line numbers. Then check its answer in code before you cut anything.

What is a good prompt for finding viral clips?

Name the 3 things a clip needs: a first line that stops the scroll, a thought that makes sense without the rest of the episode, and an ending that pays it off. Add the length in seconds, ban overlaps, intros and plugs, and ask for a score from 0 to 100.

Is there a free transcript to clips converter?

The code on this page is free to run. On Workers AI the ranking call costs under 1 cent for a 10-minute podcast and fits in the free 10,000 neurons a day. clipsdk's first $1 is free, about 33 source minutes, and it cuts and renders the clips too.

Which model does clipsdk use to rank clips?

Gemma 4 26B on Workers AI, with Qwen3 30B as the fallback. Both score on the same 0 to 100 rubric.

Start free

Your back catalog is full of shorts

Your first $1 is free: 33 minutes of video, every clip included up to 1080p60 and 20 Mb/s.

Two studio microphones on a desk in a dark room lit by a red glow