From 94e16b53fdce4446a0c5d8e9ce330b6c8523c84d Mon Sep 17 00:00:00 2001 From: OmarMWarraich Date: Mon, 1 Jul 2024 22:27:59 +0500 Subject: [PATCH 1/2] feat: Sidekiq ImgProgressJob --- Gemfile | 2 ++ Gemfile.lock | 6 ++++++ app/jobs/img_progress_job.rb | 27 +++++++++++++++++++++++++++ app/jobs/sd_render_job.rb | 7 +++++++ config/application.rb | 1 + config/cable.yml | 2 +- test/jobs/img_progress_job_test.rb | 7 +++++++ 7 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 app/jobs/img_progress_job.rb create mode 100644 test/jobs/img_progress_job_test.rb diff --git a/Gemfile b/Gemfile index a965761..bac0e5b 100644 --- a/Gemfile +++ b/Gemfile @@ -73,3 +73,5 @@ gem "sassc-rails", "~> 2.1" gem 'font-awesome-sass', '~> 5.15.1' gem 'ruby-stableDiffusion', path: '/home/owa/Docs/ror/ruby-stablediffusion/' + +gem "sidekiq" diff --git a/Gemfile.lock b/Gemfile.lock index 090662e..9a8db72 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -254,6 +254,11 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) + sidekiq (7.2.4) + concurrent-ruby (< 2) + connection_pool (>= 2.3.0) + rack (>= 2.2.4) + redis-client (>= 0.19.0) sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) @@ -315,6 +320,7 @@ DEPENDENCIES ruby-stableDiffusion! sassc-rails (~> 2.1) selenium-webdriver + sidekiq sprockets-rails stimulus-rails turbo-rails diff --git a/app/jobs/img_progress_job.rb b/app/jobs/img_progress_job.rb new file mode 100644 index 0000000..aeeec43 --- /dev/null +++ b/app/jobs/img_progress_job.rb @@ -0,0 +1,27 @@ +class ImgProgressJob < ApplicationJob + queue_as :default + + def perform(task_id, user_id, original_prompt, style_template) + payload = { + "id_task": task_id, + "id_live_preview": 1 + } + + config = RStableDiffusionAI::Configuration.new + config.host = ENV['SD_API_HOST'] + config.scheme = ENV['SD_API_SCHEME'] + config.debugging = true + + client = RStableDiffusionAI::ApiClient.new(config) + + api_instance = RStableDiffusionAI::DefaultApi.new(client) + + loop do + sleep 5 + result = api_instance.progressapi_internal_progress_post(payload) + + Rails.logger.debug "Progress: #{result}" + break if result.completed == true + end + end +end diff --git a/app/jobs/sd_render_job.rb b/app/jobs/sd_render_job.rb index 168142f..f3c4dec 100644 --- a/app/jobs/sd_render_job.rb +++ b/app/jobs/sd_render_job.rb @@ -14,6 +14,13 @@ def perform(render_settings, user_id) api_instance = RStableDiffusionAI::DefaultApi.new(client) + our_task_id = "task(#{rand(36**5...36**6).to_s(36)}#{rand(36**5...36**6).to_s(36)}#{rand(36**5...36**6).to_s(36)})" + + render_settings[:task_id] = our_task_id + render_settings[:id_task] = our_task_id + + ImgProgressJob.perform_later(our_task_id, user_id, original_prompt, style_template) + result = api_instance.text2imgapi_sdapi_v1_txt2img_post(render_settings) end diff --git a/config/application.rb b/config/application.rb index 770e623..e987003 100644 --- a/config/application.rb +++ b/config/application.rb @@ -23,5 +23,6 @@ class Application < Rails::Application # # config.time_zone = "Central Time (US & Canada)" # config.eager_load_paths << Rails.root.join("extras") + config.active_job.queue_adapter = :sidekiq end end diff --git a/config/cable.yml b/config/cable.yml index 9d1d69c..4345539 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,6 +1,6 @@ development: adapter: redis - url: redis://localhost:6379/1 + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> test: adapter: test diff --git a/test/jobs/img_progress_job_test.rb b/test/jobs/img_progress_job_test.rb new file mode 100644 index 0000000..171cec3 --- /dev/null +++ b/test/jobs/img_progress_job_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ImgProgressJobTest < ActiveJob::TestCase + # test "the truth" do + # assert true + # end +end From 1743307fc867867a65ac89be055bd7824c406aa2 Mon Sep 17 00:00:00 2001 From: OmarMWarraich Date: Tue, 2 Jul 2024 02:17:44 +0500 Subject: [PATCH 2/2] feat: Progress Holder, TurboStream, Loading, Preview and Image Generation --- Gemfile | 2 + Gemfile.lock | 11 ++++++ app/controllers/txt2_imgs_controller.rb | 8 +++- app/jobs/img_progress_job.rb | 8 ++++ app/models/progress_holder.rb | 38 +++++++++++++++++++ app/models/user.rb | 10 +++++ .../txt2_imgs/_loading_progress.html.erb | 22 +++++++++++ .../txt2_imgs/_process_starting.html.erb | 3 ++ app/views/txt2_imgs/index.html.erb | 2 +- .../20240701172911_create_progress_holders.rb | 12 ++++++ db/schema.rb | 13 ++++++- test/fixtures/progress_holders.yml | 11 ++++++ test/models/progress_holder_test.rb | 18 +++++++++ test/models/user_test.rb | 10 +++++ 14 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 app/models/progress_holder.rb create mode 100644 app/views/txt2_imgs/_loading_progress.html.erb create mode 100644 app/views/txt2_imgs/_process_starting.html.erb create mode 100644 db/migrate/20240701172911_create_progress_holders.rb create mode 100644 test/fixtures/progress_holders.yml create mode 100644 test/models/progress_holder_test.rb diff --git a/Gemfile b/Gemfile index bac0e5b..bb8d2ef 100644 --- a/Gemfile +++ b/Gemfile @@ -58,6 +58,8 @@ group :development do # Speed up commands on slow machines / big apps [https://github.com/rails/spring] # gem "spring" + gem "annotate" + gem "letter_opener" end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 9a8db72..ee64089 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -84,6 +84,9 @@ GEM tzinfo (~> 2.0) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) + annotate (3.2.0) + activerecord (>= 3.2, < 8.0) + rake (>= 10.4, < 14.0) autoprefixer-rails (10.4.16.0) execjs (~> 2) base64 (0.2.0) @@ -105,6 +108,7 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) + childprocess (5.0.0) concurrent-ruby (1.3.3) connection_pool (2.4.1) crass (1.0.6) @@ -145,6 +149,11 @@ GEM actionview (>= 5.0.0) activesupport (>= 5.0.0) json (2.7.2) + launchy (3.0.1) + addressable (~> 2.8) + childprocess (~> 5.0) + letter_opener (1.10.0) + launchy (>= 2.2, < 4) logger (1.6.0) loofah (2.22.0) crass (~> 1.0.2) @@ -304,6 +313,7 @@ PLATFORMS x86_64-linux DEPENDENCIES + annotate bcrypt (~> 3.1.7) bootsnap bootstrap (~> 5.3) @@ -313,6 +323,7 @@ DEPENDENCIES font-awesome-sass (~> 5.15.1) importmap-rails jbuilder + letter_opener pg (~> 1.1) puma (>= 5.0) rails (~> 7.1.3, >= 7.1.3.4) diff --git a/app/controllers/txt2_imgs_controller.rb b/app/controllers/txt2_imgs_controller.rb index 695b3fd..7510911 100644 --- a/app/controllers/txt2_imgs_controller.rb +++ b/app/controllers/txt2_imgs_controller.rb @@ -53,10 +53,14 @@ def create respond_to do |format| format.turbo_stream do render turbo_stream: turbo_stream.replace( + 'process_starting', + partial: '/txt2_imgs/process_starting' + ) + + turbo_stream.replace( 'image_maker', - partial: 'txt2_imgs/image_maker', + partial: '/txt2_imgs/image_maker', locals: { - render_result: render_result + render_result: render_result, } ) end diff --git a/app/jobs/img_progress_job.rb b/app/jobs/img_progress_job.rb index aeeec43..54cca03 100644 --- a/app/jobs/img_progress_job.rb +++ b/app/jobs/img_progress_job.rb @@ -16,12 +16,20 @@ def perform(task_id, user_id, original_prompt, style_template) api_instance = RStableDiffusionAI::DefaultApi.new(client) + start_time = Time.now + loop do sleep 5 result = api_instance.progressapi_internal_progress_post(payload) Rails.logger.debug "Progress: #{result}" break if result.completed == true + + Rails.logger.debug "Time.now - start_time: #{Time.now - start_time}" + + break if Time.now - start_time > 240 + + ProgressHolder.new.broadcast_updated(user_id, task_id, original_prompt, style_template, result) end end end diff --git a/app/models/progress_holder.rb b/app/models/progress_holder.rb new file mode 100644 index 0000000..910348f --- /dev/null +++ b/app/models/progress_holder.rb @@ -0,0 +1,38 @@ +# == Schema Information +# +# Table name: progress_holders +# +# id :bigint not null, primary key +# task_ref :string +# live_preview_id :integer +# user_id :bigint not null +# created_at :datetime not null +# updated_at :datetime not null +# +class ProgressHolder < ApplicationRecord + include ActionView::RecordIdentifier + belongs_to :user + + def broadcast_updated(user_id, task_ref, original_prompt, style_template, result) + progress_holder = ProgressHolder.find_or_create_by(task_ref:) do |ph| + ph.user_id = user_id + ph.live_preview_id = result.progress.positive? ? result.id_live_preview : -1 + end + + user = User.find(user_id) + + # Broadcast the updated progress to the user + broadcast_update_to( + "#{dom_id(user)}_main_image", + partial: "txt2_imgs/loading_progress", + locals: { + scroll_to: true, + original_prompt:, + style_template:, + result: JSON.parse(result.to_json) + }, + target: "image_maker" + ) + + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 74810d1..55512d6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,13 @@ +# == Schema Information +# +# Table name: users +# +# id :bigint not null, primary key +# email :string +# password_digest :string +# created_at :datetime not null +# updated_at :datetime not null +# class User < ApplicationRecord has_secure_password validates :email, presence: true, uniqueness: true diff --git a/app/views/txt2_imgs/_loading_progress.html.erb b/app/views/txt2_imgs/_loading_progress.html.erb new file mode 100644 index 0000000..7fc8114 --- /dev/null +++ b/app/views/txt2_imgs/_loading_progress.html.erb @@ -0,0 +1,22 @@ + +
+
+ Loading... +
+
+
+ <% progress = result['progress'].present? ? (result['progress'].to_f * 100) : 0 %> +
+
+
+
+
+

ETA: <%= result['eta'].to_f %> seconds

+
+
+ <% if result['live_preview'].present? && !result['completed'] != 'true' %> + <%= image_tag "#{result['live_preview']}", alt: "#{original_prompt}", class: 'img-fluid thumbnail' %> + <% end %> +
+
+
diff --git a/app/views/txt2_imgs/_process_starting.html.erb b/app/views/txt2_imgs/_process_starting.html.erb new file mode 100644 index 0000000..10190f9 --- /dev/null +++ b/app/views/txt2_imgs/_process_starting.html.erb @@ -0,0 +1,3 @@ + + We will make your image in a moment. Please wait... + \ No newline at end of file diff --git a/app/views/txt2_imgs/index.html.erb b/app/views/txt2_imgs/index.html.erb index e43038f..c247554 100644 --- a/app/views/txt2_imgs/index.html.erb +++ b/app/views/txt2_imgs/index.html.erb @@ -7,7 +7,7 @@
- <%# turbo_stream_from "#{dom_id(current_user)}_main_image" %> + <%= turbo_stream_from "#{dom_id(current_user)}_main_image" %> This will be replaced by the image maker diff --git a/db/migrate/20240701172911_create_progress_holders.rb b/db/migrate/20240701172911_create_progress_holders.rb new file mode 100644 index 0000000..0324f0d --- /dev/null +++ b/db/migrate/20240701172911_create_progress_holders.rb @@ -0,0 +1,12 @@ +class CreateProgressHolders < ActiveRecord::Migration[7.1] + def change + create_table :progress_holders do |t| + t.string :task_ref + t.integer :live_preview_id + t.references :user, null: false, foreign_key: true + + t.timestamps + end + add_index :progress_holders, :task_ref, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 5ec56b1..476e0a5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,10 +10,20 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_06_22_103323) do +ActiveRecord::Schema[7.1].define(version: 2024_07_01_172911) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "progress_holders", force: :cascade do |t| + t.string "task_ref" + t.integer "live_preview_id" + t.bigint "user_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["task_ref"], name: "index_progress_holders_on_task_ref", unique: true + t.index ["user_id"], name: "index_progress_holders_on_user_id" + end + create_table "users", force: :cascade do |t| t.string "email" t.string "password_digest" @@ -21,4 +31,5 @@ t.datetime "updated_at", null: false end + add_foreign_key "progress_holders", "users" end diff --git a/test/fixtures/progress_holders.yml b/test/fixtures/progress_holders.yml new file mode 100644 index 0000000..1b246da --- /dev/null +++ b/test/fixtures/progress_holders.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + task_ref: MyString + live_preview_id: 1 + user: one + +two: + task_ref: MyString + live_preview_id: 1 + user: two diff --git a/test/models/progress_holder_test.rb b/test/models/progress_holder_test.rb new file mode 100644 index 0000000..6c71f8a --- /dev/null +++ b/test/models/progress_holder_test.rb @@ -0,0 +1,18 @@ +# == Schema Information +# +# Table name: progress_holders +# +# id :bigint not null, primary key +# task_ref :string +# live_preview_id :integer +# user_id :bigint not null +# created_at :datetime not null +# updated_at :datetime not null +# +require "test_helper" + +class ProgressHolderTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb index 5c07f49..cfba810 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -1,3 +1,13 @@ +# == Schema Information +# +# Table name: users +# +# id :bigint not null, primary key +# email :string +# password_digest :string +# created_at :datetime not null +# updated_at :datetime not null +# require "test_helper" class UserTest < ActiveSupport::TestCase