FEATURE: enforce jpg/png for all images (#1309)

This ensures webp / gif are converted to png prior to sending
to LLMs given webp and gif are not evenly supported.

png/jpg is universally supported and are the only supported format.

longer term we need to add support for audio/video/pdf which is supported by some models.

* more specs
This commit is contained in:
Sam 2025-05-05 17:46:37 +10:00 committed by GitHub
parent b2a6ee9c05
commit a6fa619c31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 44 additions and 2 deletions

View File

@ -10,6 +10,14 @@ module DiscourseAi
next if upload.blank?
next if upload.width.to_i == 0 || upload.height.to_i == 0
desired_extension = upload.extension
desired_extension = "png" if upload.extension == "gif"
desired_extension = "png" if upload.extension == "webp"
desired_extension = "jpeg" if upload.extension == "jpg"
# this keeps it very simple format wise given everyone supports png and jpg
next if !%w[jpeg png].include?(desired_extension)
original_pixels = upload.width * upload.height
image = upload
@ -20,12 +28,15 @@ module DiscourseAi
new_width = (ratio * upload.width).to_i
new_height = (ratio * upload.height).to_i
image = upload.get_optimized_image(new_width, new_height)
image = upload.get_optimized_image(new_width, new_height, format: desired_extension)
elsif upload.extension != desired_extension
image =
upload.get_optimized_image(upload.width, upload.height, format: desired_extension)
end
next if !image
mime_type = MiniMime.lookup_by_filename(upload.original_filename).content_type
mime_type = MiniMime.lookup_by_filename("test.#{desired_extension}").content_type
path = Discourse.store.path_for(image)
if path.blank?

BIN
spec/fixtures/images/1x1.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

BIN
spec/fixtures/images/1x1.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

BIN
spec/fixtures/images/1x1.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 B

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
RSpec.describe DiscourseAi::Completions::UploadEncoder do
let(:gif) { plugin_file_from_fixtures("1x1.gif") }
let(:jpg) { plugin_file_from_fixtures("1x1.jpg") }
let(:webp) { plugin_file_from_fixtures("1x1.webp") }
it "automatically converts gifs to pngs" do
upload = UploadCreator.new(gif, "1x1.gif").create_for(Discourse.system_user.id)
encoded = described_class.encode(upload_ids: [upload.id], max_pixels: 1_048_576)
expect(encoded.length).to eq(1)
expect(encoded[0][:base64]).to be_present
expect(encoded[0][:mime_type]).to eq("image/png")
end
it "automatically converts webp to pngs" do
upload = UploadCreator.new(webp, "1x1.webp").create_for(Discourse.system_user.id)
encoded = described_class.encode(upload_ids: [upload.id], max_pixels: 1_048_576)
expect(encoded.length).to eq(1)
expect(encoded[0][:base64]).to be_present
expect(encoded[0][:mime_type]).to eq("image/png")
end
it "supports jpg" do
upload = UploadCreator.new(jpg, "1x1.jpg").create_for(Discourse.system_user.id)
encoded = described_class.encode(upload_ids: [upload.id], max_pixels: 1_048_576)
expect(encoded.length).to eq(1)
expect(encoded[0][:base64]).to be_present
expect(encoded[0][:mime_type]).to eq("image/jpeg")
end
end