2023-05-05 14:28:31 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module DiscourseAi
|
|
|
|
module AiBot
|
|
|
|
class EntryPoint
|
2023-08-23 17:20:24 -04:00
|
|
|
REQUIRE_TITLE_UPDATE = "discourse-ai-title-update"
|
|
|
|
|
2023-05-11 09:03:03 -04:00
|
|
|
GPT4_ID = -110
|
|
|
|
GPT3_5_TURBO_ID = -111
|
2023-07-26 21:24:44 -04:00
|
|
|
CLAUDE_V2_ID = -112
|
2023-12-10 22:59:57 -05:00
|
|
|
GPT4_TURBO_ID = -113
|
2024-01-04 10:22:43 -05:00
|
|
|
MIXTRAL_ID = -114
|
2024-01-04 16:15:34 -05:00
|
|
|
GEMINI_ID = -115
|
2024-01-10 23:56:40 -05:00
|
|
|
FAKE_ID = -116 # only used for dev and test
|
|
|
|
|
2023-10-23 02:00:58 -04:00
|
|
|
BOTS = [
|
|
|
|
[GPT4_ID, "gpt4_bot", "gpt-4"],
|
|
|
|
[GPT3_5_TURBO_ID, "gpt3.5_bot", "gpt-3.5-turbo"],
|
|
|
|
[CLAUDE_V2_ID, "claude_bot", "claude-2"],
|
2023-12-10 22:59:57 -05:00
|
|
|
[GPT4_TURBO_ID, "gpt4t_bot", "gpt-4-turbo"],
|
2024-01-04 10:22:43 -05:00
|
|
|
[MIXTRAL_ID, "mixtral_bot", "mixtral-8x7B-Instruct-V0.1"],
|
2024-01-04 16:15:34 -05:00
|
|
|
[GEMINI_ID, "gemini_bot", "gemini-pro"],
|
2024-01-10 23:56:40 -05:00
|
|
|
[FAKE_ID, "fake_bot", "fake"],
|
2023-10-23 02:00:58 -04:00
|
|
|
]
|
2023-05-05 14:28:31 -04:00
|
|
|
|
2024-02-15 00:37:59 -05:00
|
|
|
BOT_USER_IDS = BOTS.map(&:first)
|
|
|
|
|
2023-05-16 13:38:21 -04:00
|
|
|
def self.map_bot_model_to_user_id(model_name)
|
|
|
|
case model_name
|
2023-12-10 22:59:57 -05:00
|
|
|
in "gpt-4-turbo"
|
|
|
|
GPT4_TURBO_ID
|
2023-05-16 13:38:21 -04:00
|
|
|
in "gpt-3.5-turbo"
|
|
|
|
GPT3_5_TURBO_ID
|
|
|
|
in "gpt-4"
|
|
|
|
GPT4_ID
|
2023-07-26 21:24:44 -04:00
|
|
|
in "claude-2"
|
|
|
|
CLAUDE_V2_ID
|
2024-01-04 10:22:43 -05:00
|
|
|
in "mixtral-8x7B-Instruct-V0.1"
|
|
|
|
MIXTRAL_ID
|
2024-01-04 16:15:34 -05:00
|
|
|
in "gemini-pro"
|
|
|
|
GEMINI_ID
|
2024-01-10 23:56:40 -05:00
|
|
|
in "fake"
|
|
|
|
FAKE_ID
|
2023-05-16 13:38:21 -04:00
|
|
|
else
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-05-05 14:28:31 -04:00
|
|
|
def inject_into(plugin)
|
2023-10-23 02:00:58 -04:00
|
|
|
plugin.on(:site_setting_changed) do |name, _old_value, _new_value|
|
2024-01-29 11:24:30 -05:00
|
|
|
if name == :ai_bot_enabled_chat_bots || name == :ai_bot_enabled ||
|
|
|
|
name == :discourse_ai_enabled
|
2023-10-23 02:00:58 -04:00
|
|
|
DiscourseAi::AiBot::SiteSettingsExtension.enable_or_disable_ai_bots
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-05-05 14:28:31 -04:00
|
|
|
plugin.register_seedfu_fixtures(
|
|
|
|
Rails.root.join("plugins", "discourse-ai", "db", "fixtures", "ai_bot"),
|
|
|
|
)
|
|
|
|
|
2023-08-30 02:15:03 -04:00
|
|
|
plugin.add_to_serializer(
|
|
|
|
:current_user,
|
|
|
|
:ai_enabled_personas,
|
|
|
|
include_condition: -> do
|
|
|
|
SiteSetting.ai_bot_enabled && scope.authenticated? &&
|
|
|
|
scope.user.in_any_groups?(SiteSetting.ai_bot_allowed_groups_map)
|
|
|
|
end,
|
|
|
|
) do
|
2024-01-04 08:44:07 -05:00
|
|
|
DiscourseAi::AiBot::Personas::Persona
|
2023-11-09 19:39:49 -05:00
|
|
|
.all(user: scope.user)
|
FEATURE: UI to update ai personas on admin page (#290)
Introduces a UI to manage customizable personas (admin only feature)
Part of the change was some extensive internal refactoring:
- AIBot now has a persona set in the constructor, once set it never changes
- Command now takes in bot as a constructor param, so it has the correct persona and is not generating AIBot objects on the fly
- Added a .prettierignore file, due to the way ALE is configured in nvim it is a pre-req for prettier to work
- Adds a bunch of validations on the AIPersona model, system personas (artist/creative etc...) are all seeded. We now ensure
- name uniqueness, and only allow certain properties to be touched for system personas.
- (JS note) the client side design takes advantage of nested routes, the parent route for personas gets all the personas via this.store.findAll("ai-persona") then child routes simply reach into this model to find a particular persona.
- (JS note) data is sideloaded into the ai-persona model the meta property supplied from the controller, resultSetMeta
- This removes ai_bot_enabled_personas and ai_bot_enabled_chat_commands, both should be controlled from the UI on a per persona basis
- Fixes a long standing bug in token accounting ... we were doing to_json.length instead of to_json.to_s.length
- Amended it so {commands} are always inserted at the end unconditionally, no need to add it to the template of the system message as it just confuses things
- Adds a concept of required_commands to stock personas, these are commands that must be configured for this stock persona to show up.
- Refactored tests so we stop requiring inference_stubs, it was very confusing to need it, added to plugin.rb for now which at least is clearer
- Migrates the persona selector to gjs
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Co-authored-by: Martin Brennan <martin@discourse.org>
2023-11-21 00:56:43 -05:00
|
|
|
.map do |persona|
|
|
|
|
{ id: persona.id, name: persona.name, description: persona.description }
|
|
|
|
end
|
2023-08-30 02:15:03 -04:00
|
|
|
end
|
|
|
|
|
2023-08-16 16:29:58 -04:00
|
|
|
plugin.add_to_serializer(
|
|
|
|
:current_user,
|
|
|
|
:ai_enabled_chat_bots,
|
|
|
|
include_condition: -> do
|
|
|
|
SiteSetting.ai_bot_enabled && scope.authenticated? &&
|
|
|
|
scope.user.in_any_groups?(SiteSetting.ai_bot_allowed_groups_map)
|
|
|
|
end,
|
|
|
|
) do
|
|
|
|
model_map = {}
|
|
|
|
SiteSetting
|
|
|
|
.ai_bot_enabled_chat_bots
|
|
|
|
.split("|")
|
|
|
|
.each do |bot_name|
|
|
|
|
model_map[
|
|
|
|
::DiscourseAi::AiBot::EntryPoint.map_bot_model_to_user_id(bot_name)
|
|
|
|
] = bot_name
|
|
|
|
end
|
|
|
|
|
|
|
|
# not 100% ideal, cause it is one extra query, but we need it
|
|
|
|
bots = DB.query_hash(<<~SQL, user_ids: model_map.keys)
|
|
|
|
SELECT username, id FROM users WHERE id IN (:user_ids)
|
|
|
|
SQL
|
|
|
|
|
|
|
|
bots.each { |hash| hash["model_name"] = model_map[hash["id"]] }
|
2024-02-29 15:53:42 -05:00
|
|
|
mentionables = AiPersona.mentionables(user: scope.user)
|
|
|
|
if mentionables.present?
|
|
|
|
bots.concat(
|
|
|
|
mentionables.map do |mentionable|
|
|
|
|
{ "id" => mentionable[:user_id], "username" => mentionable[:username] }
|
|
|
|
end,
|
|
|
|
)
|
|
|
|
end
|
2023-08-16 16:29:58 -04:00
|
|
|
bots
|
|
|
|
end
|
|
|
|
|
2024-02-18 21:26:24 -05:00
|
|
|
plugin.add_to_serializer(:current_user, :can_use_assistant) do
|
|
|
|
scope.user.in_any_groups?(SiteSetting.ai_helper_allowed_groups_map)
|
|
|
|
end
|
|
|
|
|
|
|
|
plugin.add_to_serializer(:current_user, :can_use_assistant_in_post) do
|
|
|
|
scope.user.in_any_groups?(SiteSetting.post_ai_helper_allowed_groups_map)
|
|
|
|
end
|
|
|
|
|
|
|
|
plugin.add_to_serializer(:current_user, :can_use_custom_prompts) do
|
|
|
|
scope.user.in_any_groups?(SiteSetting.ai_helper_custom_prompts_allowed_groups_map)
|
|
|
|
end
|
|
|
|
|
2023-05-16 13:38:21 -04:00
|
|
|
plugin.register_svg_icon("robot")
|
|
|
|
|
2023-08-30 02:15:03 -04:00
|
|
|
plugin.add_to_serializer(
|
|
|
|
:topic_view,
|
|
|
|
:ai_persona_name,
|
|
|
|
include_condition: -> { SiteSetting.ai_bot_enabled && object.topic.private_message? },
|
FEATURE: UI to update ai personas on admin page (#290)
Introduces a UI to manage customizable personas (admin only feature)
Part of the change was some extensive internal refactoring:
- AIBot now has a persona set in the constructor, once set it never changes
- Command now takes in bot as a constructor param, so it has the correct persona and is not generating AIBot objects on the fly
- Added a .prettierignore file, due to the way ALE is configured in nvim it is a pre-req for prettier to work
- Adds a bunch of validations on the AIPersona model, system personas (artist/creative etc...) are all seeded. We now ensure
- name uniqueness, and only allow certain properties to be touched for system personas.
- (JS note) the client side design takes advantage of nested routes, the parent route for personas gets all the personas via this.store.findAll("ai-persona") then child routes simply reach into this model to find a particular persona.
- (JS note) data is sideloaded into the ai-persona model the meta property supplied from the controller, resultSetMeta
- This removes ai_bot_enabled_personas and ai_bot_enabled_chat_commands, both should be controlled from the UI on a per persona basis
- Fixes a long standing bug in token accounting ... we were doing to_json.length instead of to_json.to_s.length
- Amended it so {commands} are always inserted at the end unconditionally, no need to add it to the template of the system message as it just confuses things
- Adds a concept of required_commands to stock personas, these are commands that must be configured for this stock persona to show up.
- Refactored tests so we stop requiring inference_stubs, it was very confusing to need it, added to plugin.rb for now which at least is clearer
- Migrates the persona selector to gjs
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Co-authored-by: Martin Brennan <martin@discourse.org>
2023-11-21 00:56:43 -05:00
|
|
|
) do
|
|
|
|
id = topic.custom_fields["ai_persona_id"]
|
2024-01-04 08:44:07 -05:00
|
|
|
name =
|
|
|
|
DiscourseAi::AiBot::Personas::Persona.find_by(user: scope.user, id: id.to_i)&.name if id
|
FEATURE: UI to update ai personas on admin page (#290)
Introduces a UI to manage customizable personas (admin only feature)
Part of the change was some extensive internal refactoring:
- AIBot now has a persona set in the constructor, once set it never changes
- Command now takes in bot as a constructor param, so it has the correct persona and is not generating AIBot objects on the fly
- Added a .prettierignore file, due to the way ALE is configured in nvim it is a pre-req for prettier to work
- Adds a bunch of validations on the AIPersona model, system personas (artist/creative etc...) are all seeded. We now ensure
- name uniqueness, and only allow certain properties to be touched for system personas.
- (JS note) the client side design takes advantage of nested routes, the parent route for personas gets all the personas via this.store.findAll("ai-persona") then child routes simply reach into this model to find a particular persona.
- (JS note) data is sideloaded into the ai-persona model the meta property supplied from the controller, resultSetMeta
- This removes ai_bot_enabled_personas and ai_bot_enabled_chat_commands, both should be controlled from the UI on a per persona basis
- Fixes a long standing bug in token accounting ... we were doing to_json.length instead of to_json.to_s.length
- Amended it so {commands} are always inserted at the end unconditionally, no need to add it to the template of the system message as it just confuses things
- Adds a concept of required_commands to stock personas, these are commands that must be configured for this stock persona to show up.
- Refactored tests so we stop requiring inference_stubs, it was very confusing to need it, added to plugin.rb for now which at least is clearer
- Migrates the persona selector to gjs
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Co-authored-by: Martin Brennan <martin@discourse.org>
2023-11-21 00:56:43 -05:00
|
|
|
name || topic.custom_fields["ai_persona"]
|
|
|
|
end
|
2023-08-30 02:15:03 -04:00
|
|
|
|
2024-02-15 00:37:59 -05:00
|
|
|
plugin.on(:post_created) { |post| DiscourseAi::AiBot::Playground.schedule_reply(post) }
|
2023-10-11 18:14:19 -04:00
|
|
|
|
|
|
|
if plugin.respond_to?(:register_editable_topic_custom_field)
|
FEATURE: UI to update ai personas on admin page (#290)
Introduces a UI to manage customizable personas (admin only feature)
Part of the change was some extensive internal refactoring:
- AIBot now has a persona set in the constructor, once set it never changes
- Command now takes in bot as a constructor param, so it has the correct persona and is not generating AIBot objects on the fly
- Added a .prettierignore file, due to the way ALE is configured in nvim it is a pre-req for prettier to work
- Adds a bunch of validations on the AIPersona model, system personas (artist/creative etc...) are all seeded. We now ensure
- name uniqueness, and only allow certain properties to be touched for system personas.
- (JS note) the client side design takes advantage of nested routes, the parent route for personas gets all the personas via this.store.findAll("ai-persona") then child routes simply reach into this model to find a particular persona.
- (JS note) data is sideloaded into the ai-persona model the meta property supplied from the controller, resultSetMeta
- This removes ai_bot_enabled_personas and ai_bot_enabled_chat_commands, both should be controlled from the UI on a per persona basis
- Fixes a long standing bug in token accounting ... we were doing to_json.length instead of to_json.to_s.length
- Amended it so {commands} are always inserted at the end unconditionally, no need to add it to the template of the system message as it just confuses things
- Adds a concept of required_commands to stock personas, these are commands that must be configured for this stock persona to show up.
- Refactored tests so we stop requiring inference_stubs, it was very confusing to need it, added to plugin.rb for now which at least is clearer
- Migrates the persona selector to gjs
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Co-authored-by: Martin Brennan <martin@discourse.org>
2023-11-21 00:56:43 -05:00
|
|
|
plugin.register_editable_topic_custom_field(:ai_persona_id)
|
2023-10-11 18:14:19 -04:00
|
|
|
end
|
2023-05-05 14:28:31 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|