Merge branch 'master' into tailwind-redesign

This commit is contained in:
Andrew Brown 2023-04-18 17:36:49 -07:00
commit f94bfbce7e
11 changed files with 210 additions and 145 deletions

View File

@ -124,7 +124,7 @@ GEM
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
acts_as_list (1.0.4)
acts_as_list (1.1.0)
activerecord (>= 4.2)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
@ -133,7 +133,7 @@ GEM
autoprefixer-rails (10.4.7.0)
execjs (~> 2)
aws-eventstream (1.2.0)
aws-partitions (1.619.0)
aws-partitions (1.746.0)
aws-sdk (3.1.0)
aws-sdk-resources (~> 3)
aws-sdk-accessanalyzer (1.23.0)
@ -331,10 +331,10 @@ GEM
aws-sdk-connectparticipant (1.14.0)
aws-sdk-core (~> 3, >= 3.120.0)
aws-sigv4 (~> 1.1)
aws-sdk-core (3.132.0)
aws-sdk-core (3.171.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-costandusagereportservice (1.34.0)
aws-sdk-core (~> 3, >= 3.120.0)
@ -594,8 +594,8 @@ GEM
aws-sdk-kinesisvideosignalingchannels (1.13.0)
aws-sdk-core (~> 3, >= 3.120.0)
aws-sigv4 (~> 1.1)
aws-sdk-kms (1.58.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (1.63.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-lakeformation (1.17.0)
aws-sdk-core (~> 3, >= 3.120.0)
@ -1102,8 +1102,8 @@ GEM
aws-sdk-route53resolver (1.30.0)
aws-sdk-core (~> 3, >= 3.120.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-s3 (1.120.1)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sdk-s3control (1.40.0)
@ -1260,7 +1260,7 @@ GEM
aws-sdk-core (~> 3, >= 3.120.0)
aws-sigv4 (~> 1.1)
aws-sigv2 (1.1.0)
aws-sigv4 (1.5.1)
aws-sigv4 (1.5.2)
aws-eventstream (~> 1, >= 1.0.2)
babel-source (5.8.35)
babel-transpiler (0.7.0)
@ -1293,15 +1293,15 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.12.2)
concurrent-ruby (1.2.0)
concurrent-ruby (1.2.2)
connection_pool (2.3.0)
crass (1.0.6)
csv (3.2.5)
csv (3.2.6)
d3-rails (5.9.2)
railties (>= 3.1)
database_cleaner (2.0.1)
database_cleaner-active_record (~> 2.0.0)
database_cleaner-active_record (2.0.1)
database_cleaner (2.0.2)
database_cleaner-active_record (>= 2, < 3)
database_cleaner-active_record (2.1.0)
activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
@ -1328,7 +1328,7 @@ GEM
docile (1.1.5)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
engtagger (0.3.2)
engtagger (0.4.0)
lru_redux
erubi (1.12.0)
event_emitter (0.2.6)
@ -1408,7 +1408,7 @@ GEM
inline_svg (1.8.0)
activesupport (>= 3.0)
nokogiri (>= 1.6)
jmespath (1.6.1)
jmespath (1.6.2)
json (2.5.1)
jwt (2.2.3)
kaminari (1.2.2)
@ -1459,7 +1459,7 @@ GEM
mini_portile2 (2.8.1)
mini_racer (0.6.3)
libv8-node (~> 16.10.0.0)
minitest (5.17.0)
minitest (5.18.0)
multi_json (1.15.0)
multipart-post (2.3.0)
mustache (1.1.1)
@ -1474,12 +1474,12 @@ GEM
net-smtp (0.3.3)
net-protocol
netrc (0.11.0)
newrelic_rpm (8.16.0)
newrelic_rpm (9.2.0)
nio4r (2.5.8)
nokogiri (1.14.2)
nokogiri (1.14.3)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nokogiri (1.14.2-x86_64-linux)
nokogiri (1.14.3-x86_64-linux)
racc (~> 1.4)
opus-ruby (1.0.1)
ffi
@ -1512,8 +1512,8 @@ GEM
pundit (2.3.0)
activesupport (>= 3.0.0)
racc (1.6.2)
rack (2.2.6.2)
rack-mini-profiler (3.0.0)
rack (2.2.6.4)
rack-mini-profiler (3.1.0)
rack (>= 1.2.0)
rack-proxy (0.7.6)
rack
@ -1579,7 +1579,7 @@ GEM
netrc (~> 0.8)
rexml (3.2.5)
rinku (2.0.6)
rmagick (5.1.0)
rmagick (5.2.0)
pkg-config (~> 1.4)
ruby-vips (2.1.4)
ffi (~> 1.12)
@ -1627,12 +1627,12 @@ GEM
sqlite3 (1.6.0)
mini_portile2 (~> 2.8.0)
sqlite3 (1.6.0-x86_64-linux)
stackprof (0.2.21)
stackprof (0.2.25)
statsd-ruby (1.5.0)
stripe (5.55.0)
stripe_event (2.3.2)
stripe_event (2.7.0)
activesupport (>= 3.1)
stripe (>= 2.8, < 6)
stripe (>= 2.8, < 9)
terrapin (0.6.0)
climate_control (>= 0.0.3, < 1.0)
terser (1.1.13)

View File

@ -14,8 +14,10 @@ class BasilController < ApplicationController
return raise "Invalid content type: #{params[:content_type]}"
end
@content = @current_user_content[@content_type].sort_by(&:name)
@content = @current_user_content.fetch(@content_type, []).sort_by(&:name)
end
@generated_images_count = current_user.basil_commissions.with_deleted.count
end
def content
@ -199,45 +201,23 @@ class BasilController < ApplicationController
.limit(10)
.includes(:basil_feedbacks, :image_blob)
@in_progress_commissions = @commissions.select { |c| c.completed_at.nil? }
@can_request_another = @in_progress_commissions.count < 3
end
@generated_images_count = current_user.basil_commissions.with_deleted.count
def character
@character = current_user.characters.find(params[:id])
@guidance = BasilFieldGuidance.find_or_initialize_by(entity: @character, user: current_user).try(:guidance)
@guidance ||= {}
category_ids = AttributeCategory.where(
user_id: current_user.id,
entity_type: 'character',
label: ['Looks', 'Appearance']
).pluck(:id)
@appearance_fields = AttributeField.where(attribute_category_id: category_ids)
@attributes = Attribute.where(
attribute_field_id: @appearance_fields.pluck(:id),
entity_id: @character.id,
entity_type: 'Character'
)
@commissions = BasilCommission.where(entity_type: 'Character', entity_id: @character.id)
.order('id DESC')
.limit(20)
.includes(:basil_feedbacks)
@in_progress_commissions = BasilCommission.where(entity_type: 'Character', entity_id: @character.id, completed_at: nil)
@can_request_another = @in_progress_commissions.count < 3
@can_request_another = current_user.on_premium_plan? || @generated_images_count < BasilService::FREE_IMAGE_LIMIT
@can_request_another = @can_request_another && @in_progress_commissions.count < BasilService::MAX_JOB_QUEUE_SIZE
end
def about
end
def stats
@commissions = BasilCommission.all
@commissions = BasilCommission.all.with_deleted
@queued = BasilCommission.where(completed_at: nil)
@completed = BasilCommission.where.not(completed_at: nil)
@completed = BasilCommission.where.not(completed_at: nil).with_deleted
@average_wait_time = @completed.where('completed_at > ?', 24.hours.ago)
.average(:cached_seconds_taken)
.average(:cached_seconds_taken) || 0
@seconds_over_time = @completed.where('completed_at > ?', 24.hours.ago)
.group_by { |c| ((c.cached_seconds_taken || 0) / 60).round }
.map { |minutes, list| [minutes, list.count] }
@ -295,14 +275,16 @@ class BasilController < ApplicationController
'painting2', 'painting3', 'anime'
].flatten.compact.uniq
@total_score_per_style = BasilCommission.where(style: active_styles)
.joins(:basil_feedbacks)
.group(:style)
.sum(:score_adjustment)
.map { |style, average| [style, average.round(1)] }
.sort_by(&:second)
.reverse
@average_score_per_style = BasilCommission.where(style: active_styles)
@total_score_per_style = BasilCommission.with_deleted
.where(style: active_styles)
.joins(:basil_feedbacks)
.group(:style)
.sum(:score_adjustment)
.map { |style, average| [style, average.round(1)] }
.sort_by(&:second)
.reverse
@average_score_per_style = BasilCommission.with_deleted
.where(style: active_styles)
.joins(:basil_feedbacks)
.group(:style)
.average(:score_adjustment)
@ -310,7 +292,8 @@ class BasilController < ApplicationController
.sort_by(&:second)
.reverse
@average_score_per_page_type = BasilCommission.where.not(completed_at: nil)
@average_score_per_page_type = BasilCommission.with_deleted
.where.not(completed_at: nil)
.joins(:basil_feedbacks)
.group(:entity_type)
.average(:score_adjustment)
@ -404,14 +387,31 @@ class BasilController < ApplicationController
def review
@recent_commissions = BasilCommission.all.includes(:entity, :user).order('id DESC').limit(100)
@commissions_per_user_id = BasilCommission.with_deleted.where('created_at > ?', 48.hours.ago).group(:user_id).order('count_all DESC').limit(5).count
@unique_users_generating_count = BasilCommission.with_deleted.where('created_at > ?', 48.hours.ago).group(:user_id).count
@current_queue_items = BasilCommission.where(completed_at: nil).order('created_at ASC')
end
def commission
@generated_images_count = current_user.basil_commissions.with_deleted.count
if !current_user.on_premium_plan? && @generated_images_count > BasilService::FREE_IMAGE_LIMIT
redirect_back fallback_location: basil_path, notice: "You've reached your free image limit. Please upgrade to generate more images."
return
end
# Fetch the related content
@content = @current_user_content[commission_params.fetch(:entity_type)]
.find { |c| c.id == commission_params.fetch(:entity_id).to_i }
return raise "Invalid content commission params" if @content.nil?
current_queue_size = current_user.basil_commissions.where(completed_at: nil).where(entity: @content).count
if current_queue_size >= BasilService::MAX_JOB_QUEUE_SIZE
redirect_back fallback_location: basil_path, notice: "You can only have #{BasilService::MAX_JOB_QUEUE_SIZE} commissions per page in progress at a time. Please wait for one to complete before requesting another."
return
end
# Before creating the prompt, do a little config to tweak things to work well :)
labels_to_omit_label_text = [
"Name",

View File

@ -1,4 +1,6 @@
class BasilCommission < ApplicationRecord
acts_as_paranoid
belongs_to :user
belongs_to :entity, polymorphic: true

View File

@ -1,4 +1,7 @@
class BasilService < Service
FREE_IMAGE_LIMIT = 100
MAX_JOB_QUEUE_SIZE = 3
IGNORED_VALUES = ['', 'none', 'n/a', '.', '-', ' ', '?', '??', '???', 'x', nil]
ENABLED_PAGE_TYPES = [

View File

@ -110,9 +110,7 @@ function commission_basil(style) {
</div>
<% end %>
</div>
<% end %>
<% if @can_request_another && @relevant_fields.any? %>
<% if BasilService.experimental_styles_for(@content.page_type).any? %>
<div class="row" style="padding-left: 0.5rem">
<div class="grey-text center"><strong>Experimental styles</strong></div>
@ -130,7 +128,26 @@ function commission_basil(style) {
<% end %>
<% end %>
<% if !@can_request_another %>
<% unless current_user.on_premium_plan? %>
<div class="orange lighten-2 card-panel">
<strong>
Image generation is a Premium-only feature, but free accounts can still generate up
to <%= pluralize BasilService::FREE_IMAGE_LIMIT, 'image' %> for free.
</strong>
<br /><br />
You have generated <%= pluralize @generated_images_count, 'image' %>
and have <%= pluralize [0, BasilService::FREE_IMAGE_LIMIT - @generated_images_count].max, 'free image' %> remaining:
<div class="progress white">
<div class="determinate blue" style="width: <%= [@generated_images_count, BasilService::FREE_IMAGE_LIMIT].min %>%"></div>
</div>
<% if @generated_images_count >= BasilService::FREE_IMAGE_LIMIT %>
<%= link_to 'Click here to manage your billing plan', subscription_path, class: 'blue-text text-darken-4' %>
<% end %>
</div>
<% end %>
<% if !@can_request_another && @in_progress_commissions.any? %>
<div class="card-panel purple white-text">
Basil is working on your <%= pluralize @in_progress_commissions.count, 'requested commission' %>.
<br /><br />
@ -138,14 +155,6 @@ function commission_basil(style) {
</div>
<% end %>
<!--
<% if @commissions.any? %>
<div class="card-panel">
<strong>Like an image and want to keep it?</strong> Just click <strong>Save</strong> and it'll save to your <%= @content.name %> page next to any normal uploads.
</div>
<% end %>
-->
<% @commissions.each do |commission| %>
<div>
<% if commission.complete? %>

View File

@ -38,6 +38,26 @@
</p>
</div>
<div class="col s12 m8 l9">
<% unless current_user.on_premium_plan? %>
<div class="orange lighten-2 card-panel">
<strong>
Image generation is a Premium-only feature, but free accounts can still generate up
to <%= pluralize BasilService::FREE_IMAGE_LIMIT, 'image' %> for free.
</strong>
<br /><br />
You have generated <%= pluralize @generated_images_count, 'image' %>
and have <%= pluralize [0, BasilService::FREE_IMAGE_LIMIT - @generated_images_count].max, 'free image' %> remaining:
<div class="progress white">
<div class="determinate blue" style="width: <%= [@generated_images_count, BasilService::FREE_IMAGE_LIMIT].min %>%"></div>
</div>
<% if @generated_images_count >= BasilService::FREE_IMAGE_LIMIT %>
<%= link_to 'Click here to manage your billing plan', subscription_path, class: 'blue-text text-darken-4' %>
<% end %>
</div>
<% end %>
<% if @universe_scope %>
<div class="card-panel <%= Universe.color %> white-text">
<i class="material-icons left"><%= Universe.icon %></i>

View File

@ -1,53 +1,84 @@
<% @recent_commissions.each do |commission| %>
<div>
<% if commission.complete? %>
<%# image_tag commission.image, style: 'width: 100%' %>
<%
s3 = Aws::S3::Resource.new(region: "us-east-1")
obj = s3.bucket(commission.s3_bucket).object("job-#{commission.job_id}.png")
%>
<div class="card horizontal">
<div class="card-image">
<%= link_to obj.presigned_url(:get) do %>
<%= image_tag obj.presigned_url(:get) %>
<% end %>
</div>
<div class="card-stacked">
<div class="card-content">
<div>
<%= commission.id %>.
<% if commission.entity.present? %>
<strong><%= link_to commission.entity.name, commission.entity %></strong>
<div class="row">
<div class="col s3">
<br />
<div><strong>Most-active creators over 48h</strong></div>
<ol>
<% @commissions_per_user_id.each do |user_id, count| %>
<%# This is an N+1 query, but we can deal with it later %>
<% user = User.find(user_id.to_i) %>
<li><%= link_to user.display_name, user %>: <%= pluralize count, 'image' %></li>
<% end %>
</ol>
<div>
<%= pluralize @unique_users_generating_count.count, 'unique user' %> over 48h
</div>
<br /><br />
<div><strong>Queue</strong></div>
<ol>
<% @current_queue_items.each do |commission| %>
<li>
<%= commission.entity_type %>-<%= commission.entity_id %> (<%= commission.style %>)
for U-<%= commission.user_id %>
</li>
<% end %>
</ol>
</div>
<div class="col s9">
<% @recent_commissions.each do |commission| %>
<div>
<% if commission.complete? %>
<%# image_tag commission.image, style: 'width: 100%' %>
<%
s3 = Aws::S3::Resource.new(region: "us-east-1")
obj = s3.bucket(commission.s3_bucket).object("job-#{commission.job_id}.png")
%>
<div class="card horizontal">
<div class="card-image">
<%= link_to obj.presigned_url(:get) do %>
<%= image_tag obj.presigned_url(:get) %>
<% end %>
<% if commission.style? %>
<em>(<%= commission.style.humanize %>)</em>
<% end %>
by <%= link_to commission.user.name, commission.user %>
<div style="font-size: 0.5em"><%= commission.job_id %></div>
</div>
<ul>
<li>
Completed <%= time_ago_in_words commission.completed_at %> ago
</li>
<li>
Took <%= distance_of_time_in_words commission.completed_at - commission.created_at %>
</li>
<hr />
<li>
<div>Preprompt:</div>
<%= commission.prompt.inspect %>
</li>
</ul>
<div class="card-stacked">
<div class="card-content">
<div>
<%= commission.id %>.
<% if commission.entity.present? %>
<strong><%= link_to commission.entity.name, commission.entity %></strong>
<% end %>
<% if commission.style? %>
<em>(<%= commission.style.humanize %>)</em>
<% end %>
by <%= link_to commission.user.name, commission.user %>
<div style="font-size: 0.5em"><%= commission.job_id %></div>
</div>
<ul>
<li>
Completed <%= time_ago_in_words commission.completed_at %> ago
</li>
<li>
Took <%= distance_of_time_in_words commission.completed_at - commission.created_at %>
</li>
<hr />
<li>
<div>Preprompt:</div>
<%= commission.prompt.inspect %>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<% else %>
<div class="card-panel green white-text darken-4">
Basil is still working on this commission...
<div style="font-size: 0.8em">
(Requested <%= time_ago_in_words(commission.created_at) %> ago)
</div>
<% else %>
<div class="card-panel green white-text darken-4">
Basil is still working on this commission...
<div style="font-size: 0.8em">
(Requested <%= time_ago_in_words(commission.created_at) %> ago)
</div>
</div>
<% end %>
</div>
<% end %>
</div>
<% end %>
</div>

View File

@ -1,20 +1,18 @@
<% if Date.current <= 'April 15, 2023'.to_date %>
<div class="col s12 m5 l4">
<div class="grey-text uppercase center">
See what's new
</div>
<%= link_to basil_path do %>
<div class="card-panel hoverable purple white-text" style="margin-bottom: 0">
<div class="valign-wrapper">
<i class="material-icons" class="left" style="font-size: 3em; margin-right: 0.3em;">camera</i>
<div>
Bring your notebook pages to life with our new image generator
</div>
<div class="col s12 m5 l4">
<div class="grey-text uppercase center">
See what's new
</div>
<%= link_to basil_path do %>
<div class="card-panel hoverable purple white-text" style="margin-bottom: 0">
<div class="valign-wrapper">
<i class="material-icons" class="left" style="font-size: 3em; margin-right: 0.3em;">camera</i>
<div>
Bring your notebook pages to life with our new image generator
</div>
</div>
<% end %>
<div style="margin-bottom: 2em;">
<%= link_to 'dismiss message', notice_dismissal_dismiss_path(notice_id: 20), class: 'right' %>
</div>
<% end %>
<div style="margin-bottom: 2em;">
<%= link_to 'dismiss message', notice_dismissal_dismiss_path(notice_id: 20), class: 'right' %>
</div>
<% end %>
</div>

View File

@ -25,10 +25,6 @@ Rails.application.routes.draw do
get '/:content_type', to: 'basil#index', as: :basil_content_index
get '/:content_type/:id', to: 'basil#content', as: :basil_content
post '/:content_type/:id', to: 'basil#commission', as: :basil_commission
# URLs to migrate over
# get '/character/:id', to: 'basil#character', as: :basil_character
# post '/character/:id', to: 'basil#commission'
end
end

View File

@ -0,0 +1,5 @@
class AddDeletedAtColumnToBasilCommissions < ActiveRecord::Migration[6.1]
def change
add_column :basil_commissions, :deleted_at, :datetime
end
end

View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2023_03_23_231640) do
ActiveRecord::Schema.define(version: 2023_04_14_183606) do
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
@ -200,6 +200,7 @@ ActiveRecord::Schema.define(version: 2023_03_23_231640) do
t.float "cached_seconds_taken"
t.string "s3_bucket", default: "basil-commissions"
t.datetime "saved_at"
t.datetime "deleted_at"
t.index ["entity_type", "entity_id", "saved_at"], name: "basil_commissions_ees"
t.index ["entity_type", "entity_id", "style"], name: "basil_commissions_ees2"
t.index ["entity_type", "entity_id"], name: "basil_commissions_ee"