0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-14 13:58:53 +08:00
discourse/plugins/discourse-ai/lib/configuration/llm_enumerator.rb
Sam e3fae646d4
DEV: AI persona to agent migration (#38319)
Co-authored-by: Keegan George <kgeorge13@gmail.com>
2026-03-10 15:59:45 +11:00

125 lines
4.6 KiB
Ruby
Vendored

# frozen_string_literal: true
require "enum_site_setting"
module DiscourseAi
module Configuration
class LlmEnumerator < ::EnumSiteSetting
def self.global_usage
rval = Hash.new { |h, k| h[k] = [] }
if SiteSetting.ai_bot_enabled
LlmModel.enabled_chat_bot_ids.each { |llm_id| rval[llm_id] << { type: :ai_bot } }
end
# this is unconditional, so it is clear that we always signal configuration
AiAgent
.where.not(default_llm_id: nil)
.pluck(:default_llm_id, :name, :id)
.each { |llm_id, name, id| rval[llm_id] << { type: :ai_agent, name: name, id: id } }
if SiteSetting.ai_helper_enabled
{
"#{I18n.t("js.discourse_ai.features.ai_helper.proofread")}" =>
SiteSetting.ai_helper_proofreader_agent,
"#{I18n.t("js.discourse_ai.features.ai_helper.title_suggestions")}" =>
SiteSetting.ai_helper_title_suggestions_agent,
"#{I18n.t("js.discourse_ai.features.ai_helper.explain")}" =>
SiteSetting.ai_helper_explain_agent,
"#{I18n.t("js.discourse_ai.features.ai_helper.illustrate_post")}" =>
SiteSetting.ai_helper_post_illustrator_agent,
"#{I18n.t("js.discourse_ai.features.ai_helper.smart_dates")}" =>
SiteSetting.ai_helper_smart_dates_agent,
"#{I18n.t("js.discourse_ai.features.ai_helper.translator")}" =>
SiteSetting.ai_helper_translator_agent,
"#{I18n.t("js.discourse_ai.features.ai_helper.markdown_tables")}" =>
SiteSetting.ai_helper_markdown_tables_agent,
"#{I18n.t("js.discourse_ai.features.ai_helper.custom_prompt")}" =>
SiteSetting.ai_helper_custom_prompt_agent,
}.each do |helper_type, agent_id|
next if agent_id.blank?
agent = AiAgent.find_by(id: agent_id)
next if agent.blank? || agent.default_llm_id.blank?
model_id = agent.default_llm_id || SiteSetting.ai_default_llm_model.to_i
rval[model_id] << { type: :ai_helper, name: helper_type }
end
end
if SiteSetting.ai_helper_enabled_features.split("|").include?("image_caption")
image_caption_agent = AiAgent.find_by(id: SiteSetting.ai_helper_image_caption_agent)
model_id = image_caption_agent.default_llm_id || SiteSetting.ai_default_llm_model.to_i
rval[model_id] << { type: :ai_helper_image_caption }
end
if SiteSetting.ai_summarization_enabled
summarization_agent = AiAgent.find_by(id: SiteSetting.ai_summarization_agent)
model_id = summarization_agent.default_llm_id || SiteSetting.ai_default_llm_model.to_i
rval[model_id] << { type: :ai_summarization }
end
if SiteSetting.ai_embeddings_semantic_search_enabled
search_agent = AiAgent.find_by(id: SiteSetting.ai_embeddings_semantic_search_hyde_agent)
model_id = search_agent.default_llm_id || SiteSetting.ai_default_llm_model.to_i
rval[model_id] << { type: :ai_embeddings_semantic_search }
end
if SiteSetting.ai_spam_detection_enabled && AiModerationSetting.spam.present?
model_id = AiModerationSetting.spam[:llm_model_id]
rval[model_id] << { type: :ai_spam }
end
if defined?(DiscourseAutomation::Automation)
DiscourseAutomation::Automation
.joins(:fields)
.where(script: %w[llm_report llm_triage])
.where("discourse_automation_fields.name = ?", "model")
.pluck(
"metadata ->> 'value', discourse_automation_automations.name, discourse_automation_automations.id",
)
.each do |model_text, name, id|
next if model_text.blank?
model_id = model_text.to_i
rval[model_id] << { type: :automation, name: name, id: id } if model_id.present?
end
end
rval
end
def self.valid_value?(val)
true
end
# returns an array of hashes (id: , name:, vision_enabled:)
def self.values_for_serialization
return [] unless table_exists?
DB.query_hash(<<~SQL).map(&:symbolize_keys)
SELECT id, display_name AS name, vision_enabled
FROM llm_models
SQL
end
def self.values
return [] unless table_exists?
DB.query_hash(<<~SQL).map(&:symbolize_keys)
SELECT display_name AS name, id AS value
FROM llm_models
SQL
end
def self.table_exists?
DB.exec("SELECT 1 FROM llm_models LIMIT 0")
true
rescue StandardError
false
end
end
end
end