Sam 17f04c76d8
FEATURE: add OpenAI image generation and editing capabilities (#1293)
This commit enhances the AI image generation functionality by adding support for:

1. OpenAI's GPT-based image generation model (gpt-image-1)
2. Image editing capabilities through the OpenAI API
3. A new "Designer" persona specialized in image generation and editing
4. Two new AI tools: CreateImage and EditImage

Technical changes include:
- Renaming `ai_openai_dall_e_3_url` to `ai_openai_image_generation_url` with a migration
- Adding `ai_openai_image_edit_url` setting for the image edit API endpoint
- Refactoring image generation code to handle both DALL-E and the newer GPT models
- Supporting multipart/form-data for image editing requests

* wild guess but maybe quantization is breaking the test sometimes

this increases distance

* Update lib/personas/designer.rb

Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>

* simplify and de-flake code

* fix, in chat we need enough context so we know exactly what uploads a user uploaded.

* Update lib/personas/tools/edit_image.rb

Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>

* cleanup downloaded files right away

* fix implementation

---------

Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
2025-04-29 17:38:54 +10:00

78 lines
2.3 KiB
Ruby

# frozen_string_literal: true
module DiscourseAi
module AiHelper
class Painter
def commission_thumbnails(input, user)
return [] if input.blank?
model = SiteSetting.ai_helper_illustrate_post_model
if model == "stable_diffusion_xl"
stable_diffusion_prompt = diffusion_prompt(input, user)
return [] if stable_diffusion_prompt.blank?
artifacts =
DiscourseAi::Inference::StabilityGenerator
.perform!(stable_diffusion_prompt)
.dig(:artifacts)
.to_a
.map { |art| art[:base64] }
base64_to_image(artifacts, user.id)
elsif model == "dall_e_3"
attribution =
I18n.t(
"discourse_ai.ai_helper.painter.attribution.#{SiteSetting.ai_helper_illustrate_post_model}",
)
results =
DiscourseAi::Inference::OpenAiImageGenerator.create_uploads!(
input,
model: "dall-e-3",
user_id: user.id,
title: attribution,
)
results.map { |result| UploadSerializer.new(result[:upload], root: false) }
end
end
private
def base64_to_image(artifacts, user_id)
attribution =
I18n.t(
"discourse_ai.ai_helper.painter.attribution.#{SiteSetting.ai_helper_illustrate_post_model}",
)
artifacts.each_with_index.map do |art, i|
f = Tempfile.new("v1_txt2img_#{i}.png")
f.binmode
f.write(Base64.decode64(art))
f.rewind
upload = UploadCreator.new(f, attribution).create_for(user_id)
f.unlink
UploadSerializer.new(upload, root: false)
end
end
def diffusion_prompt(text, user)
prompt =
DiscourseAi::Completions::Prompt.new(
<<~TEXT.strip,
Provide me a StableDiffusion prompt to generate an image that illustrates the following post in 40 words or less, be creative.
You'll find the post between <input></input> XML tags.
TEXT
messages: [{ type: :user, content: text, id: user.username }],
)
DiscourseAi::Completions::Llm.proxy(SiteSetting.ai_helper_model).generate(
prompt,
user: user,
feature_name: "illustrate_post",
)
end
end
end
end