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
Same prompt, thinking on and off
| Run | Time | Completion tokens | Cost | Picks that passed |
|---|---|---|---|---|
| Gemma 4, thinking on (default) | 96 s | About 8,200 | Under 1 cent | All 3 |
| Gemma 4, thinking off | 6 s | About 270 | Under a tenth of a cent | None |
| clipsdk, ranked and rendered | 92 s | Included | About $0.29 | 3 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.
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.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.023sCheck 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?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.
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"
}'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
promptand 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.
Keep reading
- Moment ranking: the best parts of a long video, scored 0 to 100clipsdk scores every moment of a long video 0 to 100 on hook, complete thought and payoff, and returns up to 20 ranked clips of 10 to 90 seconds, each with a one-line reason.
- Build an OpusClip cloneThe whole clipping pipeline in 5 Python files: transcribe, pick moments with an LLM, reframe to 9:16, caption and render, with real costs.
- Turn every podcast episode into a week of shortsUpload a podcast episode and get up to 20 vertical clips, each scored 0 to 100 with a reason, reframed to the speaker and captioned. A 60 minute episode costs ~$1.80.
- POST /v1/clips referencePOST /v1/clips takes a video URL and returns up to 20 clips of 10 to 90 s, scored 0 to 100. Defaults: 5 clips of 20 to 60 s, 9:16 at 1080x1920, bold captions, auto reframe.
- Scene cut detection for clipsFind hard cuts with PySceneDetect and ffmpeg scdet, split a clip into shots, and see why a vertical reframe must restart at each one.
- TikTok safe zonesTikTok, Reels and YouTube safe zones for captions in pixels at 1080x1920, measured from TikTok's own template, with a script that checks your clips.
Sources
- Cloudflare: Gemma 4 26B A4B on Workers AI, checked 7 November 2026
- Cloudflare: Workers AI pricing, checked 7 November 2026
- NASA: Rocket Ranch podcast with Moogega Cooper, checked 7 November 2026
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.
