diff --git a/app/controllers/discourse_ai/discord_bot/discord_bot_controller.rb b/app/controllers/discourse_ai/discord_bot/discord_bot_controller.rb new file mode 100644 index 00000000..05c592eb --- /dev/null +++ b/app/controllers/discourse_ai/discord_bot/discord_bot_controller.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module DiscourseAi + module DiscordBot + class DiscordBotController < ::ApplicationController + requires_plugin ::DiscourseAi::PLUGIN_NAME + skip_before_action :verify_authenticity_token + + + MY_PUBLIC_KEY = "6056aea5db8de8f0c1aa2494e45db790fd4a68c607785a9933ed186025f1c8c6".freeze + + def search + # Request signature verification + begin + verify_request! + rescue Ed25519::VerifyError + return head :unauthorized + end + + body = JSON.parse(request.body.read) + + if body['type'] == 1 + # Respond to Discord PING request + render json: { type: 1 } + else + # Respond to /commands + response = { type: 4, data: { content: 'This is a response' } } + render json: response + end + end + + private + def verify_request! + signature = request.headers['X-Signature-Ed25519'] + timestamp = request.headers['X-Signature-Timestamp'] + verify_key.verify([signature].pack('H*'), "#{timestamp}#{request.raw_post}") + end + + def verify_key + Ed25519::VerifyKey.new([MY_PUBLIC_KEY].pack('H*')).freeze + end + end + end +end diff --git a/config/routes.rb b/config/routes.rb index 917a6510..4afd9ae3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,6 +18,10 @@ DiscourseAi::Engine.routes.draw do post "post/:post_id/stop-streaming" => "bot#stop_streaming_response" get "bot-username" => "bot#show_bot_username" end + + scope module: :discord_bot, path: "/discord-bot", defaults: { format: :json } do + post "search" => "discord_bot#search" + end end Discourse::Application.routes.append { mount ::DiscourseAi::Engine, at: "discourse-ai" } diff --git a/lib/modules/discord_bot/entry_point.rb b/lib/modules/discord_bot/entry_point.rb new file mode 100644 index 00000000..9dfe277f --- /dev/null +++ b/lib/modules/discord_bot/entry_point.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module DiscourseAi + module Embeddings + class EntryPoint + def load_files + require_relative "model" + require_relative "topic" + require_relative "jobs/regular/generate_embeddings" + require_relative "semantic_related" + require_relative "semantic_search" + end + + def inject_into(plugin) + 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 ||= + TopicList.new( + :suggested, + nil, + DiscourseAi::Embeddings::SemanticRelated.candidates_for(topic), + ).topics + end + + 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 + + %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 + + 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 diff --git a/lib/modules/discord_bot/webhook_handler.rb b/lib/modules/discord_bot/webhook_handler.rb new file mode 100644 index 00000000..e69de29b diff --git a/plugin.rb b/plugin.rb index aa1ea37e..6d625306 100644 --- a/plugin.rb +++ b/plugin.rb @@ -9,6 +9,7 @@ gem "tokenizers", "0.3.2", platform: RUBY_PLATFORM gem "tiktoken_ruby", "0.0.5", platform: RUBY_PLATFORM +gem "ed25519", "1.2.4", platform: RUBY_PLATFORM enabled_site_setting :discourse_ai_enabled