Merge branch 'main' into ux-filter-feature-styles

This commit is contained in:
Kris 2025-06-27 16:57:37 -04:00 committed by GitHub
commit 584420bac8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 78 additions and 35 deletions

View File

@ -73,6 +73,11 @@ export default class AiFeaturesList extends Component {
return this.args.modules.sortBy("module_name"); return this.args.modules.sortBy("module_name");
} }
@action
isSpamModule(aModule) {
return aModule.module_name === "spam";
}
@action @action
hasGroups(feature) { hasGroups(feature) {
return this.groupList(feature).length > 0; return this.groupList(feature).length > 0;
@ -106,12 +111,20 @@ export default class AiFeaturesList extends Component {
<h3>{{i18n <h3>{{i18n
(concat "discourse_ai.features." module.module_name ".name") (concat "discourse_ai.features." module.module_name ".name")
}}</h3> }}</h3>
{{#if (this.isSpamModule module)}}
<DButton
class="edit"
@label="discourse_ai.features.edit"
@route="adminPlugins.show.discourse-ai-spam"
/>
{{else}}
<DButton <DButton
class="edit" class="edit"
@label="discourse_ai.features.edit" @label="discourse_ai.features.edit"
@route="adminPlugins.show.discourse-ai-features.edit" @route="adminPlugins.show.discourse-ai-features.edit"
@routeModels={{module.id}} @routeModels={{module.id}}
/> />
{{/if}}
</div> </div>
<div>{{i18n <div>{{i18n
(concat (concat
@ -194,6 +207,7 @@ export default class AiFeaturesList extends Component {
</span> </span>
{{/if}} {{/if}}
</div> </div>
{{#unless (this.isSpamModule module)}}
{{#if feature.personas}} {{#if feature.personas}}
<div class="ai-feature-card__groups"> <div class="ai-feature-card__groups">
<span class="ai-feature-card__label"> <span class="ai-feature-card__label">
@ -211,7 +225,7 @@ export default class AiFeaturesList extends Component {
</span> </span>
{{/if}} {{/if}}
</div> </div>
{{/if}} {{/unless}}
</div> </div>
</div> </div>
{{/each}} {{/each}}

View File

@ -235,7 +235,7 @@ en:
ai_helper: ai_helper:
name: "Helper" name: "Helper"
description: "Assists users in community interaction, such as creating topics, writing posts, and reading content." description: "Assists users in community interaction, such as creating topics, writing posts, and reading content"
proofread: Proofread text proofread: Proofread text
title_suggestions: "Suggest titles" title_suggestions: "Suggest titles"
explain: "Explain" explain: "Explain"
@ -254,6 +254,11 @@ en:
topic_title_translator: "Topic title translator" topic_title_translator: "Topic title translator"
short_text_translator: "Short text translator" short_text_translator: "Short text translator"
spam:
name: "Spam"
description: "Identifies potential spam using the selected LLM and flags it for site moderators to inspect in the review queue"
inspect_posts: "Inspect posts"
modals: modals:
select_option: "Select an option..." select_option: "Select an option..."

View File

@ -131,6 +131,19 @@ module DiscourseAi
] ]
end end
def spam_features
feature_cache[:spam] ||= [
new(
"inspect_posts",
nil,
DiscourseAi::Configuration::Module::SPAM_ID,
DiscourseAi::Configuration::Module::SPAM,
persona_ids_lookup: -> { [AiModerationSetting.spam&.ai_persona_id].compact },
llm_models_lookup: -> { [AiModerationSetting.spam&.llm_model].compact },
),
]
end
def lookup_bot_persona_ids def lookup_bot_persona_ids
AiPersona AiPersona
.where(enabled: true) .where(enabled: true)
@ -182,6 +195,7 @@ module DiscourseAi
ai_helper_features, ai_helper_features,
translation_features, translation_features,
bot_features, bot_features,
spam_features,
].flatten ].flatten
end end

View File

@ -10,8 +10,9 @@ module DiscourseAi
AI_HELPER = "ai_helper" AI_HELPER = "ai_helper"
TRANSLATION = "translation" TRANSLATION = "translation"
BOT = "bot" BOT = "bot"
SPAM = "spam"
NAMES = [SUMMARIZATION, SEARCH, DISCORD, INFERENCE, AI_HELPER, TRANSLATION, BOT].freeze NAMES = [SUMMARIZATION, SEARCH, DISCORD, INFERENCE, AI_HELPER, TRANSLATION, BOT, SPAM].freeze
SUMMARIZATION_ID = 1 SUMMARIZATION_ID = 1
SEARCH_ID = 2 SEARCH_ID = 2
@ -20,6 +21,7 @@ module DiscourseAi
AI_HELPER_ID = 5 AI_HELPER_ID = 5
TRANSLATION_ID = 6 TRANSLATION_ID = 6
BOT_ID = 7 BOT_ID = 7
SPAM_ID = 8
class << self class << self
def all def all
@ -27,46 +29,52 @@ module DiscourseAi
new( new(
SUMMARIZATION_ID, SUMMARIZATION_ID,
SUMMARIZATION, SUMMARIZATION,
"ai_summarization_enabled", enabled_by_setting: "ai_summarization_enabled",
features: DiscourseAi::Configuration::Feature.summarization_features, features: DiscourseAi::Configuration::Feature.summarization_features,
), ),
new( new(
SEARCH_ID, SEARCH_ID,
SEARCH, SEARCH,
"ai_bot_enabled", enabled_by_setting: "ai_bot_enabled",
features: DiscourseAi::Configuration::Feature.search_features, features: DiscourseAi::Configuration::Feature.search_features,
extra_check: -> { SiteSetting.ai_bot_discover_persona.present? }, extra_check: -> { SiteSetting.ai_bot_discover_persona.present? },
), ),
new( new(
DISCORD_ID, DISCORD_ID,
DISCORD, DISCORD,
"ai_discord_search_enabled", enabled_by_setting: "ai_discord_search_enabled",
features: DiscourseAi::Configuration::Feature.discord_features, features: DiscourseAi::Configuration::Feature.discord_features,
), ),
new( new(
INFERENCE_ID, INFERENCE_ID,
INFERENCE, INFERENCE,
"inferred_concepts_enabled", enabled_by_setting: "inferred_concepts_enabled",
features: DiscourseAi::Configuration::Feature.inference_features, features: DiscourseAi::Configuration::Feature.inference_features,
), ),
new( new(
AI_HELPER_ID, AI_HELPER_ID,
AI_HELPER, AI_HELPER,
"ai_helper_enabled", enabled_by_setting: "ai_helper_enabled",
features: DiscourseAi::Configuration::Feature.ai_helper_features, features: DiscourseAi::Configuration::Feature.ai_helper_features,
), ),
new( new(
TRANSLATION_ID, TRANSLATION_ID,
TRANSLATION, TRANSLATION,
"ai_translation_enabled", enabled_by_setting: "ai_translation_enabled",
features: DiscourseAi::Configuration::Feature.translation_features, features: DiscourseAi::Configuration::Feature.translation_features,
), ),
new( new(
BOT_ID, BOT_ID,
BOT, BOT,
"ai_bot_enabled", enabled_by_setting: "ai_bot_enabled",
features: DiscourseAi::Configuration::Feature.bot_features, features: DiscourseAi::Configuration::Feature.bot_features,
), ),
new(
SPAM_ID,
SPAM,
enabled_by_setting: "ai_spam_detection_enabled",
features: DiscourseAi::Configuration::Feature.spam_features,
),
] ]
end end
@ -75,7 +83,7 @@ module DiscourseAi
end end
end end
def initialize(id, name, enabled_by_setting, features: [], extra_check: nil) def initialize(id, name, enabled_by_setting: nil, features: [], extra_check: nil)
@id = id @id = id
@name = name @name = name
@enabled_by_setting = enabled_by_setting @enabled_by_setting = enabled_by_setting
@ -86,6 +94,8 @@ module DiscourseAi
attr_reader :id, :name, :enabled_by_setting, :features attr_reader :id, :name, :enabled_by_setting, :features
def enabled? def enabled?
return @extra_check.call if enabled_by_setting.blank? && @extra_check.present?
enabled_setting = SiteSetting.get(enabled_by_setting) enabled_setting = SiteSetting.get(enabled_by_setting)
if @extra_check if @extra_check

View File

@ -44,13 +44,13 @@ module DiscourseAi
- Site description: {site_description} - Site description: {site_description}
- Site top 10 categories: {top_categories} - Site top 10 categories: {top_categories}
Format your response as a JSON object with a one key named "spam", which indicates if a post is spam or legitimate. Format your response as a JSON object with a one key named "spam", which is a boolean that indicates if a post is spam or legitimate.
Your output should be in the following format: Your output should be in the following format:
<output> <output>
{"spam": "xx"} {"spam": xx}
</output> </output>
Where "xx" is true if the post is spam, or false if it's legitimate. Where xx is true if the post is spam, or false if it's legitimate.
PROMPT PROMPT
end end

View File

@ -19,7 +19,7 @@ RSpec.describe DiscourseAi::Admin::AiFeaturesController do
get "/admin/plugins/discourse-ai/ai-features.json" get "/admin/plugins/discourse-ai/ai-features.json"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.parsed_body["ai_features"].count).to eq(7) expect(response.parsed_body["ai_features"].count).to eq(8)
end end
end end

View File

@ -28,7 +28,7 @@ RSpec.describe "Admin AI features configuration", type: :system, js: true do
ai_features_page.toggle_unconfigured ai_features_page.toggle_unconfigured
# this changes as we add more AI features # this changes as we add more AI features
expect(ai_features_page).to have_listed_modules(6) expect(ai_features_page).to have_listed_modules(7)
end end
it "lists the persona used for the corresponding AI feature" do it "lists the persona used for the corresponding AI feature" do