discourse-ai/lib/modules/ai_bot/personas/persona.rb

137 lines
4.3 KiB
Ruby
Raw Normal View History

#frozen_string_literal: true
module DiscourseAi
module AiBot
module Personas
def self.all(user: nil)
personas = [Personas::General, Personas::SqlHelper]
personas << Personas::Artist if SiteSetting.ai_stability_api_key.present?
personas << Personas::SettingsExplorer
personas << Personas::Researcher if SiteSetting.ai_google_custom_search_api_key.present?
personas << Personas::Creative
personas_allowed = SiteSetting.ai_bot_enabled_personas.split("|")
personas =
personas.filter do |persona|
personas_allowed.include?(persona.to_s.demodulize.underscore)
end
if user
personas.concat(
AiPersona.all_personas.filter do |persona|
user.in_any_groups?(persona.allowed_group_ids)
end,
)
end
personas
end
class Persona
def self.name
I18n.t("discourse_ai.ai_bot.personas.#{to_s.demodulize.underscore}.name")
end
def self.description
I18n.t("discourse_ai.ai_bot.personas.#{to_s.demodulize.underscore}.description")
end
def initialize(allow_commands: true)
@allow_commands = allow_commands
end
def commands
[]
end
def render_commands(render_function_instructions:)
return +"" if !@allow_commands
result = +""
if render_function_instructions
result << "\n"
result << function_list.system_prompt
result << "\n"
end
result << available_commands.map(&:custom_system_message).compact.join("\n")
result
end
def render_system_prompt(topic: nil, render_function_instructions: true)
substitutions = {
site_url: Discourse.base_url,
site_title: SiteSetting.title,
site_description: SiteSetting.site_description,
time: Time.zone.now,
commands: render_commands(render_function_instructions: render_function_instructions),
}
substitutions[:participants] = topic.allowed_users.map(&:username).join(", ") if topic
system_prompt.gsub(/\{(\w+)\}/) do |match|
found = substitutions[match[1..-2].to_sym]
found.nil? ? match : found.to_s
end
end
def available_commands
return [] if !@allow_commands
return @available_commands if @available_commands
@available_commands = all_available_commands.filter { |cmd| commands.include?(cmd) }
end
def available_functions
return [] if !@allow_commands
# note if defined? can be a problem in test
# this can never be nil so it is safe
return @available_functions if @available_functions
functions = []
functions =
available_commands.map do |command|
function =
DiscourseAi::Inference::Function.new(name: command.name, description: command.desc)
command.parameters.each { |parameter| function.add_parameter(parameter) }
function
end
@available_functions = functions
end
def function_list
return @function_list if @function_list
@function_list = DiscourseAi::Inference::FunctionList.new
available_functions.each { |function| @function_list << function }
@function_list
end
def all_available_commands
return @cmds if @cmds
all_commands = [
Commands::CategoriesCommand,
Commands::TimeCommand,
Commands::SearchCommand,
Commands::SummarizeCommand,
Commands::ReadCommand,
]
all_commands << Commands::TagsCommand if SiteSetting.tagging_enabled
all_commands << Commands::ImageCommand if SiteSetting.ai_stability_api_key.present?
if SiteSetting.ai_google_custom_search_api_key.present? &&
SiteSetting.ai_google_custom_search_cx.present?
all_commands << Commands::GoogleCommand
end
allowed_commands = SiteSetting.ai_bot_enabled_chat_commands.split("|")
@cmds = all_commands.filter { |klass| allowed_commands.include?(klass.name) }
end
end
end
end
end