split Smart Search from general AI functionality
soon SmartSearch will make use of our forthcoming LLM gem test plan: - smoke test search feature flag=smart_search closes ADV-55 Change-Id: I9d837528c28c5acfdb0ded817cf0cc2259dd44b8 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/342407 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com> QA-Review: Jeremy Stanley <jeremy@instructure.com> Product-Review: Jeremy Stanley <jeremy@instructure.com>
This commit is contained in:
parent
ebb42c1408
commit
9a89ade898
|
@ -78,16 +78,16 @@ class SmartSearchController < ApplicationController
|
|||
# @returns [SearchResult]
|
||||
def search
|
||||
return render_unauthorized_action unless @context.grants_right?(@current_user, session, :read)
|
||||
return render_unauthorized_action unless OpenAi.smart_search_available?(@context)
|
||||
return render_unauthorized_action unless SmartSearch.smart_search_available?(@context)
|
||||
return render json: { error: "missing 'q' param" }, status: :bad_request unless params.key?(:q)
|
||||
|
||||
OpenAi.with_pgvector do
|
||||
WikiPageEmbedding.with_pgvector do
|
||||
response = {
|
||||
results: []
|
||||
}
|
||||
|
||||
if params[:q].present?
|
||||
embedding = OpenAi.generate_embedding(params[:q])
|
||||
embedding = SmartSearch.generate_embedding(params[:q])
|
||||
|
||||
# Prototype query using "neighbor". Embedding is now on join table so manual SQL for now
|
||||
# wiki_pages = WikiPage.nearest_neighbors(:embedding, embedding, distance: "inner_product")
|
||||
|
@ -110,7 +110,7 @@ class SmartSearchController < ApplicationController
|
|||
def show
|
||||
@context = Course.find(params[:course_id])
|
||||
|
||||
render_unauthorized_action unless OpenAi.smart_search_available?(@context)
|
||||
render_unauthorized_action unless SmartSearch.smart_search_available?(@context)
|
||||
set_active_tab("search")
|
||||
@show_left_side = true
|
||||
add_crumb(t("#crumbs.search", "Search"), named_context_url(@context, :course_search_url)) unless @skip_crumb
|
||||
|
|
|
@ -3368,7 +3368,7 @@ class Course < ActiveRecord::Base
|
|||
Course.default_tabs
|
||||
end
|
||||
|
||||
if OpenAi.smart_search_available?(self)
|
||||
if SmartSearch.smart_search_available?(self)
|
||||
default_tabs.insert(1,
|
||||
{
|
||||
id: TAB_SEARCH,
|
||||
|
|
|
@ -108,7 +108,7 @@ class WikiPage < ActiveRecord::Base
|
|||
|
||||
def should_generate_embeddings?
|
||||
return false if deleted?
|
||||
return false unless OpenAi.smart_search_available?(context)
|
||||
return false unless SmartSearch.smart_search_available?(context)
|
||||
|
||||
saved_change_to_body? ||
|
||||
saved_change_to_title? ||
|
||||
|
@ -143,7 +143,7 @@ class WikiPage < ActiveRecord::Base
|
|||
def generate_embeddings
|
||||
delete_embeddings
|
||||
chunk_content do |chunk|
|
||||
embedding = OpenAi.generate_embedding(chunk)
|
||||
embedding = SmartSearch.generate_embedding(chunk)
|
||||
wiki_page_embeddings.create!(embedding:)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -786,6 +786,11 @@ class ActiveRecord::Base
|
|||
# Just return something that isn't an ar connection object so consoles don't explode
|
||||
override
|
||||
end
|
||||
|
||||
def self.with_pgvector(&)
|
||||
vector_schema = connection.extension("vector").schema
|
||||
connection.add_schema_to_search_path(vector_schema, &)
|
||||
end
|
||||
end
|
||||
|
||||
module UsefulFindInBatches
|
||||
|
|
|
@ -111,9 +111,9 @@ module FeatureFlags
|
|||
def self.smart_search_after_state_change_hook(_user, context, old_state, new_state)
|
||||
if %w[off allowed].include?(old_state) && %w[on allowed_on].include?(new_state)
|
||||
if context.is_a?(Account) && !context.site_admin?
|
||||
OpenAi.delay(priority: Delayed::LOW_PRIORITY).index_account(context)
|
||||
SmartSearch.delay(priority: Delayed::LOW_PRIORITY).index_account(context)
|
||||
elsif context.is_a?(Course)
|
||||
OpenAi.delay(priority: Delayed::LOW_PRIORITY).index_course(context)
|
||||
SmartSearch.delay(priority: Delayed::LOW_PRIORITY).index_course(context)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
# 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/>.
|
||||
|
||||
module OpenAi
|
||||
module SmartSearch
|
||||
class << self
|
||||
def api_key
|
||||
Rails.application.credentials.dig(:smart_search, :openai_api_token)
|
||||
|
@ -62,11 +62,6 @@ module OpenAi
|
|||
JSON.parse(response.body)["choices"][0]["text"].strip
|
||||
end
|
||||
|
||||
def with_pgvector(&)
|
||||
vector_schema = ActiveRecord::Base.connection.extension("vector").schema
|
||||
ActiveRecord::Base.connection.add_schema_to_search_path(vector_schema, &)
|
||||
end
|
||||
|
||||
def index_account(root_account)
|
||||
# by default, index all courses updated in the last year
|
||||
date_cutoff = Setting.get("smart_search_index_days_ago", "365").to_i.days.ago
|
|
@ -1103,8 +1103,8 @@ describe WikiPage do
|
|||
before do
|
||||
skip "not available" unless ActiveRecord::Base.connection.table_exists?("wiki_page_embeddings")
|
||||
|
||||
allow(OpenAi).to receive(:generate_embedding).and_return([1] * 1536)
|
||||
expect(OpenAi).to receive(:api_key).at_least(:once).and_return("fake_api_key")
|
||||
allow(SmartSearch).to receive(:generate_embedding).and_return([1] * 1536)
|
||||
expect(SmartSearch).to receive(:api_key).at_least(:once).and_return("fake_api_key")
|
||||
end
|
||||
|
||||
before :once do
|
||||
|
@ -1128,7 +1128,7 @@ describe WikiPage do
|
|||
|
||||
it "strips HTML from the body before indexing" do
|
||||
wiki_page_model(title: "test", body: "<ul><li>foo</li></ul>")
|
||||
expect(OpenAi).to receive(:generate_embedding).with("test\n* foo")
|
||||
expect(SmartSearch).to receive(:generate_embedding).with("test\n* foo")
|
||||
run_jobs
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue