Skip to content

Commit

Permalink
Track enabled bots with attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
romanrizzi committed Jun 17, 2024
1 parent 0c58b37 commit a38a3af
Show file tree
Hide file tree
Showing 36 changed files with 221 additions and 182 deletions.
1 change: 1 addition & 0 deletions app/controllers/discourse_ai/admin/ai_llms_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def ai_llm_params
:url,
:api_key,
:bot_username,
:enabled_chat_bot,
)
end
end
Expand Down
60 changes: 26 additions & 34 deletions app/models/ai_persona.rb
Original file line number Diff line number Diff line change
Expand Up @@ -252,40 +252,32 @@ def ensure_not_system
#
# Table name: ai_personas
#
# id :bigint not null, primary key
# name :string(100) not null
# description :string(2000) not null
# tools :json not null
# system_prompt :string(10000000) not null
# allowed_group_ids :integer default([]), not null, is an Array
# created_by_id :integer
# enabled :boolean default(TRUE), not null
# created_at :datetime not null
# updated_at :datetime not null
# system :boolean default(FALSE), not null
# priority :boolean default(FALSE), not null
# temperature :float
# top_p :float
# user_id :integer
# mentionable :boolean default(FALSE), not null
# default_llm :text
# max_context_posts :integer
# max_post_context_tokens :integer
# max_context_tokens :integer
# vision_enabled :boolean default(FALSE), not null
# vision_max_pixels :integer default(1048576), not null
# rag_chunk_tokens :integer default(374), not null
# rag_chunk_overlap_tokens :integer default(10), not null
# rag_conversation_chunks :integer default(10), not null
# role :enum default("bot"), not null
# role_category_ids :integer default([]), not null, is an Array
# role_tags :string default([]), not null, is an Array
# role_group_ids :integer default([]), not null, is an Array
# role_whispers :boolean default(FALSE), not null
# role_max_responses_per_hour :integer default(50), not null
# question_consolidator_llm :text
# allow_chat :boolean default(FALSE), not null
# tool_details :boolean default(TRUE), not null
# id :bigint not null, primary key
# name :string(100) not null
# description :string(2000) not null
# system_prompt :string(10000000) not null
# allowed_group_ids :integer default([]), not null, is an Array
# created_by_id :integer
# enabled :boolean default(TRUE), not null
# created_at :datetime not null
# updated_at :datetime not null
# system :boolean default(FALSE), not null
# priority :boolean default(FALSE), not null
# temperature :float
# top_p :float
# user_id :integer
# mentionable :boolean default(FALSE), not null
# default_llm :text
# max_context_posts :integer
# vision_enabled :boolean default(FALSE), not null
# vision_max_pixels :integer default(1048576), not null
# rag_chunk_tokens :integer default(374), not null
# rag_chunk_overlap_tokens :integer default(10), not null
# rag_conversation_chunks :integer default(10), not null
# question_consolidator_llm :text
# allow_chat :boolean default(FALSE), not null
# tool_details :boolean default(TRUE), not null
# tools :json not null
#
# Indexes
#
Expand Down
4 changes: 2 additions & 2 deletions app/models/chat_message_custom_prompt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class ChatMessageCustomPrompt < ActiveRecord::Base

# == Schema Information
#
# Table name: message_custom_prompts
# Table name: chat_message_custom_prompts
#
# id :bigint not null, primary key
# message_id :bigint not null
Expand All @@ -16,5 +16,5 @@ class ChatMessageCustomPrompt < ActiveRecord::Base
#
# Indexes
#
# index_message_custom_prompts_on_message_id (message_id) UNIQUE
# index_chat_message_custom_prompts_on_message_id (message_id) UNIQUE
#
46 changes: 46 additions & 0 deletions app/models/llm_model.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,51 @@
# frozen_string_literal: true

class LlmModel < ActiveRecord::Base
FIRST_BOT_USER_ID = -1200

belongs_to :user

def toggle_companion_user
return if bot_username == "fake" && Rails.env.production?

enable_check = SiteSetting.ai_bot_enabled && enabled_chat_bot

if enable_check
if !user
next_id = DB.query_single(<<~SQL).first
SELECT min(id) - 1 FROM users
SQL

new_user =
User.new(
id: [FIRST_BOT_USER_ID, next_id].min,
email: "no_email_#{bot_username}",
name: bot_username.titleize,
username: UserNameSuggester.suggest(bot_username),
active: true,
approved: true,
admin: true,
moderator: true,
trust_level: TrustLevel[4],
)
new_user.save!(validate: false)
self.update!(user: new_user)
else
user.update!(active: true)
end
elsif user
# will include deleted
has_posts = DB.query_single("SELECT 1 FROM posts WHERE user_id = #{user.id} LIMIT 1").present?

if has_posts
user.update!(active: false) if user.active
else
user.destroy!
self.update!(user: nil)
end
end
end

def tokenizer_class
tokenizer.constantize
end
Expand All @@ -22,4 +65,7 @@ def tokenizer_class
# updated_at :datetime not null
# url :string
# api_key :string
# bot_username :string
# user_id :integer
# enabled_chat_bot :boolean default(FALSE), not null
#
3 changes: 2 additions & 1 deletion assets/javascripts/discourse/admin/models/ai-llm.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export default class AiLlm extends RestModel {
"max_prompt_tokens",
"url",
"api_key",
"bot_username"
"bot_username",
"enabled_chat_bot"
);
}

Expand Down
10 changes: 6 additions & 4 deletions assets/javascripts/discourse/components/ai-bot-header-icon.gjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import i18n from "discourse-common/helpers/i18n";
import { composeAiBotMessage } from "../lib/ai-bot-helper";

export default class AiBotHeaderIcon extends Component {
@service siteSettings;
@service currentUser;
@service composer;

get bots() {
return this.siteSettings.ai_bot_add_to_header
? this.siteSettings.ai_bot_enabled_chat_bots.split("|").filter(Boolean)
: [];
const availableBots = this.currentUser.ai_enabled_chat_bots
.filter((bot) => !bot.is_persosna)
.filter(Boolean);

return availableBots ? availableBots.map((bot) => bot.model_name) : [];
}

@action
Expand Down
26 changes: 25 additions & 1 deletion assets/javascripts/discourse/components/ai-llm-editor.gjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { Input } from "@ember/component";
import { on } from "@ember/modifier";
import { action } from "@ember/object";
import { later } from "@ember/runloop";
import { inject as service } from "@ember/service";
import BackButton from "discourse/components/back-button";
import DButton from "discourse/components/d-button";
import DToggleSwitch from "discourse/components/d-toggle-switch";
import { popupAjaxError } from "discourse/lib/ajax-error";
import icon from "discourse-common/helpers/d-icon";
import i18n from "discourse-common/helpers/i18n";
Expand Down Expand Up @@ -110,6 +112,21 @@ export default class AiLlmEditor extends Component {
});
}

@action
async toggleEnabledChatBot() {
this.args.model.set("enabled_chat_bot", !this.args.model.enabled_chat_bot);
if (!this.args.model.isNew) {
try {
await this.args.model.update({
enabled_chat_bot: this.args.model.enabled_chat_bot,
});
} catch (e) {
popupAjaxError(e);
}
}
await this.toggleField("enabled_chat_bot", true);
}

<template>
<BackButton
@route="adminPlugins.show.discourse-ai-llms"
Expand Down Expand Up @@ -193,7 +210,14 @@ export default class AiLlmEditor extends Component {
@content={{I18n.t "discourse_ai.llms.hints.companion_bot_username"}}
/>
</div>

<div class="control-group">
<DToggleSwitch
class="ai-llm-editor__enabled-chat-bot"
@state={{@model.enabled_chat_bot}}
@label="discourse_ai.llms.enabled_chat_bot"
{{on "click" this.toggleEnabledChatBot}}
/>
</div>
<div class="control-group ai-llm-editor__action_panel">
<DButton
class="ai-llm-editor__test"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { hash } from "@ember/helper";
import { next } from "@ember/runloop";
import { inject as service } from "@ember/service";
import KeyValueStore from "discourse/lib/key-value-store";
import I18n from "I18n";
import DropdownSelectBox from "select-kit/components/dropdown-select-box";

function isBotMessage(composer, currentUser) {
Expand Down Expand Up @@ -110,15 +109,16 @@ export default class BotSelector extends Component {
}

get llmOptions() {
return this.siteSettings.ai_bot_enabled_chat_bots
.split("|")
.filter(Boolean)
.map((bot) => {
return {
id: bot,
name: I18n.t(`discourse_ai.ai_bot.bot_names.${bot}`),
};
});
const availableBots = this.currentUser.ai_enabled_chat_bots
.filter((bot) => !bot.is_persosna)
.filter(Boolean);

return availableBots.map((bot) => {
return {
id: bot.model_name,
name: bot.display_name,
};
});
}

<template>
Expand Down
3 changes: 2 additions & 1 deletion config/locales/client.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ en:
url: "URL of the service hosting the model"
api_key: "API Key of the service hosting the model"
companion_bot_username: "Companion user's username"
enabled_chat_bot: "Allow Companion user to act as an AI Bot"
save: "Save"
edit: "Edit"
saved: "LLM Model Saved"
Expand All @@ -227,7 +228,7 @@ en:
hints:
max_prompt_tokens: "Max numbers of tokens for the prompt. As a rule of thumb, this should be 50% of the model's context window."
name: "We include this in the API call to specify which model we'll use."
companion_bot_username: "Features like the AI Bot create an user with this username for users to interact with."
companion_bot_username: "Some features, like the AI Bot, set up a companion user account other users can interact with. Set this companion user's username here."

providers:
aws_bedrock: "AWS Bedrock"
Expand Down
3 changes: 0 additions & 3 deletions config/locales/server.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,6 @@ en:
disable_module_first: "You have to disable %{setting} first."
set_llm_first: "Set %{setting} first."
model_unreachable: "We couldn't get a response from this model. Check your settings first."
configure_llm:
one: "We couldn't find an LLM with the name %{models}. Go to the plugin's LLMs section to set it up."
other: "We couldn't find configured LLMs with these names: %{models}. Go to the plugin's LLMs section to set them up."
endpoints:
not_configured: "%{display_name} (not configured)"
configuration_hint:
Expand Down
7 changes: 3 additions & 4 deletions config/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,10 @@ discourse_ai:
default: "1|2" # 1: admins, 2: moderators
allow_any: false
refresh: true
ai_bot_enabled_chat_bots: # TODO(roman): Make this dynamic
ai_bot_enabled_chat_bots: # TODO(roman): Remove setting. Deprecated
type: list
default: ""
client: true
validator: "DiscourseAi::Configuration::LlmModelValidator"
"gpt-3.5-turbo"
hidden: true
choices: "DiscourseAi::Configuration::LlmEnumerator.available_ai_bots"
ai_bot_add_to_header:
default: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ class AddCompanionUserToLlmModel < ActiveRecord::Migration[7.0]
def change
add_column :llm_models, :bot_username, :string
add_column :llm_models, :user_id, :integer
add_column :llm_models, :enabled_chat_bot, :boolean, null: false, default: false
end
end
Loading

0 comments on commit a38a3af

Please sign in to comment.