diff --git a/Gemfile.lock b/Gemfile.lock
index 35c9a10f8..eb9361415 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -180,6 +180,7 @@ GEM
faraday-net_http (3.3.0)
net-http
ffi (1.17.0-aarch64-linux-gnu)
+ ffi (1.17.0-x86_64-darwin)
ffi (1.17.0-x86_64-linux-gnu)
font-awesome-sass (6.5.2)
sassc (~> 2.0)
@@ -278,6 +279,8 @@ GEM
nio4r (2.7.3)
nokogiri (1.16.7-aarch64-linux)
racc (~> 1.4)
+ nokogiri (1.16.7-x86_64-darwin)
+ racc (~> 1.4)
nokogiri (1.16.7-x86_64-linux)
racc (~> 1.4)
numo-narray (0.9.2.1)
@@ -507,6 +510,7 @@ GEM
PLATFORMS
aarch64-linux
+ x86_64-darwin-22
x86_64-linux
DEPENDENCIES
diff --git a/app/controllers/ai_judges_controller.rb b/app/controllers/ai_judges_controller.rb
new file mode 100644
index 000000000..6fe8ae238
--- /dev/null
+++ b/app/controllers/ai_judges_controller.rb
@@ -0,0 +1,22 @@
+class AiJudgesController < ApplicationController
+ def create
+ @book = Book.find(params[:book_id])
+ @user = User.find(params[:user_id])
+
+ @ai_user = AiJudge.new(book: @book, user: @user)
+
+ if @ai_user.save
+ redirect_to @book, notice: 'User was successfully added as an AI Judge.'
+ else
+ render :new
+ end
+ end
+
+ def destroy
+ @ai_judge = User.find(params[:id])
+ @book = Book.find(params[:book_id])
+ @book.judge
+ @ai_user.destroy
+ redirect_to @ai_user.book, notice: 'AI Judge was successfully removed.'
+ end
+end
diff --git a/app/controllers/api/v1/bulk_ratings_controller.rb b/app/controllers/api/v1/bulk_ratings_controller.rb
index c5a3ca491..ca2cd483c 100644
--- a/app/controllers/api/v1/bulk_ratings_controller.rb
+++ b/app/controllers/api/v1/bulk_ratings_controller.rb
@@ -15,11 +15,11 @@ def update
if params[:doc_ids].present?
params[:doc_ids].each do |doc_id|
rating = @query.ratings.find_or_create_by doc_id: doc_id
- rating.user = @current_user
# rating.update rating_params
rating.rating = pluck_out_just_rating_param
rating.save
+ JudgementFromRatingJob.perform_later current_user, rating
end
end
diff --git a/app/controllers/api/v1/queries/ratings_controller.rb b/app/controllers/api/v1/queries/ratings_controller.rb
index 1567222fb..114643244 100644
--- a/app/controllers/api/v1/queries/ratings_controller.rb
+++ b/app/controllers/api/v1/queries/ratings_controller.rb
@@ -8,10 +8,11 @@ class RatingsController < Api::V1::Queries::ApplicationController
def update
@rating = @query.ratings.find_or_create_by doc_id: @doc_id
- @rating.user = @current_user
+ # @rating.user = @current_user
if @rating.update rating_params
Analytics::Tracker.track_rating_created_event current_user, @rating
+ JudgementFromRatingJob.perform_later current_user, @rating
respond_with @rating
else
render json: @rating.errors, status: :bad_request
diff --git a/app/controllers/books_controller.rb b/app/controllers/books_controller.rb
index 1cab39a58..97d146c76 100644
--- a/app/controllers/books_controller.rb
+++ b/app/controllers/books_controller.rb
@@ -5,11 +5,11 @@ class BooksController < ApplicationController
before_action :set_book,
only: [ :show, :edit, :update, :destroy, :combine, :assign_anonymous, :delete_ratings_by_assignee,
:reset_unrateable, :reset_judge_later, :delete_query_doc_pairs_below_position,
- :eric_steered_us_wrong ]
+ :eric_steered_us_wrong, :run_judge_judy ]
before_action :check_book,
only: [ :show, :edit, :update, :destroy, :combine, :assign_anonymous, :delete_ratings_by_assignee,
:reset_unrateable, :reset_judge_later, :delete_query_doc_pairs_below_position,
- :eric_steered_us_wrong ]
+ :eric_steered_us_wrong, :run_judge_judy ]
before_action :find_user, only: [ :reset_unrateable, :reset_judge_later, :delete_ratings_by_assignee ]
@@ -24,10 +24,6 @@ def index
# rubocop:disable Metrics/MethodLength
def show
@count_of_anonymous_book_judgements = @book.judgements.where(user: nil).count
- @count_of_anonymous_case_judgements = 0
- @book.cases.each do |kase|
- @count_of_anonymous_case_judgements += kase.ratings.where(user: nil).count
- end
@moar_judgements_needed = @book.judgements.where(user: current_user).count < @book.query_doc_pairs.count
@cases = @book.cases
@@ -189,13 +185,17 @@ def combine
:alert => "Could not merge due to errors: #{@book.errors.full_messages.to_sentence}. #{query_doc_pair_count} query/doc pairs."
end
end
+
+ def run_judge_judy
+ RunJudgeJudyJob.perform_later(@book)
+ redirect_to book_path(@book), :notice => "Started #{@book.ai_judge.fullname} judging query/doc pairs."
+ end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity
# rubocop:enable Layout/LineLength
- # rubocop:disable Metrics/MethodLength
def assign_anonymous
# assignee = @book.team.members.find_by(id: params[:assignee_id])
assignee = User.find_by(id: params[:assignee_id])
@@ -209,17 +209,16 @@ def assign_anonymous
judgement.save!
end
end
- @book.cases.each do |kase|
- kase.ratings.where(user: nil).find_each do |rating|
- rating.user = assignee
- rating.save!
- end
- end
+ # @book.cases.each do |kase|
+ # kase.ratings.where(user: nil).find_each do |rating|
+ # rating.user = assignee
+ # rating.save!
+ # end
+ # end
UpdateCaseJob.perform_later @book
redirect_to book_path(@book), :notice => "Assigned #{assignee.fullname} to ratings and judgements."
end
- # rubocop:enable Metrics/MethodLength
def delete_ratings_by_assignee
judgements_to_delete = @book.judgements.where(user: @user)
diff --git a/app/jobs/judgement_from_rating_job.rb b/app/jobs/judgement_from_rating_job.rb
new file mode 100644
index 000000000..0bf9a5d18
--- /dev/null
+++ b/app/jobs/judgement_from_rating_job.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class JudgementFromRatingJob < ApplicationJob
+ queue_as :default
+
+ def perform user, rating
+ query = rating.query
+ book = query.case.book
+ if book
+ query_doc_pair = book.query_doc_pairs.find_or_create_by query_text: rating.query.query_text, doc_id: rating.doc_id
+
+ judgement = query_doc_pair.judgements.find_or_initialize_by(user: user)
+ judgement.rating = rating.rating
+ judgement.save!
+
+ RunJudgeJudyJob.perform_later book
+ end
+ end
+end
diff --git a/app/jobs/populate_book_job.rb b/app/jobs/populate_book_job.rb
index 106cd3c36..6c05c86cf 100644
--- a/app/jobs/populate_book_job.rb
+++ b/app/jobs/populate_book_job.rb
@@ -36,7 +36,7 @@ def perform user, book, kase
# we are smart and just look up the correct user id from rating.user_id via the database, no API data needed.
judgement = query_doc_pair.judgements.find_or_create_by user_id: rating.user_id
judgement.rating = pair[:rating]
- judgement.user = rating.user
+ judgement.user = User.find(pair[:user_id]) # rating.user
judgement.save!
end
@@ -52,6 +52,8 @@ def perform user, book, kase
book.populate_file.purge
book.save
+ RunJudgeJudyJob.perform_later book
+
Analytics::Tracker.track_query_doc_pairs_bulk_updated_event user, book, is_book_empty
end
# rubocop:enable Security/MarshalLoad
diff --git a/app/jobs/run_judge_judy_job.rb b/app/jobs/run_judge_judy_job.rb
new file mode 100644
index 000000000..941716921
--- /dev/null
+++ b/app/jobs/run_judge_judy_job.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class RunJudgeJudyJob < ApplicationJob
+ queue_as :default
+ sidekiq_options log_level: :warn
+
+ def perform book
+ #judge = book.ai_judge
+ judge = nil
+ if judge # only run the job if we have a judge defined
+ loop do
+ query_doc_pair = SelectionStrategy.random_query_doc_based_on_strategy(book, judge)
+ break if query_doc_pair.nil?
+
+ judgement = Judgement.new(query_doc_pair: query_doc_pair, user: judge, updated_at: Time.zone.now)
+ judgement.rating = 4
+ judgement.explanation = "Eric writing code. Judge is #{judge.email}"
+ judgement.save!
+
+ UpdateCaseJob.perform_later book
+ end
+ end
+ end
+end
diff --git a/app/models/book.rb b/app/models/book.rb
index 455b8ee8c..e8e867b47 100644
--- a/app/models/book.rb
+++ b/app/models/book.rb
@@ -32,6 +32,15 @@ class Book < ApplicationRecord
belongs_to :owner,
class_name: 'User', optional: true
+ #belongs_to :ai_judge,
+ # class_name: 'User', optional: true
+ #
+ #has_many :users, dependent: :destroy
+ #has_many :ai_judges, through: :ai_judges
+ has_and_belongs_to_many :ai_judges,
+ class_name: 'User',
+ join_table: 'ai_judges'
+
belongs_to :selection_strategy
belongs_to :scorer
has_many :query_doc_pairs, dependent: :destroy, autosave: true
diff --git a/app/models/user.rb b/app/models/user.rb
index 72a000046..34b115bdc 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -22,8 +22,10 @@
# locked_at :datetime
# name :string(255)
# num_logins :integer
+# openai_key :string(255)
# password :string(120)
# profile_pic :string(4000)
+# prompt :string(4000)
# reset_password_sent_at :datetime
# reset_password_token :string(255)
# stored_raw_invitation_token :string(255)
@@ -100,7 +102,7 @@ class User < ApplicationRecord
has_many :shared_scorers,
through: :teams,
source: :scorers
-
+
has_many :permissions,
dependent: :destroy
@@ -118,6 +120,9 @@ class User < ApplicationRecord
dependent: :destroy
has_many :announcements, foreign_key: 'author_id', dependent: :destroy, inverse_of: :author
+
+ #has_many :ai_judges, dependent: :destroy
+ #has_many :books, through: :ai_judges
# Validations
@@ -208,6 +213,11 @@ def store_raw_invitation_token
# Scopes
# default_scope -> { includes(:permissions) }
+ scope :only_ai_judges, -> { where('`users`.`openai_key` IS NOT NULL') }
+
+ def ai_judge?
+ return !openai_key.nil?
+ end
def num_queries
queries.count
diff --git a/app/services/ratings_manager.rb b/app/services/ratings_manager.rb
index 978309816..0f07cec8a 100644
--- a/app/services/ratings_manager.rb
+++ b/app/services/ratings_manager.rb
@@ -30,7 +30,6 @@ def sync_ratings_for_case kase
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/PerceivedComplexity
- # rubocop:disable Metrics/CyclomaticComplexity
def sync_judgements_to_ratings kase, query_doc_pair
query = Query.find_or_initialize_by(case: kase, query_text: query_doc_pair.query_text)
@@ -53,7 +52,9 @@ def sync_judgements_to_ratings kase, query_doc_pair
summed_rating = query_doc_pair.judgements.rateable.sum(&:rating)
rating = Rating.find_or_initialize_by(query: query, doc_id: query_doc_pair.doc_id)
- rating.user = query_doc_pair.judgements.last.user if rating.user.nil?
+ # I think the whole rating having a user was bogus becasue we have multiple raters
+ # on the book side, which kind of messes this us.
+ # rating.user = query_doc_pair.judgements.last.user if rating.user.nil?
rating.rating = if @book.support_implicit_judgements?
summed_rating / count_of_judgements
else
@@ -70,5 +71,4 @@ def sync_judgements_to_ratings kase, query_doc_pair
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/PerceivedComplexity
- # rubocop:enable Metrics/CyclomaticComplexity
end
diff --git a/app/views/books/_form.html.erb b/app/views/books/_form.html.erb
index b4b4714a6..af3af487a 100644
--- a/app/views/books/_form.html.erb
+++ b/app/views/books/_form.html.erb
@@ -51,6 +51,33 @@
<%= form.label :selection_strategy_id, class: 'form-label' %>
<%= form.collection_select(:selection_strategy_id, SelectionStrategy.all, :id, :descriptive_name, { prompt: true }, required: true, class: 'form-control') %>
+
+
+ <%= form.label :ai_judge_id, class: 'form-label' %>
+ <%
+ ai_judges = book.ai_judges
+ %>
+ <%= form.collection_select(:ai_judge_id, ai_judges, :id, :name, { include_blank: true, prompt: true }, required: false, class: 'form-control') %>
+
You can specify an AI powered Judge to evaluate this book. This list is derived from Judges created for your teams, so you must associate the book with a team first!
+
+
+
+ <%= form_with(url: book_ai_judges_path(@book), method: :post) do |form| %>
+ <%= select_tag 'user_id', options_from_collection_for_select(@book.teams.collect{|team| team.members.only_ai_judges }.flatten, :id, :name) %>
+ <%= form.submit 'Add AI Judge' %>
+ <% end %>
+
+
+ AI Judges
+
+ <% @book.ai_judges.each do |user| %>
+ -
+ <%= user.name %>
+ <%= button_to 'Remove', book_ai_judge_path(@book, user), method: :delete, class: 'btn btn-danger btn-sm' %>
+
+ <% end %>
+
+
<%= form.label :show_rank, class: 'form-check-label' %>
<%= form.check_box :show_rank, class: 'form-check-input' %>
diff --git a/app/views/books/show.html.erb b/app/views/books/show.html.erb
index 3ab8b054a..5eb7b379d 100644
--- a/app/views/books/show.html.erb
+++ b/app/views/books/show.html.erb
@@ -15,17 +15,48 @@ This book consists of <%= @book.query_doc_pairs.count %> query document pairs an
<%= render 'judgements/moar_judgements_needed', book: @book %>
-
-
+<% if !@book.ai_judges.empty? %>
+ We have some AI Judges,
<%= @book.ai_judges.map(&:name).to_sentence %> helping us.
+
+ <%= button_to 'Run Judgment Process', run_judge_judy_book_path(@book), method: :patch %>
+
+<% end %>
+
+<% if @book.import_file.attached? %>
+
+ This book has an upload of data that is currently being processed and is not ready for use yet.
+
+ Import file is <%=link_to 'available here', rails_blob_path(@book.import_file.blob, only_path: true) %>.
+ Status: <%= @book.query_doc_pairs.count %>
+ <%= link_to book_path(@book) do %>
+ Refresh
+
+ <% end %>
+
+
+<% end %>
+
+<% if @book.populate_file.attached? %>
+
+ Currently populating this book with fresh data from a case.
+
+ Status is the book has <%= @book.query_doc_pairs.count %> query doc pairs.
+ <%= link_to book_path(@book) do %>
+
+ <% end %>
-<% if @count_of_anonymous_book_judgements > 0 %>
-
- This book has <%= @count_of_anonymous_book_judgements %> anonymous judgements that could be mapped to a user.
<% end %>
-<% if @count_of_anonymous_case_judgements > 0 %>
+
+<% if @count_of_anonymous_book_judgements > 0 %>
- The associated cases have <%= @count_of_anonymous_case_judgements %> anonymous ratings that could be mapped to a user.
+ This book has <%= @count_of_anonymous_book_judgements %> anonymous judgements that could be mapped to a user.
<% end %>
@@ -107,7 +138,7 @@ This book consists of <%= @book.query_doc_pairs.count %> query document pairs an
To reference these judgements from a notebook or another system you can reference these <%= link_to 'Quepid APIs', apipie_apipie_path %> endpoints:
<%= api_book_path(@book, format: :csv) %>
or
<%= api_export_book_path(@book) %>
-
+
Leaderboard
@@ -143,7 +174,12 @@ This book consists of <%= @book.query_doc_pairs.count %> query document pairs an
<% @stats_data.each do | row | %>
- <%=display_judge_name (row[:judge]) %> |
+
+ <%=display_judge_name (row[:judge]) %>
+ <% if row[:judge] && row[:judge].ai_judge? %>
+
+ <% end %>
+ |
<% if row[:judge] %>
<%=row[:unrateable] %> <%= link_to_if(row[:judge] && row[:unrateable] > 0, "reset", reset_unrateable_book_path(@book,row[:judge].id), data: { turbo_method: :delete, turbo_confirm: "Are you sure?" }){ '' } %>
diff --git a/config/routes.rb b/config/routes.rb
index 6449a581a..aa8dbe392 100755
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -57,8 +57,9 @@
resources :books do
resources :judgements
+ resources :ai_judges
resources :query_doc_pairs do
- resources :judgements
+ resources :judgements
post 'unrateable' => 'judgements#unrateable'
patch 'unrateable' => 'judgements#unrateable'
get 'judge_later' => 'judgements#judge_later'
@@ -68,6 +69,7 @@
member do
patch 'combine'
patch 'assign_anonymous'
+ patch 'run_judge_judy'
delete 'delete_ratings_by_assignee', action: :delete_ratings_by_assignee, as: :delete_ratings_by_assignee
delete 'reset_unrateable/:user_id', action: :reset_unrateable, as: :reset_unrateable
delete 'reset_judge_later/:user_id', action: :reset_judge_later, as: :reset_judge_later
diff --git a/db/migrate/20240317233035_add_ai_judge_to_book.rb b/db/migrate/20240317233035_add_ai_judge_to_book.rb
new file mode 100644
index 000000000..cec3e54b9
--- /dev/null
+++ b/db/migrate/20240317233035_add_ai_judge_to_book.rb
@@ -0,0 +1,5 @@
+class AddAiJudgeToBook < ActiveRecord::Migration[7.1]
+ def change
+ add_column :books, :ai_judge_id, :integer
+ end
+end
diff --git a/db/migrate/20240318135613_add_judge_attributes_to_users.rb b/db/migrate/20240318135613_add_judge_attributes_to_users.rb
new file mode 100644
index 000000000..a6d814547
--- /dev/null
+++ b/db/migrate/20240318135613_add_judge_attributes_to_users.rb
@@ -0,0 +1,6 @@
+class AddJudgeAttributesToUsers < ActiveRecord::Migration[7.1]
+ def change
+ add_column :users, :prompt, :string, limit: 4000
+ add_column :users, :openai_key, :string
+ end
+end
diff --git a/db/migrate/20241017005156_create_ai_judges_join_table.rb b/db/migrate/20241017005156_create_ai_judges_join_table.rb
new file mode 100644
index 000000000..aa1b01a65
--- /dev/null
+++ b/db/migrate/20241017005156_create_ai_judges_join_table.rb
@@ -0,0 +1,12 @@
+class CreateAiJudgesJoinTable < ActiveRecord::Migration[7.2]
+ def change
+ create_table :ai_judges do |t|
+ t.references :book, null: false, foreign_key: true
+ # user doesn't have explicit fk because the id are different types
+ t.references :user, null: false #, foreign_key: true
+ t.timestamps
+ end
+
+ add_index :ai_judges, [:book_id, :user_id], unique: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 006150a3f..78950ec22 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.2].define(version: 2024_06_26_181338) do
+ActiveRecord::Schema[7.2].define(version: 2024_10_17_005156) do
create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_bin", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
@@ -46,6 +46,16 @@
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
end
+ create_table "ai_judges", charset: "utf8mb4", collation: "utf8mb4_bin", force: :cascade do |t|
+ t.bigint "book_id", null: false
+ t.bigint "user_id", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["book_id", "user_id"], name: "index_ai_judges_on_book_id_and_user_id", unique: true
+ t.index ["book_id"], name: "index_ai_judges_on_book_id"
+ t.index ["user_id"], name: "index_ai_judges_on_user_id"
+ end
+
create_table "annotations", id: :integer, charset: "utf8mb3", force: :cascade do |t|
t.text "message"
t.string "source"
@@ -356,6 +366,8 @@
t.boolean "completed_case_wizard", default: false, null: false
t.string "stored_raw_invitation_token"
t.string "profile_pic", limit: 4000
+ t.string "prompt", limit: 4000
+ t.string "openai_key"
t.index ["default_scorer_id"], name: "index_users_on_default_scorer_id"
t.index ["email"], name: "ix_user_username", unique: true
t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true, length: 191
@@ -366,6 +378,7 @@
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
+ add_foreign_key "ai_judges", "books"
add_foreign_key "annotations", "users"
add_foreign_key "book_metadata", "books"
add_foreign_key "books", "selection_strategies"
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
index 38e6f6b5a..241c64f8c 100644
--- a/test/fixtures/users.yml
+++ b/test/fixtures/users.yml
@@ -20,8 +20,10 @@
# locked_at :datetime
# name :string(255)
# num_logins :integer
+# openai_key :string(255)
# password :string(120)
# profile_pic :string(4000)
+# prompt :string(4000)
# reset_password_sent_at :datetime
# reset_password_token :string(255)
# stored_raw_invitation_token :string(255)
diff --git a/test/integration/case_to_book_to_case_flow_test.rb b/test/integration/case_to_book_to_case_flow_test.rb
index 26ebbf276..ca054a28c 100644
--- a/test/integration/case_to_book_to_case_flow_test.rb
+++ b/test/integration/case_to_book_to_case_flow_test.rb
@@ -52,8 +52,6 @@ class CaseToBookToCaseFlowTest < ActionDispatch::IntegrationTest
put api_book_case_refresh_url book, new_case, params: { create_missing_queries: true }
- response.parsed_body
-
new_case.reload
assert_not_empty new_case.queries
diff --git a/test/integration/judge_judy_flow_test.rb b/test/integration/judge_judy_flow_test.rb
new file mode 100644
index 000000000..40267b100
--- /dev/null
+++ b/test/integration/judge_judy_flow_test.rb
@@ -0,0 +1,119 @@
+# frozen_string_literal: true
+
+require 'test_helper'
+
+class JudgeJudyFlowTest < ActionDispatch::IntegrationTest
+ let(:book) { books(:james_bond_movies) }
+ let(:acase) { cases(:shared_with_team) }
+ let(:team) { teams(:shared) }
+ let(:user) { users(:random) }
+
+ test 'Demonstrate how to work with Judge Judy' do
+ post users_login_url params: { user: { email: user.email, password: 'password' }, format: :json }
+
+ assert_empty(acase.queries)
+ assert_empty(acase.ratings)
+
+ assert_includes user.teams, team
+ assert_includes acase.teams, team
+ assert_includes book.teams, team
+
+ # Link to a Case and Book together and populate it.
+ put api_case_url acase, params: { case_id: acase.id, case: { book_id: book.id }, format: :json }
+ assert_response :ok
+
+ acase.reload
+
+ assert_equal acase.book, book
+
+ # Set up Judge Judy. Give her a prompt (and an OPENAI KEY)
+
+ judge_judy = User.new name: 'judge judy', email: 'judgejudy@quepid.com', password: 'password'
+
+ # Add her to the team
+ judge_judy.teams << team
+ judge_judy.save!
+ # Add her to the book as the judge. Like owner_id but it's ai_judge_id
+ #book.ai_judge = judge_judy
+ book.save!
+
+ # Wait for her to judge
+ perform_enqueued_jobs do
+ # patch :update, params: data
+ RunJudgeJudyJob.perform_later(book)
+ end
+
+ book.reload
+
+ # make sure every query_doc_pair has a rating by Judge Judy.
+ assert_equal book.query_doc_pairs.size, book.judgements.where(user: judge_judy).size
+
+ # Add a query to the case --> and then rate it to create rating.
+ post api_case_queries_url acase,
+ params: { case_id: acase.id,
+ query: { query_text: 'what is the average velocity of a swallow?' } }
+ assert_response :ok
+ response_json = response.parsed_body
+ query = Query.find(response_json['query']['query_id'])
+
+ rating = {
+ doc_id: 'african_swallow',
+ rating: 1,
+ }
+
+ put api_case_query_ratings_url acase, query, params: { case_id: acase.id, query_id: query.id, rating: rating }
+ assert_response :ok
+ puts response.parsed_body
+ rating = Rating.find(response.parsed_body['id'])
+
+ # make sure Judge Judy didn't get involved'
+ # we don' want users tracked at the case rating level
+ assert_nil rating.user
+ # assert_equal rating.user, user
+ assert_equal rating.rating, 1
+
+ # Here is the big question, if I rate something in the main UI, how is that handled?
+ # I worry that if a case rating creates/updates a book judgement, and that triggers a
+ # update the case that we get weird round tripping. Really want ratings to be book --> Case
+
+ data = {
+ book_id: book.id,
+ case_id: acase.id,
+ query_doc_pairs: [
+ {
+ query_text: query.query_text,
+ doc_id: rating.doc_id,
+ rating: rating.rating,
+ user_id: user.id,
+ position: 0,
+ document_fields: {
+ title: 'Monty Python Quest for Holy Grail',
+ year: '1987',
+ },
+ }
+ ],
+ }
+
+ perform_enqueued_jobs do
+ assert_difference 'book.query_doc_pairs.count' do
+ put api_book_populate_url book, params: data
+ assert_response :no_content
+ end
+ end
+ book.reload
+ assert_equal book.query_doc_pairs.size, book.judgements.where(user: judge_judy).size
+
+ query_doc_pairs = book.query_doc_pairs.where(query_text: query.query_text, doc_id: rating.doc_id)
+ assert_equal query_doc_pairs.count, 1
+
+ judgements = query_doc_pairs.first.judgements
+ assert_equal 2, judgements.count
+
+ rating.reload
+
+ # See that the original case rating has changed to be the average of
+ # Judge Judy with a 4 and User with 1. (1+4)/2 = 2.5 rounded to 3.0
+ assert_equal rating.rating, 3.0
+ assert_nil rating.user # I think that having a "last user who rated" wasn't good idea.'
+ end
+end
diff --git a/test/integration/show.json.jbuilder b/test/integration/show.json.jbuilder
deleted file mode 100644
index d0e4b27d4..000000000
--- a/test/integration/show.json.jbuilder
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-json.partial! 'book', book: @book
diff --git a/test/models/user_test.rb b/test/models/user_test.rb
index 6168f3346..249cad2dc 100644
--- a/test/models/user_test.rb
+++ b/test/models/user_test.rb
@@ -22,8 +22,10 @@
# locked_at :datetime
# name :string(255)
# num_logins :integer
+# openai_key :string(255)
# password :string(120)
# profile_pic :string(4000)
+# prompt :string(4000)
# reset_password_sent_at :datetime
# reset_password_token :string(255)
# stored_raw_invitation_token :string(255)
|