Repository navigation
Conversation
GIFs are stored as GIFs rather than converted to WebP: re-encoding every frame took 25s and ~5GB with Imagick for a 280-frame screen recording, and GD runs out of memory. The GIF is parsed into its blocks and written back, which drops bytes outside them, in ~0.1s. The AI cannot moderate animated images, so ten evenly spaced frames, first and last included, are composited as shown and checked instead. Messages, terminal and scheduled commits still refuse GIFs.
wotta
marked this pull request as draft
October 20, 2026 21:13
Author
wotta
commented
Oct 20, 2026
| /** | ||
| * How many frames of a GIF are checked, spread evenly from its first to its last. | ||
| */ | ||
| private const int GIF_FRAMES = 10; |
Author
There was a problem hiding this comment.
After discussing a bit, 10 seemed fine but I can imagine for longer gifs more could be wanted.
If this feature is wanted at all
| * | ||
| * @return list<string> | ||
| */ | ||
| private function gifFrames(string $bytes): array |
Author
There was a problem hiding this comment.
This is definitely something that I am unsure about. this would mean for a gif at least ten frames are sent to OpenAI
Member
|
Closing as a duplicate of #1184. Thanks for the work on this! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Is this wanted at all? I built this to post a screen recording, but I'm not sure animated GIFs fit /dev/null. Before going further I'd like a yes or no from you, especially on the moderation trade-off below. It's fine to close this if it doesn't fit.
What it does
Animated GIFs can be dropped, pasted or picked into the commit and reply composers, and play on the timeline and the commit page. Messages, terminal commits and scheduled commits still refuse them.
The problem with checking GIFs
Every image is checked by OpenAI's moderation API, and by the minors check, before a commit is approved for others to see. Neither takes animated images: OpenAI accepts only non-animated GIFs. An animated GIF is either refused, which leaves the commit pending forever, or judged by a single frame. A GIF can show something harmless in its first frame and something else later, so checking one frame isn't enough.
What this PR does instead:
UpdateCommitAiDecisiontakes 10 evenly spaced frames, first and last included, and draws each one as a viewer would see it. Most GIF frames only redraw a small patch, so frame offsets and disposal are handled. Each of those frames is checked as a still PNG. On a 280-frame recording that takes about 3 s and 41 MB in the job.The gap that remains: frames between the samples aren't checked. A bad frame shown only briefly between two samples could still get the commit auto-approved. Options I see:
GIF_FRAMES. Each extra frame costs one more moderation call and one more image in the minors check.Why GIFs aren't converted to WebP
I benchmarked the conversion on a real 280-frame, 1112×550 screen recording (1.4 MB):
So GIFs are kept as GIFs. Each one is parsed into its blocks with
intervention/gif, already a dependency, and written back out. This drops anything appended outside the GIF blocks, and a GIF that is cut short is refused. GIFs are not scaled down.CommitImage::mimeType()picks the content type from the file extension for the image route, the feed and the og:image metadata.The composer picker is shared, so a GIF dropped into chat passes the browser check and then gets the server's validation error.
Questions