[output] Add optional TwelveLabs scene labelling#555
Conversation
Adds scenedetect.output.label_scenes, an opt-in helper that attaches a short natural-language description to each detected scene using the TwelveLabs Pegasus video-understanding model. Pixel-based detectors locate the cuts; this forwards each scene's start/end timecode to Pegasus so the description covers only that portion of the video. The integration is gated behind the optional 'twelvelabs' extra and is never invoked during normal detection.
|
that is exciting! the pip install isn't working for me though. user error? |
|
Not user error — that's pip install 'scenedetect[twelvelabs]'One caveat: since this is still an open PR (not yet on PyPI), pip won't find the pip install 'scenedetect[twelvelabs] @ git+https://github.com/mohit-twelvelabs/PySceneDetect.git@feat/twelvelabs-integration'or clone the branch and — Mohit (@mohit-twelvelabs, TwelveLabs) |
|
Awesome, that worked, thanks a lot! |
|
I got it working. Unfortunately the use of a file ID instead of a url doesn't seem to work (I got the error that this is not supported in pegasus 1.5). Also, when running a test with a url I got a BadRequestError error from Pegasus 1.5 because a detected scene was too short: Would be nice to just ignore that to make this more stable? |
Pegasus 1.5 requires each analysed window to be at least 4s and rejects an indexed video_id, so per-scene labelling could 400 and abort the whole pass. - Add MIN_PEGASUS_SCENE_SECONDS (4.0) and skip shorter scenes with a logged note instead of calling analyze() on them. - Catch a per-scene BadRequestError, log it, and continue rather than aborting the batch; auth/quota/server errors still propagate and fail fast. - Treat an id source as an uploaded asset via VideoContext_AssetId, and reject the unsupported video_id up front with a clear, actionable error instead of a confusing raw 400. Update docstring/README accordingly.
|
Thanks for testing this, @frueter — both reports are fixed in 3e27d8c. (a) Scenes shorter than 4s no longer abort the run. Pegasus 1.5 requires each analysed window to span at least 4 seconds, so a short detected scene was 400ing and breaking the whole pass. There's now a (b) The id source no longer produces a confusing error. Confirmed against the SDK (twelvelabs 1.2.8) that Unit tests cover both: a sub-4s scene is skipped without aborting, a per-scene API error is skipped, and the — Mohit (@mohit-twelvelabs, TwelveLabs) |
|
Cool, thanks! I got it working now but made the mistake of running a 15
minute short film through it.
Of course I got a "TooManyRequests" error from twelveLabs after waiting for
a while because I am just on a free account.
Idiot me.
The errors says I need to wait a day, so will do that and try again with a
shorter version, haha.
Thanks, this is cool and I'm keen to include this in the CutDetector app
eventually.
…On Sat, Jun 27, 2026 at 4:03 PM mohit ***@***.***> wrote:
*mohit-twelvelabs* left a comment (Breakthrough/PySceneDetect#555)
<#555 (comment)>
Thanks for testing this, @frueter <https://github.com/frueter> — both
reports are fixed in 3e27d8c
<3e27d8c>
.
*(a) Scenes shorter than 4s no longer abort the run.* Pegasus 1.5
requires each analysed window to span at least 4 seconds, so a short
detected scene was 400ing and breaking the whole pass. There's now a MIN_PEGASUS_SCENE_SECONDS
= 4.0 constant: scenes shorter than that are skipped with a logged
warning (and simply omitted from the results, identifiable by
SceneLabel.index) and the pass continues. I also hardened the per-scene
call so an unexpected BadRequestError from one scene is logged and
skipped rather than aborting the batch — while auth/quota/server errors
still propagate and fail fast.
*(b) The id source no longer produces a confusing error.* Confirmed
against the SDK (twelvelabs 1.2.8) that pegasus1.5 analyze does not
accept an indexed video_id — it needs a video_url or an uploaded asset.
So an id source is now sent as an asset via VideoContext_AssetId (new
asset_id= argument), and passing the old video_id= raises a clear,
actionable ValueError up front (pointing you to video_url=/asset_id=)
instead of letting the API return a raw 400. Docstring and README updated
to match.
Unit tests cover both: a sub-4s scene is skipped without aborting, a
per-scene API error is skipped, and the video_id path raises the up-front
error.
— Mohit ***@***.*** <https://github.com/mohit-twelvelabs>,
TwelveLabs)
—
Reply to this email directly, view it on GitHub
<#555?email_source=notifications&email_token=AANFIKYYUJKRREVQ2HBJQLT5B5BP7A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIOBRGUYTIMJYGIZ2M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-4815141823>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AANFIK7LGWGLPCGY4SMZML35B5BP7AVCNFSNUABEKJSXA33TNF2G64TZHMZDANBXGA2DIOJ3JFZXG5LFHM2DONBXGIZTOMBZGGQXMAQ>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/AANFIKYJK4BR4T26K276QU35B5BP7A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIOBRGUYTIMJYGIZ2M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJKTGN5XXIZLSL5UW64Y>
and Android
<https://github.com/notifications/mobile/android/AANFIK6444YDVJ5ZYLYF4TT5B5BP7A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIOBRGUYTIMJYGIZ2M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLTGN5XXIZLSL5QW4ZDSN5UWI>.
Download it today!
You are receiving this because you were mentioned.Message ID:
***@***.***>
--
Frank Rueter I VFX Supervisor | OHUfx | +64 21 110 7919
Aotearoa | New Zealand
www.ohufx.com
|
Catch TooManyRequestsError per scene: log a clear warning (with Retry-After when present), stop further per-scene calls, and return the labels gathered so far instead of aborting the whole pass. Long videos on the free tier can hit the quota mid-run; consistent with the existing skip-and-continue contract.
|
@frueter No worries at all — thanks for putting it through a real 15-minute film, that's exactly the kind of run that surfaces this. Fixed in commit So a long video on the free tier now degrades gracefully — you get partial labels and a clear message rather than a crash, and can rerun once the quota resets to pick up the remainder. Really glad you're keen to bring it into CutDetector! — Mohit (@mohit-twelvelabs, TwelveLabs) |
|
Awesome, thank you!
Frank Rueter I VFX Supervisor | OHUfx | +64 21 110 7919
Aotearoa | New Zealand
www.ohufx.com
…On Sat, 27 Jun 2026, 9:39 pm mohit, ***@***.***> wrote:
*mohit-twelvelabs* left a comment (Breakthrough/PySceneDetect#555)
<#555 (comment)>
@frueter <https://github.com/frueter> No worries at all — thanks for
putting it through a real 15-minute film, that's exactly the kind of run
that surfaces this.
Fixed in commit 2688d10: label_scenes now catches the TwelveLabs
rate-limit error (HTTP 429 / TooManyRequestsError). Instead of erroring
out the whole run, it logs a clear warning (e.g. "TwelveLabs rate limit hit
(free-tier quota?) — stopping scene labelling early; returning the labels
generated so far"), stops making further per-scene Pegasus calls (once
you're throttled, the rest would just 429 too), and returns the labels
collected up to that point. If the API sends a Retry-After, it's included
in the warning so you know roughly when the quota resets. I also added a
unit test that mocks a 429 mid-pass and asserts the run stops gracefully
with partial results rather than raising, plus a docs note that long videos
on the free tier can hit the limit.
So a long video on the free tier now degrades gracefully — you get partial
labels and a clear message rather than a crash, and can rerun once the
quota resets to pick up the remainder. Really glad you're keen to bring it
into CutDetector!
— Mohit ***@***.*** <https://github.com/mohit-twelvelabs>,
TwelveLabs)
—
Reply to this email directly, view it on GitHub
<#555?email_source=notifications&email_token=AANFIK6OYMWJ6RXAGDXVSV35B6I4NA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIOBRGY2DGNRZGI32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-4816436927>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AANFIK2MWF3M2AN2SH5M3UT5B6I4NAVCNFSNUABEKJSXA33TNF2G64TZHMZDANBXGA2DIOJ3JFZXG5LFHM2DONBXGIZTOMBZGGQXMAQ>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/AANFIK7O5ZXEWCBMUU7QGKT5B6I4NA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIOBRGY2DGNRZGI32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJKTGN5XXIZLSL5UW64Y>
and Android
<https://github.com/notifications/mobile/android/AANFIKZ6PO7M3GUSQIRYOYL5B6I4NA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIOBRGY2DGNRZGI32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLTGN5XXIZLSL5QW4ZDSN5UWI>.
Download it today!
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
Sorry for the delay in getting back to you on this. I appreciate the PR, but I'm not a fan of this approach for plugins/integrations. I really do want to interop with the ecosystem more generally, but I want to explore one of the recommended options from https://packaging.python.org/en/latest/guides/creating-and-discovering-plugins/ first (tracked under issue #240). E.g. it should be possible for you to publish your own That's also an option today if you wanted to I suppose, e.g. something like: from scenedetect import detect, ContentDetector
from scenedetect_twelvelabs import label_scenes
scenes = detect("my_video.mp4", ContentDetector())
for label in label_scenes(scenes, video_url="https://example.com/my_video.mp4"):
print(label.index, label.label)Until we work out how to actually get the namespace injection stuff working. Thoughts? For now I've closed this as rejected, but I'm still open to discussions on how to actually get a proper plugin system going in #240. I do appreciate your effort on this, very well put together PR. |
|
Thanks so much, @Breakthrough — and no worries at all about the timing. Really appreciate the thoughtful close and the kind words. Your instinct makes total sense: a standalone Thanks again for the careful look, and for keeping the door open. |
|
I agree and this is actually what I was looking for initially.
It will be great to see supporting packages like this out there!
Am already starting to think how to create a good UX for it in
CutDetector...
Frank Rueter I VFX Supervisor | OHUfx | +64 21 110 7919
Aotearoa | New Zealand
www.ohufx.com
…On Sun, 28 Jun 2026, 2:19 pm Brandon Castellano, ***@***.***> wrote:
*Breakthrough* left a comment (Breakthrough/PySceneDetect#555)
<#555 (comment)>
Sorry for the delay in getting back to you on this. I don't think this is
a good idea for now - I really do want to interop with the ecosystem more
generally, but we can't just use optional dependencies for integrations
like this. I want to go with a proper plugin system re: #240
<#240> which would
allow you to publish your own scenedetect-twelvelabs package on PyPI.
That's also an option today if you wanted to I suppose, e.g. something
like:
from scenedetect import detect, ContentDetectorfrom scenedetect_twelvelabs import label_scenes
scenes = detect("my_video.mp4", ContentDetector())for label in label_scenes(scenes, video_url="https://example.com/my_video.mp4"):
print(label.index, label.label)
Thoughts? For now I've closed this as rejected but I'm still open to
discussions on how to actually get a proper plugin system going.
—
Reply to this email directly, view it on GitHub
<#555?email_source=notifications&email_token=AANFIKYWULFOGZQY7566XI35CB6E5A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIOBSGQYTSOJZGEZ2M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-4824199913>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AANFIK5HTWJUYVPSUY2ZGPD5CB6E5AVCNFSNUABEKJSXA33TNF2G64TZHMZDANBXGA2DIOJ3JFZXG5LFHM2DONBXGIZTOMBZGGQXMAQ>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/AANFIKYAE7NQTOWRKPMSLX35CB6E5A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIOBSGQYTSOJZGEZ2M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJKTGN5XXIZLSL5UW64Y>
and Android
<https://github.com/notifications/mobile/android/AANFIKZKKJEWEXW2T355HHL5CB6E5A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIOBSGQYTSOJZGEZ2M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLTGN5XXIZLSL5QW4ZDSN5UWI>.
Download it today!
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
I'll go ahead and say pre-emptively that, if you're keen, you folks are more than welcome to create your own package using Eventually we should probably come up with a set of guidelines such as https://flask.palletsprojects.com/en/stable/extensiondev/#recommended-extension-guidelines but for now I'm totally fine with just adopting the same pattern of having plugins use the |
Hi! I'm Mohit, I work at TwelveLabs (@mohit-twelvelabs).
What this adds
An opt-in
scenedetect.output.label_sceneshelper that attaches a short natural-language description to each detected scene using the TwelveLabs Pegasus video-understanding model.PySceneDetect's detectors find where the cuts are (pixel/histogram/hash based); this complements that by answering what is in each scene. Each detected scene's start/end timecode is forwarded to Pegasus via its
start_time/end_timeparameters, so each description covers only that portion of the video and the labels line up 1:1 with the scene list:Why it helps
A common ask after shot detection is a quick semantic summary per scene (for editing, search, dataset labelling, highlight reels). This wires that in without the user having to build their own pipeline, while keeping PySceneDetect's pixel-based detection as the source of truth for cut boundaries.
Opt-in / non-breaking
pip install scenedetect[twelvelabs]. Thetwelvelabspackage is not a hard dependency; if it's missing,label_scenesraises a friendlyImportErrorwith install instructions.scenedetect.outputhelpers, following the existing re-export convention.How it was tested
tests/test_labels.py) using a fake client assert the per-scene timecode wiring and source-argument validation; these run in CI without a key.TWELVELABS_API_KEY(and aTWELVELABS_TEST_VIDEO_URL) are set.analyzerequest wiring (modelpegasus1.5, video source, prompt, per-scenestart_time/end_time,max_tokens) passes all server-side parameter validation. Full per-scene generation against a hosted sample is pending a clean public sample URL.ruff checkandruff format --checkpass on all changed files;pytest tests/test_labels.pypasses (2 passed, 1 skipped).You can grab a free API key at https://twelvelabs.io — there's a generous free tier.