From 43888fa5ea1d43893add930032fa7d4fe41f6c3a Mon Sep 17 00:00:00 2001 From: drusepth Date: Tue, 17 Jan 2023 14:39:04 -0800 Subject: [PATCH 01/11] this probably works for generating creatures, time to test on big boi server lol --- bin/generate-image-from-prompt.py | 27 ++++++++++ bin/tristan.rb | 90 ++++++++++++++++++++++++++++++- 2 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 bin/generate-image-from-prompt.py diff --git a/bin/generate-image-from-prompt.py b/bin/generate-image-from-prompt.py new file mode 100644 index 0000000..7e7b5ec --- /dev/null +++ b/bin/generate-image-from-prompt.py @@ -0,0 +1,27 @@ +import argparse +import redis +import torch +from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler + +print("In Pythonland") +parser = argparse.ArgumentParser() +parser.add_argument("prompt_id", type=str, help="The id of the prompt to retrieve.") +parser.add_argument("output_name", type=str, help="The name of the output file.") +args = parser.parse_args() + +# Read prompt from Redis +print("Reading prompt from Redis...") +r = redis.Redis(host='localhost', port=6379, db=0) +prompt = str(r.get(args.prompt_id)) +print("Generating image for prompt:\n", prompt) + +# Use the DPMSolverMultistepScheduler (DPM-Solver++) scheduler here instead +#model_id = "stabilityai/stable-diffusion-2-1" +model_id = "CompVis/stable-diffusion-v1-4" +pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16) +#pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config) +pipe.enable_attention_slicing() +pipe = pipe.to("cuda") + +image = pipe(prompt).images[0] +image.save("generated/" + args.output_name) diff --git a/bin/tristan.rb b/bin/tristan.rb index e30b14b..dfe97f5 100644 --- a/bin/tristan.rb +++ b/bin/tristan.rb @@ -166,9 +166,7 @@ def possessive_adjective(template) def generate_character(event:, template:) puts "Generating a character [#{template.join(',')}] for #{event.interaction.user.username}" - character_template = {} - character_template[:name] = Faker::Name.name if template.include?('name') if template.include?('archetype') @@ -383,6 +381,56 @@ def generate_character(event:, template:) end end +def generate_creature(event:, template:) + puts "Generating a creature [#{template.join(',')}] for #{event.interaction.user.username}" + creature_template = {} + creature_template[:name] = 'Creature name' if template.include?('name') + + template_prelude = "Here's your generated creature, #{event.interaction.user.mention}!\n\n" + template_id = Time.now.to_i.to_s + '-' + event.interaction.user.username + + # Save this template in redis so we can look it up to generate new creatures from later (which gets around storing the template in + # discord's custom_id, which only allows 100 characters). + @redis.set(template_id, template.join(',')) + + # Start by sending the creature image first, then the template. + if template.include?('image') + # So... apparently we need Python for anything HF-related because Ruby doesn't have a library for it. + # So we'll just shell out to Python and let it do the work for us -- but we'll generate our prompt + # here and set it in Redis so Python can pull it out to do the work. + prompt = [ + "A #{Faker::Creature::Animal.name} mixed with a #{Faker::Creature::Animal.name}", + "rare undiscovered species of living in forest, photograph, masterpiece, trending on cgsociety, exotic, realistic rendering, fictional creature, alien, cinematic lighting, volumetric lighting, cinematic, fantasy art, detailed" + ].join(', ') + prompt_id = 'prompt-' + Time.now.to_i.to_s + '-' + event.interaction.user.username + @redis.set(prompt_id, prompt) + + puts "Piping out to Python..." + system("python3 generate-image-from-prompt.py #{prompt_id} #{event.interaction.user.username + '-' + Time.now.to_i.to_s + '.png'}") + + puts "Back from Python..." + if File.exists("generated/#{event.interaction.user.username + '-' + Time.now.to_i.to_s + '.png'}") + event.send_file( + File.open("generated/#{event.interaction.user.username + '-' + Time.now.to_i.to_s + '.png'}", 'r'), + caption: "Creature image" + ) + else + puts "No file found!" + end + end + + event.respond(content: template_prelude + creature_template.map { |key, value| "**#{key.to_s.gsub('_', ' ').capitalize}**: #{value}" }.join("\n")) do |_, view| + view.row do |r| + r.button(label: 'Generate another creature with this template', style: :success, custom_id: 'reroll_character:' + template_id) + r.button(label: 'Use a new template', style: :secondary, custom_id: 'creature_template_builder') + end + end + + # After sending the image, we should clean it up and delete our local copy so we don't fill up the server's disk. + # sleep(5) + # File.delete("pic.png") +end + bot = Discordrb::Bot.new( token: ENV.fetch('DISCORD_TOKEN'), intents: [:server_messages] @@ -390,6 +438,7 @@ def generate_character(event:, template:) bot.register_application_command(:generate, 'Generators') do |generators| generators.subcommand(:character, 'Generate a filled-out character template') + generators.subcommand(:creature, 'Generate a filled-out creature template') end def show_character_template_menu(event) @@ -432,18 +481,48 @@ def show_character_template_menu(event) end end +def show_creature_template_menu(event) + creature_generation_introduction = [ + "**Generate a creature**", + "Generating a creature is a WIP. Right now, you can only generate a random creature's art." + ] + event.respond(content: creature_generation_introduction.join("\n"), ephemeral: true) do |_, view| + view.row do |r| + r.select_menu(custom_id: 'generate_creature', placeholder: 'Build your creature template', min_values: 1, max_values: 25) do |s| + # s.option(label: 'Name', value: 'name') + # s.option(label: 'Description', value: 'description') + s.option(label: 'Image', value: 'image') + # s.option(label: 'Biome', value: 'biome') + # s.option(label: 'Taxonomy', value: 'taxonomy') + end + end + end +end + bot.application_command(:generate).subcommand(:character) do |event| show_character_template_menu(event) end +bot.application_command(:generate).subcommand(:creature) do |event| + show_creature_template_menu(event) +end + bot.button(custom_id: 'character_template_builder') do |event| show_character_template_menu(event) end +bot.button(custom_id: 'creature_template_builder') do |event| + show_creature_template_menu(event) +end + bot.select_menu(custom_id: 'generate_character') do |event| generate_character(event: event, template: event.values) end +bot.select_menu(custom_id: 'generate_creature') do |event| + generate_creature(event: event, template: event.values) +end + bot.button(custom_id: /^reroll_character:/) do |event| template_id = event.interaction.button.custom_id.split(':').last attributes = @redis.get(template_id).split(',') @@ -451,4 +530,11 @@ def show_character_template_menu(event) generate_character(event: event, template: attributes) end +bot.button(custom_id: /^reroll_creature:/) do |event| + template_id = event.interaction.button.custom_id.split(':').last + attributes = @redis.get(template_id).split(',') + + generate_creature(event: event, template: attributes) +end + bot.run From 3413073aa67741263263c947bc36cc867ce4b0d6 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Tue, 17 Jan 2023 14:52:40 -0800 Subject: [PATCH 02/11] upgrade all the things --- .ruby-version | 2 +- Gemfile | 2 +- Gemfile.lock | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.ruby-version b/.ruby-version index a4dd9db..944880f 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.4 +3.2.0 diff --git a/Gemfile b/Gemfile index c70fc8d..0616302 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source "https://rubygems.org" git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby "2.7.4" +ruby "3.2.0" # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" gem "rails", "~> 7.0.2", ">= 7.0.2.3" diff --git a/Gemfile.lock b/Gemfile.lock index 9ea70ef..5c58b0f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -143,7 +143,7 @@ GEM timeout netrc (0.11.0) nio4r (2.5.8) - nokogiri (1.13.6-x86_64-linux) + nokogiri (1.14.0-x86_64-linux) racc (~> 1.4) opus-ruby (1.0.1) ffi @@ -153,7 +153,7 @@ GEM method_source (~> 1.0) puma (5.6.4) nio4r (~> 2.0) - racc (1.6.0) + racc (1.6.2) rack (2.2.4) rack-test (2.0.2) rack (>= 1.3) @@ -232,7 +232,7 @@ DEPENDENCIES tzinfo-data RUBY VERSION - ruby 2.7.4p191 + ruby 3.2.0p0 BUNDLED WITH 2.3.5 From eba0a79bc2cffbcee0097fc111d70550a162a8d5 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Tue, 17 Jan 2023 15:27:57 -0800 Subject: [PATCH 03/11] tweaks from tests: --- .gitignore | 2 ++ bin/tristan.rb | 18 +++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 12439e5..1cf5ddf 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ # Ignore master key for decrypting credentials and more. /config/master.key + +/bin/generated diff --git a/bin/tristan.rb b/bin/tristan.rb index dfe97f5..e35d1f6 100644 --- a/bin/tristan.rb +++ b/bin/tristan.rb @@ -406,16 +406,16 @@ def generate_creature(event:, template:) @redis.set(prompt_id, prompt) puts "Piping out to Python..." - system("python3 generate-image-from-prompt.py #{prompt_id} #{event.interaction.user.username + '-' + Time.now.to_i.to_s + '.png'}") + system("python3 generate-image-from-prompt.py #{prompt_id} #{prompt_id + '.png'}") puts "Back from Python..." - if File.exists("generated/#{event.interaction.user.username + '-' + Time.now.to_i.to_s + '.png'}") + if File.exist?("generated/#{prompt_id + '.png'}") event.send_file( - File.open("generated/#{event.interaction.user.username + '-' + Time.now.to_i.to_s + '.png'}", 'r'), + File.open("generated/#{prompt_id + '.png'}", 'r'), caption: "Creature image" ) else - puts "No file found!" + puts "No file found at generated/#{prompt_id + '.png'}" end end @@ -488,12 +488,12 @@ def show_creature_template_menu(event) ] event.respond(content: creature_generation_introduction.join("\n"), ephemeral: true) do |_, view| view.row do |r| - r.select_menu(custom_id: 'generate_creature', placeholder: 'Build your creature template', min_values: 1, max_values: 25) do |s| - # s.option(label: 'Name', value: 'name') - # s.option(label: 'Description', value: 'description') + r.select_menu(custom_id: 'generate_creature', placeholder: 'Build your creature template', min_values: 1, max_values: 5) do |s| + s.option(label: 'Name', value: 'name') + s.option(label: 'Description', value: 'description') s.option(label: 'Image', value: 'image') - # s.option(label: 'Biome', value: 'biome') - # s.option(label: 'Taxonomy', value: 'taxonomy') + s.option(label: 'Biome', value: 'biome') + s.option(label: 'Taxonomy', value: 'taxonomy') end end end From 3062364e2d563f665ace324ff9fa889fe7f74a67 Mon Sep 17 00:00:00 2001 From: drusepth Date: Tue, 17 Jan 2023 15:31:01 -0800 Subject: [PATCH 04/11] gpt take the wheel --- bin/tristan.rb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/bin/tristan.rb b/bin/tristan.rb index e35d1f6..ea28da4 100644 --- a/bin/tristan.rb +++ b/bin/tristan.rb @@ -410,16 +410,25 @@ def generate_creature(event:, template:) puts "Back from Python..." if File.exist?("generated/#{prompt_id + '.png'}") - event.send_file( - File.open("generated/#{prompt_id + '.png'}", 'r'), - caption: "Creature image" - ) + # event.send_file( + # File.open("generated/#{prompt_id + '.png'}", 'r'), + # caption: "Creature image" + # ) + puts "Image generated!" else puts "No file found at generated/#{prompt_id + '.png'}" end end - event.respond(content: template_prelude + creature_template.map { |key, value| "**#{key.to_s.gsub('_', ' ').capitalize}**: #{value}" }.join("\n")) do |_, view| + event.respond( + content: template_prelude + creature_template.map { |key, value| "**#{key.to_s.gsub('_', ' ').capitalize}**: #{value}" }.join("\n"), + attachments: [ + Discordrb::Webhooks::Attachment.new( + File.open("generated/#{prompt_id + '.png'}", 'r'), + 'creature.png' + ) + ] + ) do |_, view| view.row do |r| r.button(label: 'Generate another creature with this template', style: :success, custom_id: 'reroll_character:' + template_id) r.button(label: 'Use a new template', style: :secondary, custom_id: 'creature_template_builder') From 0f8e94f5b940c2e1f00d2641d435c2bd9aa58a15 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Tue, 17 Jan 2023 15:38:39 -0800 Subject: [PATCH 05/11] small fix --- bin/tristan.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/tristan.rb b/bin/tristan.rb index ea28da4..f17bf9e 100644 --- a/bin/tristan.rb +++ b/bin/tristan.rb @@ -423,14 +423,15 @@ def generate_creature(event:, template:) event.respond( content: template_prelude + creature_template.map { |key, value| "**#{key.to_s.gsub('_', ' ').capitalize}**: #{value}" }.join("\n"), attachments: [ - Discordrb::Webhooks::Attachment.new( + Discordrb::Attachment.new( File.open("generated/#{prompt_id + '.png'}", 'r'), - 'creature.png' + 'creature.png', + bot ) ] ) do |_, view| view.row do |r| - r.button(label: 'Generate another creature with this template', style: :success, custom_id: 'reroll_character:' + template_id) + r.button(label: 'Generate another creature with this template', style: :success, custom_id: 'reroll_creature:' + template_id) r.button(label: 'Use a new template', style: :secondary, custom_id: 'creature_template_builder') end end From 5689b672a7e3bc01e0a37e3b2c69b09839e5edea Mon Sep 17 00:00:00 2001 From: drusepth Date: Tue, 17 Jan 2023 15:39:47 -0800 Subject: [PATCH 06/11] try this --- bin/tristan.rb | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/bin/tristan.rb b/bin/tristan.rb index f17bf9e..1ae0427 100644 --- a/bin/tristan.rb +++ b/bin/tristan.rb @@ -409,26 +409,23 @@ def generate_creature(event:, template:) system("python3 generate-image-from-prompt.py #{prompt_id} #{prompt_id + '.png'}") puts "Back from Python..." + if File.exist?("generated/#{prompt_id + '.png'}") - # event.send_file( - # File.open("generated/#{prompt_id + '.png'}", 'r'), - # caption: "Creature image" - # ) - puts "Image generated!" + puts "Image generated at generated/#{prompt_id + '.png'}" else puts "No file found at generated/#{prompt_id + '.png'}" end + + attachment = Discordrb::Attachment.new( + File.open("generated/#{prompt_id + '.png'}", 'r'), + 'creature.png', + File.extname("generated/#{prompt_id + '.png'}") + ) end event.respond( content: template_prelude + creature_template.map { |key, value| "**#{key.to_s.gsub('_', ' ').capitalize}**: #{value}" }.join("\n"), - attachments: [ - Discordrb::Attachment.new( - File.open("generated/#{prompt_id + '.png'}", 'r'), - 'creature.png', - bot - ) - ] + attachments: [attachment] ) do |_, view| view.row do |r| r.button(label: 'Generate another creature with this template', style: :success, custom_id: 'reroll_creature:' + template_id) From fdeafe557eae7baafb41b790a487d214331692cb Mon Sep 17 00:00:00 2001 From: drusepth Date: Tue, 17 Jan 2023 15:41:18 -0800 Subject: [PATCH 07/11] we'll do it live --- bin/tristan.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/tristan.rb b/bin/tristan.rb index 1ae0427..3431ab5 100644 --- a/bin/tristan.rb +++ b/bin/tristan.rb @@ -416,6 +416,9 @@ def generate_creature(event:, template:) puts "No file found at generated/#{prompt_id + '.png'}" end + require 'pry' + binding.pry + attachment = Discordrb::Attachment.new( File.open("generated/#{prompt_id + '.png'}", 'r'), 'creature.png', From cfc8e22d6fd0956a7e0746c78692ebcc8a6bfb02 Mon Sep 17 00:00:00 2001 From: drusepth Date: Tue, 17 Jan 2023 16:47:25 -0800 Subject: [PATCH 08/11] ok this will be fine for now --- bin/generate-image-from-prompt.py | 3 +-- bin/tristan.rb | 12 ++---------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/bin/generate-image-from-prompt.py b/bin/generate-image-from-prompt.py index 7e7b5ec..ef41fbf 100644 --- a/bin/generate-image-from-prompt.py +++ b/bin/generate-image-from-prompt.py @@ -6,7 +6,6 @@ print("In Pythonland") parser = argparse.ArgumentParser() parser.add_argument("prompt_id", type=str, help="The id of the prompt to retrieve.") -parser.add_argument("output_name", type=str, help="The name of the output file.") args = parser.parse_args() # Read prompt from Redis @@ -24,4 +23,4 @@ pipe = pipe.to("cuda") image = pipe(prompt).images[0] -image.save("generated/" + args.output_name) +image.save("generated/" + args.prompt_id + '.png') diff --git a/bin/tristan.rb b/bin/tristan.rb index 3431ab5..c4a4f01 100644 --- a/bin/tristan.rb +++ b/bin/tristan.rb @@ -406,24 +406,16 @@ def generate_creature(event:, template:) @redis.set(prompt_id, prompt) puts "Piping out to Python..." - system("python3 generate-image-from-prompt.py #{prompt_id} #{prompt_id + '.png'}") + system("python3 generate-image-from-prompt.py #{prompt_id}") puts "Back from Python..." if File.exist?("generated/#{prompt_id + '.png'}") puts "Image generated at generated/#{prompt_id + '.png'}" + event.bot.send_file(event.channel, File.open("generated/#{prompt_id}.png", 'r')) else puts "No file found at generated/#{prompt_id + '.png'}" end - - require 'pry' - binding.pry - - attachment = Discordrb::Attachment.new( - File.open("generated/#{prompt_id + '.png'}", 'r'), - 'creature.png', - File.extname("generated/#{prompt_id + '.png'}") - ) end event.respond( From 0825d9c10abdfd4c166fb8e89414d62193dac548 Mon Sep 17 00:00:00 2001 From: drusepth Date: Tue, 17 Jan 2023 16:49:41 -0800 Subject: [PATCH 09/11] cleanup --- bin/tristan.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bin/tristan.rb b/bin/tristan.rb index c4a4f01..b6a5c4e 100644 --- a/bin/tristan.rb +++ b/bin/tristan.rb @@ -418,10 +418,7 @@ def generate_creature(event:, template:) end end - event.respond( - content: template_prelude + creature_template.map { |key, value| "**#{key.to_s.gsub('_', ' ').capitalize}**: #{value}" }.join("\n"), - attachments: [attachment] - ) do |_, view| + event.respond(content: template_prelude + creature_template.map { |key, value| "**#{key.to_s.gsub('_', ' ').capitalize}**: #{value}" }.join("\n")) do |_, view| view.row do |r| r.button(label: 'Generate another creature with this template', style: :success, custom_id: 'reroll_creature:' + template_id) r.button(label: 'Use a new template', style: :secondary, custom_id: 'creature_template_builder') From d804a62a0f3244319f6429ef0516154a318ab847 Mon Sep 17 00:00:00 2001 From: drusepth Date: Tue, 17 Jan 2023 16:53:33 -0800 Subject: [PATCH 10/11] live debug again --- bin/tristan.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/tristan.rb b/bin/tristan.rb index b6a5c4e..46bd597 100644 --- a/bin/tristan.rb +++ b/bin/tristan.rb @@ -393,13 +393,15 @@ def generate_creature(event:, template:) # discord's custom_id, which only allows 100 characters). @redis.set(template_id, template.join(',')) + message = event.respond("Generating creature for #{event.interaction.user.mention}...") + # Start by sending the creature image first, then the template. if template.include?('image') # So... apparently we need Python for anything HF-related because Ruby doesn't have a library for it. # So we'll just shell out to Python and let it do the work for us -- but we'll generate our prompt # here and set it in Redis so Python can pull it out to do the work. prompt = [ - "A #{Faker::Creature::Animal.name} mixed with a #{Faker::Creature::Animal.name}", + "Photograph of a #{Faker::Creature::Animal.name} mixed with a #{Faker::Creature::Animal.name}", "rare undiscovered species of living in forest, photograph, masterpiece, trending on cgsociety, exotic, realistic rendering, fictional creature, alien, cinematic lighting, volumetric lighting, cinematic, fantasy art, detailed" ].join(', ') prompt_id = 'prompt-' + Time.now.to_i.to_s + '-' + event.interaction.user.username @@ -418,6 +420,9 @@ def generate_creature(event:, template:) end end + require 'pry' + binding.pry + event.respond(content: template_prelude + creature_template.map { |key, value| "**#{key.to_s.gsub('_', ' ').capitalize}**: #{value}" }.join("\n")) do |_, view| view.row do |r| r.button(label: 'Generate another creature with this template', style: :success, custom_id: 'reroll_creature:' + template_id) From ee75120b33fe072763842747a611583db58dc342 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Tue, 17 Jan 2023 17:24:23 -0800 Subject: [PATCH 11/11] fine for now --- bin/tristan.rb | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/bin/tristan.rb b/bin/tristan.rb index 46bd597..f5ae33f 100644 --- a/bin/tristan.rb +++ b/bin/tristan.rb @@ -393,7 +393,12 @@ def generate_creature(event:, template:) # discord's custom_id, which only allows 100 characters). @redis.set(template_id, template.join(',')) - message = event.respond("Generating creature for #{event.interaction.user.mention}...") + event.respond(content: template_prelude + creature_template.map { |key, value| "**#{key.to_s.gsub('_', ' ').capitalize}**: #{value}" }.join("\n")) do |_, view| + view.row do |r| + r.button(label: 'Generate another creature with this template', style: :success, custom_id: 'reroll_creature:' + template_id) + r.button(label: 'Use a new template', style: :secondary, custom_id: 'creature_template_builder') + end + end # Start by sending the creature image first, then the template. if template.include?('image') @@ -420,16 +425,6 @@ def generate_creature(event:, template:) end end - require 'pry' - binding.pry - - event.respond(content: template_prelude + creature_template.map { |key, value| "**#{key.to_s.gsub('_', ' ').capitalize}**: #{value}" }.join("\n")) do |_, view| - view.row do |r| - r.button(label: 'Generate another creature with this template', style: :success, custom_id: 'reroll_creature:' + template_id) - r.button(label: 'Use a new template', style: :secondary, custom_id: 'creature_template_builder') - end - end - # After sending the image, we should clean it up and delete our local copy so we don't fill up the server's disk. # sleep(5) # File.delete("pic.png")