mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-03-01 23:09:19 +00:00
TopicQuery already provides a lot of safeguards and options for filtering topic, and enforcing permissions. It makes sense to rely on it as other plugins like discourse-assign do. As a bonus, we now have access to the current_user while serializing these topics, so users will see things like unread posts count just like we do for the lists.
86 lines
3.0 KiB
Ruby
86 lines
3.0 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module DiscourseAi
|
|
module Embeddings
|
|
class EntryPoint
|
|
def load_files
|
|
require_relative "models/base"
|
|
require_relative "models/all_mpnet_base_v2"
|
|
require_relative "models/text_embedding_ada_002"
|
|
require_relative "models/multilingual_e5_large"
|
|
require_relative "strategies/truncation"
|
|
require_relative "manager"
|
|
require_relative "jobs/regular/generate_embeddings"
|
|
require_relative "semantic_related"
|
|
require_relative "semantic_search"
|
|
end
|
|
|
|
def inject_into(plugin)
|
|
# Include random topics in the suggested list *only* if there are no related topics.
|
|
plugin.register_modifier(
|
|
:topic_view_suggested_topics_options,
|
|
) do |suggested_options, topic_view|
|
|
related_topics = topic_view.related_topics
|
|
include_random = related_topics.nil? || related_topics.length == 0
|
|
suggested_options.merge(include_random: include_random)
|
|
end
|
|
|
|
# Query and serialize related topics.
|
|
plugin.add_to_class(:topic_view, :related_topics) do
|
|
if topic.private_message? || !SiteSetting.ai_embeddings_semantic_related_topics_enabled
|
|
return nil
|
|
end
|
|
|
|
@related_topics ||= TopicQuery.new(@user).list_semantic_related_topics(topic).topics
|
|
end
|
|
|
|
plugin.add_to_class(:topic_query, :list_semantic_related_topics) do |topic|
|
|
query_opts = {
|
|
skip_ordering: true,
|
|
per_page: SiteSetting.ai_embeddings_semantic_related_topics,
|
|
unordered: true,
|
|
}
|
|
|
|
if !SiteSetting.ai_embeddings_semantic_related_include_closed_topics
|
|
query_opts[:status] = "open"
|
|
end
|
|
|
|
create_list(:semantic_related, query_opts) do |topics|
|
|
candidate_ids = DiscourseAi::Embeddings::SemanticRelated.related_topic_ids_for(topic)
|
|
|
|
topics
|
|
.where.not(id: topic.id)
|
|
.where(id: candidate_ids)
|
|
.order("array_position(ARRAY#{candidate_ids}, topics.id)") # array_position forces the order of the topics to be preserved
|
|
end
|
|
end
|
|
|
|
%i[topic_view TopicViewPosts].each do |serializer|
|
|
plugin.add_to_serializer(
|
|
serializer,
|
|
:related_topics,
|
|
include_condition: -> { SiteSetting.ai_embeddings_semantic_related_topics_enabled },
|
|
) do
|
|
if object.next_page.nil? && !object.topic.private_message?
|
|
object.related_topics.map do |t|
|
|
SuggestedTopicSerializer.new(t, scope: scope, root: false)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
# embeddings generation.
|
|
callback =
|
|
Proc.new do |topic|
|
|
if SiteSetting.ai_embeddings_enabled
|
|
Jobs.enqueue(:generate_embeddings, topic_id: topic.id)
|
|
end
|
|
end
|
|
|
|
plugin.on(:topic_created, &callback)
|
|
plugin.on(:topic_edited, &callback)
|
|
end
|
|
end
|
|
end
|
|
end
|