Sam 426e348c8a
FIX: make stable diffusion multi site friendly (#265)
Previous to this change image generation did not work on multisite

There was a background thread generating the images and it was
getting site settings from the default site in the cluster

This also removes referer header which is not needed
2023-10-25 11:04:16 +11:00

108 lines
2.6 KiB
Ruby

#frozen_string_literal: true
module DiscourseAi::AiBot::Commands
class ImageCommand < Command
class << self
def name
"image"
end
def desc
"Renders an image from the description (remove all connector words, keep it to 40 words or less). Despite being a text based bot you can generate images! (when user asks to draw, paint or other synonyms try this)"
end
def parameters
[
Parameter.new(
name: "prompt",
description:
"The prompt used to generate or create or draw the image (40 words or less, be creative)",
type: "string",
required: true,
),
]
end
end
def result_name
"results"
end
def description_args
{ prompt: @last_prompt }
end
def chain_next_response
false
end
def custom_raw
@custom_raw
end
def process(prompt:)
@last_prompt = prompt
show_progress(localized_description)
results = nil
# this ensures multisite safety since background threads
# generate the images
api_key = SiteSetting.ai_stability_api_key
engine = SiteSetting.ai_stability_engine
api_url = SiteSetting.ai_stability_api_url
# API is flaky, so try a few times
3.times do
begin
thread =
Thread.new do
begin
results =
DiscourseAi::Inference::StabilityGenerator.perform!(
prompt,
engine: engine,
api_key: api_key,
api_url: api_url,
)
rescue => e
Rails.logger.warn("Failed to generate image for prompt #{prompt}: #{e}")
end
end
show_progress(".", progress_caret: true) while !thread.join(2)
break if results
end
end
return { prompt: prompt, error: "Something went wrong, could not generate image" } if !results
uploads = []
results[:artifacts].each_with_index do |image, i|
f = Tempfile.new("v1_txt2img_#{i}.png")
f.binmode
f.write(Base64.decode64(image[:base64]))
f.rewind
uploads << UploadCreator.new(f, "image.png").create_for(bot_user.id)
f.unlink
end
@custom_raw = <<~RAW
[grid]
#{
uploads
.map { |upload| "![#{prompt.gsub(/\|\'\"/, "")}|512x512, 50%](#{upload.short_url})" }
.join(" ")
}
[/grid]
RAW
{ prompt: prompt, displayed_to_user: true }
end
end
end