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");
}
@action
isSpamModule(aModule) {
return aModule.module_name === "spam";
}
@action
hasGroups(feature) {
return this.groupList(feature).length > 0;
@ -106,12 +111,20 @@ export default class AiFeaturesList extends Component {
<h3>{{i18n
(concat "discourse_ai.features." module.module_name ".name")
}}</h3>
<DButton
class="edit"
@label="discourse_ai.features.edit"
@route="adminPlugins.show.discourse-ai-features.edit"
@routeModels={{module.id}}
/>
{{#if (this.isSpamModule module)}}
<DButton
class="edit"
@label="discourse_ai.features.edit"
@route="adminPlugins.show.discourse-ai-spam"
/>
{{else}}
<DButton
class="edit"
@label="discourse_ai.features.edit"
@route="adminPlugins.show.discourse-ai-features.edit"
@routeModels={{module.id}}
/>
{{/if}}
</div>
<div>{{i18n
(concat
@ -194,24 +207,25 @@ export default class AiFeaturesList extends Component {
</span>
{{/if}}
</div>
{{#if feature.personas}}
<div class="ai-feature-card__groups">
<span class="ai-feature-card__label">
{{i18n "discourse_ai.features.groups"}}
</span>
{{#if (this.hasGroups feature)}}
<ul class="ai-feature-card__item-groups">
{{#each (this.groupList feature) as |group|}}
<li>{{group.name}}</li>
{{/each}}
</ul>
{{else}}
{{#unless (this.isSpamModule module)}}
{{#if feature.personas}}
<div class="ai-feature-card__groups">
<span class="ai-feature-card__label">
{{i18n "discourse_ai.features.no_groups"}}
{{i18n "discourse_ai.features.groups"}}
</span>
{{#if (this.hasGroups feature)}}
<ul class="ai-feature-card__item-groups">
{{#each (this.groupList feature) as |group|}}
<li>{{group.name}}</li>
{{/each}}
</ul>
{{else}}
<span class="ai-feature-card__label">
{{i18n "discourse_ai.features.no_groups"}}
</span>
{{/if}}
</div>
{{/if}}
{{/unless}}
</div>
</div>
{{/each}}

View File

@ -235,7 +235,7 @@ en:
ai_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
title_suggestions: "Suggest titles"
explain: "Explain"
@ -253,6 +253,11 @@ en:
post_raw_translator: "Post raw translator"
topic_title_translator: "Topic title 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:
select_option: "Select an option..."

View File

@ -131,6 +131,19 @@ module DiscourseAi
]
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
AiPersona
.where(enabled: true)
@ -182,6 +195,7 @@ module DiscourseAi
ai_helper_features,
translation_features,
bot_features,
spam_features,
].flatten
end

View File

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

View File

@ -44,13 +44,13 @@ module DiscourseAi
- Site description: {site_description}
- 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:
<output>
{"spam": "xx"}
{"spam": xx}
</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
end

View File

@ -19,7 +19,7 @@ RSpec.describe DiscourseAi::Admin::AiFeaturesController do
get "/admin/plugins/discourse-ai/ai-features.json"
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

View File

@ -28,7 +28,7 @@ RSpec.describe "Admin AI features configuration", type: :system, js: true do
ai_features_page.toggle_unconfigured
# 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
it "lists the persona used for the corresponding AI feature" do