Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved active auctions ai scoring #1147

Merged
merged 1 commit into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions app/jobs/active_auctions_ai_sorting_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class ActiveAuctionsAiSortingJob < ApplicationJob
def perform
return unless self.class.needs_to_run?

auctions_list = Auction.active
auctions_list = Auction.active_with_offers_count
ai_response = fetch_ai_response(auctions_list)
process_ai_response(ai_response)
rescue OpenAI::Error => e
Expand Down Expand Up @@ -51,12 +51,24 @@ def chat_parameters(auctions_list)
model: model,
messages: [
{ role: 'system', content: system_message },
{ role: 'user', content: auctions_list.pluck(:id, :domain_name).to_s },
{ role: 'user', content: format(auctions_list) },
{ role: 'user', content: 'Response in JSON format: [{id:, domain_name:, ai_score:}]' }
]
}
end

def format(auctions_list)
auctions_list.map do |a|
sliced = a.attributes.slice('id', 'domain_name')
if a.platform != 'english'
sliced.merge!({ last_offer: 0, offers_count: 0 })
else
sliced.merge!({ last_offer: a.cents, offers_count: a.offers_count })
end
sliced
end.to_json
end

def update_auctions_with_ai_scores(ai_scores)
update_values = ai_scores.map { |score| "WHEN #{score[:id]} THEN #{score[:ai_score]}" }.join(' ')
update_ids = ai_scores.pluck(:id).join(',')
Expand Down
58 changes: 2 additions & 56 deletions app/models/auction.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# rubocop:disable Metrics
class Auction < ApplicationRecord
class Auction < ApplicationRecord # rubocop:disable Metrics
include Presentable
include SqlQueriable
include Searchable
include PgSearch::Model

Expand Down Expand Up @@ -227,58 +227,4 @@ def users_price
def maximum_bids
Money.new(offers.maximum(:cents), Setting.find_by(code: 'auction_currency').retrieve)
end

def self.with_user_offers(user_id)
Auction.from(with_user_offers_query(user_id))
end

def self.with_user_offers_query(user_id)
sql = <<~SQL
(WITH offers_subquery AS (
SELECT *
FROM offers
WHERE user_id = ?
)
SELECT DISTINCT
auctions.*,
offers_subquery.cents AS users_offer_cents,
offers_subquery.id AS users_offer_id,
offers_subquery.uuid AS users_offer_uuid
FROM auctions
LEFT JOIN offers_subquery on auctions.id = offers_subquery.auction_id) AS auctions
SQL

ActiveRecord::Base.sanitize_sql([sql, user_id])
end

def self.with_highest_offers
Auction.from(with_highest_offers_query)
end

def self.with_highest_offers_query
sql = <<~SQL
(WITH offers_subquery AS (
SELECT DISTINCT on (uuid) offers.*
FROM (SELECT auction_id,
max(cents) over (PARTITION BY auction_id) as max_price,
min(created_at) over (PARTITION BY auction_id, cents) as min_time
FROM offers
) AS highest_offers
INNER JOIN offers
ON
offers.cents = highest_offers.max_price AND
offers.created_at = highest_offers.min_time AND
offers.auction_id = highest_offers.auction_id)
SELECT DISTINCT
auctions.*,
offers_subquery.cents AS highest_offer_cents,
offers_subquery.id AS highest_offer_id,
offers_subquery.uuid AS highest_offer_uuid,
(SELECT COUNT(*) FROM offers where offers.auction_id = auctions.id) AS number_of_offers
FROM auctions
LEFT JOIN offers_subquery on auctions.id = offers_subquery.auction_id) AS auctions
SQL

sql
end
end
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# rubocop:disable Metrics
# frozen_string_literal: true

module Auction::Searchable
extend ActiveSupport::Concern

BLIND = '0'.freeze
ENGLISH = '1'.freeze
BLIND = '0'
ENGLISH = '1'

included do
scope :active, -> { where('starts_at <= ? AND ends_at >= ?', Time.now.utc, Time.now.utc) }
Expand Down Expand Up @@ -99,49 +100,5 @@ def search(params = {}, current_user = nil)
query.order("#{is_from_admin ? sort_admin_column : sort_column} #{sort_direction} NULLS LAST")
end
end

def with_max_offer_cents_for_english_auction(user = nil)
if user
joins(<<-SQL
LEFT JOIN (
SELECT auction_id, MAX(cents) AS max_offer_cents
FROM offers
WHERE auction_id IN (
SELECT id FROM auctions WHERE platform = 1
UNION
SELECT auction_id FROM offers WHERE user_id = #{user.id} AND auction_id IN (SELECT id FROM auctions WHERE platform IS NULL OR platform = 0)
)
GROUP BY auction_id
) AS offers_subquery ON auctions.id = offers_subquery.auction_id
SQL
)
else
joins(<<-SQL
LEFT JOIN (
SELECT auction_id, MAX(cents) AS max_offer_cents
FROM offers
WHERE auction_id IN (SELECT id FROM auctions WHERE platform = 1)
GROUP BY auction_id
) AS offers_subquery ON auctions.id = offers_subquery.auction_id
SQL
)
end
end

def sorted_by_winning_offer_username
joins(<<-SQL
LEFT JOIN (
SELECT offers.auction_id, offers.username
FROM offers
WHERE offers.cents = (
SELECT MAX(offers_inner.cents)
FROM offers AS offers_inner
WHERE offers_inner.auction_id = offers.auction_id
)
GROUP BY offers.auction_id, offers.username
) AS offers_subquery ON auctions.id = offers_subquery.auction_id
SQL
)
end
end
end
125 changes: 125 additions & 0 deletions app/models/concerns/auction/sql_queriable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# frozen_string_literal: true

module Auction::SqlQueriable # rubocop:disable Metrics/ModuleLength
extend ActiveSupport::Concern

class_methods do
def with_user_offers(user_id)
Auction.from(with_user_offers_query(user_id))
end

def with_user_offers_query(user_id)
sql = <<~SQL
(WITH offers_subquery AS (
SELECT *
FROM offers
WHERE user_id = ?
)
SELECT DISTINCT
auctions.*,
offers_subquery.cents AS users_offer_cents,
offers_subquery.id AS users_offer_id,
offers_subquery.uuid AS users_offer_uuid
FROM auctions
LEFT JOIN offers_subquery on auctions.id = offers_subquery.auction_id) AS auctions
SQL

ActiveRecord::Base.sanitize_sql([sql, user_id])
end

def with_highest_offers
Auction.from(with_highest_offers_query)
end

def with_highest_offers_query
<<~SQL
(WITH offers_subquery AS (
SELECT DISTINCT on (uuid) offers.*
FROM (SELECT auction_id,
max(cents) over (PARTITION BY auction_id) as max_price,
min(created_at) over (PARTITION BY auction_id, cents) as min_time
FROM offers
) AS highest_offers
INNER JOIN offers
ON
offers.cents = highest_offers.max_price AND
offers.created_at = highest_offers.min_time AND
offers.auction_id = highest_offers.auction_id)
SELECT DISTINCT
auctions.*,
offers_subquery.cents AS highest_offer_cents,
offers_subquery.id AS highest_offer_id,
offers_subquery.uuid AS highest_offer_uuid,
(SELECT COUNT(*) FROM offers where offers.auction_id = auctions.id) AS number_of_offers
FROM auctions
LEFT JOIN offers_subquery on auctions.id = offers_subquery.auction_id) AS auctions
SQL
end

def active_with_offers_count
Auction.active.from(with_offers_count_query)
end

def with_offers_count_query
<<~SQL
(SELECT
auctions.*,
offers.cents,
recent_offers.offers_count
FROM auctions
LEFT JOIN (
SELECT auction_id,
MAX(updated_at) as last_updated_at,
COUNT(*) as offers_count
FROM offers
GROUP BY auction_id
) AS recent_offers ON auctions.id = recent_offers.auction_id
LEFT JOIN offers ON auctions.id = offers.auction_id AND offers.updated_at = recent_offers.last_updated_at) AS auctions
SQL
end

def with_max_offer_cents_for_english_auction(user = nil)
if user
joins(<<-SQL
LEFT JOIN (
SELECT auction_id, MAX(cents) AS max_offer_cents
FROM offers
WHERE auction_id IN (
SELECT id FROM auctions WHERE platform = 1
UNION
SELECT auction_id FROM offers WHERE user_id = #{user.id} AND auction_id IN (SELECT id FROM auctions WHERE platform IS NULL OR platform = 0)
)
GROUP BY auction_id
) AS offers_subquery ON auctions.id = offers_subquery.auction_id
SQL
)
else
joins(<<-SQL
LEFT JOIN (
SELECT auction_id, MAX(cents) AS max_offer_cents
FROM offers
WHERE auction_id IN (SELECT id FROM auctions WHERE platform = 1)
GROUP BY auction_id
) AS offers_subquery ON auctions.id = offers_subquery.auction_id
SQL
)
end
end

def sorted_by_winning_offer_username
joins(<<-SQL
LEFT JOIN (
SELECT offers.auction_id, offers.username
FROM offers
WHERE offers.cents = (
SELECT MAX(offers_inner.cents)
FROM offers AS offers_inner
WHERE offers_inner.auction_id = offers.auction_id
)
GROUP BY offers.auction_id, offers.username
) AS offers_subquery ON auctions.id = offers_subquery.auction_id
SQL
)
end
end
end
2 changes: 1 addition & 1 deletion app/views/auctions/_auction.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<% if auction.platform == 'blind' || auction.platform.nil? %>
<span class="auctions-table-mobile-infotainment"><%= t('auctions.your_current_price') %>: </span><%= number_with_precision(auction.users_price, precision: 2, separator: ",") %>
<% else %>
<span class="auctions-table-mobile-infotainment"><%= t('auctions.your_current_price') %>:</span>
<span class="auctions-table-mobile-infotainment"><%= t('auctions.current_price') %>:</span>
<span class="initial-color current_<%= auction.currently_winning_offer&.user_id %>_user"><%= number_with_precision(english_auction_presenter.maximum_bids, precision: 2, separator: ",") %></span>
<% end %>
</td>
Expand Down
Loading