add migrations and models for discussion summary prototype

refs ADV-49

flag = none

Test plan:
- tests pass

Change-Id: I834e1d7720686d59da9a5f2cdcdee1cb1fe850e8
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/346722
Reviewed-by: Cody Cutrer <cody@instructure.com>
Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com>
Migration-Review: Cody Cutrer <cody@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
QA-Review: Richard Zana <rzana@instructure.com>
Product-Review: Richard Zana <rzana@instructure.com>
This commit is contained in:
rzana 2024-05-03 12:42:13 +02:00 committed by Richard Zana
parent 146a28ee5d
commit ec3b5dbb32
9 changed files with 357 additions and 0 deletions

View File

@ -97,6 +97,7 @@ class DiscussionTopic < ActiveRecord::Base
has_many :course_sections, through: :discussion_topic_section_visibilities, dependent: :destroy has_many :course_sections, through: :discussion_topic_section_visibilities, dependent: :destroy
belongs_to :user belongs_to :user
has_one :master_content_tag, class_name: "MasterCourses::MasterContentTag", inverse_of: :discussion_topic has_one :master_content_tag, class_name: "MasterCourses::MasterContentTag", inverse_of: :discussion_topic
has_many :summaries, class_name: "DiscussionTopicSummary"
validates_associated :discussion_topic_section_visibilities validates_associated :discussion_topic_section_visibilities
validates :context_id, :context_type, presence: true validates :context_id, :context_type, presence: true

View File

@ -0,0 +1,34 @@
# frozen_string_literal: true
# Copyright (C) 2024 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class DiscussionTopicSummary < ActiveRecord::Base
belongs_to :root_account, class_name: "Account"
belongs_to :discussion_topic, inverse_of: :summaries
has_many :feedback, class_name: "DiscussionTopicSummary::Feedback"
validates :summary, presence: true
validates :llm_config_version, presence: true
validates :dynamic_content_hash, presence: true
before_validation :set_root_account
def set_root_account
self.root_account ||= discussion_topic.root_account
end
end

View File

@ -0,0 +1,52 @@
# frozen_string_literal: true
#
# Copyright (C) 2024 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class DiscussionTopicSummary
class Feedback < ActiveRecord::Base
belongs_to :root_account, class_name: "Account"
belongs_to :discussion_topic_summary, inverse_of: :feedback
belongs_to :user
before_validation :set_root_account
def set_root_account
self.root_account ||= discussion_topic_summary.root_account
end
def like
update!(liked: true, disliked: false)
end
def dislike
update!(liked: false, disliked: true)
end
def reset_like
update!(liked: false, disliked: false)
end
def regenerate
update!(regenerated: true)
end
def disable_summary
update!(summary_disabled: true)
end
end
end

View File

@ -28,4 +28,5 @@ ActiveSupport::Inflector.inflections do |inflect|
inflect.acronym "CSV" inflect.acronym "CSV"
inflect.acronym "OAuth" inflect.acronym "OAuth"
inflect.acronym "OAuth2" inflect.acronym "OAuth2"
inflect.irregular "feedback", "feedback"
end end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
# Copyright (C) 2024 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class AddSummaryEnabledToDiscussionTopics < ActiveRecord::Migration[7.0]
tag :predeploy
def change
add_column :discussion_topics, :summary_enabled, :boolean, default: false, null: false
end
end

View File

@ -0,0 +1,55 @@
# frozen_string_literal: true
# Copyright (C) 2024 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class AddSummaryToDiscussionTopics < ActiveRecord::Migration[7.0]
tag :predeploy
def change
create_table :discussion_topic_summaries do |t|
t.references :root_account, foreign_key: { to_table: :accounts }, index: false, null: false
t.replica_identity_index
t.references :discussion_topic, null: false, foreign_key: true, index: { name: "index_summaries_on_topic_id" }
t.string :llm_config_version, null: false, limit: 255
t.string :dynamic_content_hash, null: false, limit: 255
t.timestamps
t.text :summary
t.integer :input_tokens
t.integer :output_tokens
t.float :generation_time
t.index %i[discussion_topic_id llm_config_version dynamic_content_hash], name: "index_summaries_on_topic_id_and_llm_config_version_and_hash"
t.index %i[discussion_topic_id created_at], name: "index_summaries_on_topic_id_and_created_at", order: { created_at: :desc }
end
create_table :discussion_topic_summary_feedback do |t|
t.references :root_account, foreign_key: { to_table: :accounts }, index: false, null: false
t.replica_identity_index
t.references :discussion_topic_summary, null: false, foreign_key: true, index: false
t.references :user, null: false, foreign_key: true
t.boolean :liked, default: false, null: false
t.boolean :disliked, default: false, null: false
t.boolean :regenerated, null: false, default: false
t.boolean :summary_disabled, null: false, default: false
t.timestamps
t.index %i[discussion_topic_summary_id user_id], unique: true, name: "index_feedback_on_summary_id_and_user_id"
t.check_constraint "NOT (liked AND disliked)"
end
end
end

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
# Copyright (C) 2024 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class AddReplicaIdentityToDiscussionSummaries < ActiveRecord::Migration[7.0]
tag :predeploy
def up
set_replica_identity :discussion_topic_summaries
set_replica_identity :discussion_topic_summary_feedback
end
def down
set_replica_identity :discussion_topic_summaries, :default
set_replica_identity :discussion_topic_summary_feedback, :default
end
end

View File

@ -0,0 +1,88 @@
# frozen_string_literal: true
# Copyright (C) 2024 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
describe DiscussionTopicSummary::Feedback do
before do
discussion_topic = course_model.discussion_topics.create!
@discussion_topic_summary = discussion_topic.summaries.create!(
discussion_topic:,
summary: "summary",
dynamic_content_hash: "hash",
llm_config_version: "V0_A"
)
@user = User.create!(name: "John Doe")
@feedback = @discussion_topic_summary.feedback.create!(user: @user)
end
describe "associations" do
subject { described_class.new(discussion_topic_summary: @discussion_topic_summary, user: @user) }
it "is associated with the correct parameters" do
subject.valid?
expect(subject.discussion_topic_summary).to eq(@discussion_topic_summary)
expect(subject.user).to eq(@user)
expect(subject.root_account).to eq(@discussion_topic_summary.root_account)
end
end
describe "action methods" do
context "when action is like" do
it "sets liked to true" do
@feedback.like
expect(@feedback.liked).to be true
expect(@feedback.disliked).to be false
end
end
context "when action is dislike" do
it "sets disliked to true" do
@feedback.dislike
expect(@feedback.liked).to be false
expect(@feedback.disliked).to be true
end
end
context "when action is reset_like" do
it "sets liked and disliked to false" do
@feedback.like
@feedback.reset_like
expect(@feedback.liked).to be false
expect(@feedback.disliked).to be false
@feedback.dislike
@feedback.reset_like
expect(@feedback.liked).to be false
expect(@feedback.disliked).to be false
end
end
context "when action is regenerate" do
it "sets regenerated to true" do
@feedback.regenerate
expect(@feedback.regenerated).to be true
end
end
context "when action is disable_summary" do
it "sets summary_disabled to true" do
@feedback.disable_summary
expect(@feedback.summary_disabled).to be true
end
end
end
end

View File

@ -0,0 +1,70 @@
# frozen_string_literal: true
# Copyright (C) 2024 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
describe DiscussionTopicSummary do
before do
@discussion_topic = course_model.discussion_topics.create!
end
describe "associations" do
subject do
described_class.new(
discussion_topic: @discussion_topic,
summary: "summary",
dynamic_content_hash: "hash",
llm_config_version: "V0_A"
)
end
it "is associated with the correct parameters" do
subject.valid?
expect(subject.discussion_topic).to eq(@discussion_topic)
expect(subject.llm_config_version).to eq("V0_A")
end
end
describe "validations" do
it "validates presence of summary" do
summary = DiscussionTopicSummary.new(
discussion_topic: @discussion_topic,
dynamic_content_hash: "hash"
)
expect(summary.valid?).to be false
expect(summary.errors[:summary]).to include("can't be blank")
end
it "validates presence of dynamic_content_hash" do
summary = DiscussionTopicSummary.new(
discussion_topic: @discussion_topic,
summary: "Valid Summary"
)
expect(summary.valid?).to be false
expect(summary.errors[:dynamic_content_hash]).to include("can't be blank")
end
it "validates presence of llm_config_version" do
summary = DiscussionTopicSummary.new(
discussion_topic: @discussion_topic,
summary: "Valid Summary",
dynamic_content_hash: "hash"
)
expect(summary.valid?).to be false
expect(summary.errors[:llm_config_version]).to include("can't be blank")
end
end
end