#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 # API is flaky, so try a few times 3.times do begin thread = Thread.new do begin results = DiscourseAi::Inference::StabilityGenerator.perform!(prompt) 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 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