Skip to content

Commit 3211265

Browse files
committed
Track enabled bots with attribute
1 parent 0c58b37 commit 3211265

35 files changed

+213
-142
lines changed

app/controllers/discourse_ai/admin/ai_llms_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ def ai_llm_params
107107
:url,
108108
:api_key,
109109
:bot_username,
110+
:enabled_chat_bot,
110111
)
111112
end
112113
end

app/models/ai_persona.rb

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -252,40 +252,32 @@ def ensure_not_system
252252
#
253253
# Table name: ai_personas
254254
#
255-
# id :bigint not null, primary key
256-
# name :string(100) not null
257-
# description :string(2000) not null
258-
# tools :json not null
259-
# system_prompt :string(10000000) not null
260-
# allowed_group_ids :integer default([]), not null, is an Array
261-
# created_by_id :integer
262-
# enabled :boolean default(TRUE), not null
263-
# created_at :datetime not null
264-
# updated_at :datetime not null
265-
# system :boolean default(FALSE), not null
266-
# priority :boolean default(FALSE), not null
267-
# temperature :float
268-
# top_p :float
269-
# user_id :integer
270-
# mentionable :boolean default(FALSE), not null
271-
# default_llm :text
272-
# max_context_posts :integer
273-
# max_post_context_tokens :integer
274-
# max_context_tokens :integer
275-
# vision_enabled :boolean default(FALSE), not null
276-
# vision_max_pixels :integer default(1048576), not null
277-
# rag_chunk_tokens :integer default(374), not null
278-
# rag_chunk_overlap_tokens :integer default(10), not null
279-
# rag_conversation_chunks :integer default(10), not null
280-
# role :enum default("bot"), not null
281-
# role_category_ids :integer default([]), not null, is an Array
282-
# role_tags :string default([]), not null, is an Array
283-
# role_group_ids :integer default([]), not null, is an Array
284-
# role_whispers :boolean default(FALSE), not null
285-
# role_max_responses_per_hour :integer default(50), not null
286-
# question_consolidator_llm :text
287-
# allow_chat :boolean default(FALSE), not null
288-
# tool_details :boolean default(TRUE), not null
255+
# id :bigint not null, primary key
256+
# name :string(100) not null
257+
# description :string(2000) not null
258+
# system_prompt :string(10000000) not null
259+
# allowed_group_ids :integer default([]), not null, is an Array
260+
# created_by_id :integer
261+
# enabled :boolean default(TRUE), not null
262+
# created_at :datetime not null
263+
# updated_at :datetime not null
264+
# system :boolean default(FALSE), not null
265+
# priority :boolean default(FALSE), not null
266+
# temperature :float
267+
# top_p :float
268+
# user_id :integer
269+
# mentionable :boolean default(FALSE), not null
270+
# default_llm :text
271+
# max_context_posts :integer
272+
# vision_enabled :boolean default(FALSE), not null
273+
# vision_max_pixels :integer default(1048576), not null
274+
# rag_chunk_tokens :integer default(374), not null
275+
# rag_chunk_overlap_tokens :integer default(10), not null
276+
# rag_conversation_chunks :integer default(10), not null
277+
# question_consolidator_llm :text
278+
# allow_chat :boolean default(FALSE), not null
279+
# tool_details :boolean default(TRUE), not null
280+
# tools :json not null
289281
#
290282
# Indexes
291283
#

app/models/chat_message_custom_prompt.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class ChatMessageCustomPrompt < ActiveRecord::Base
66

77
# == Schema Information
88
#
9-
# Table name: message_custom_prompts
9+
# Table name: chat_message_custom_prompts
1010
#
1111
# id :bigint not null, primary key
1212
# message_id :bigint not null
@@ -16,5 +16,5 @@ class ChatMessageCustomPrompt < ActiveRecord::Base
1616
#
1717
# Indexes
1818
#
19-
# index_message_custom_prompts_on_message_id (message_id) UNIQUE
19+
# index_chat_message_custom_prompts_on_message_id (message_id) UNIQUE
2020
#

app/models/llm_model.rb

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,51 @@
11
# frozen_string_literal: true
22

33
class LlmModel < ActiveRecord::Base
4+
FIRST_BOT_USER_ID = -1200
5+
46
belongs_to :user
57

8+
def toggle_companion_user
9+
return if bot_username == "fake" && Rails.env.production?
10+
11+
enable_check = SiteSetting.ai_bot_enabled && enabled_chat_bot
12+
13+
if enable_check
14+
if !user
15+
next_id = DB.query_single(<<~SQL).first
16+
SELECT min(id) - 1 FROM users
17+
SQL
18+
19+
new_user =
20+
User.new(
21+
id: [FIRST_BOT_USER_ID, next_id].min,
22+
email: "no_email_#{bot_username}",
23+
name: bot_username.titleize,
24+
username: UserNameSuggester.suggest(bot_username),
25+
active: true,
26+
approved: true,
27+
admin: true,
28+
moderator: true,
29+
trust_level: TrustLevel[4],
30+
)
31+
new_user.save!(validate: false)
32+
self.update!(user: new_user)
33+
else
34+
user.update!(active: true)
35+
end
36+
elsif user
37+
# will include deleted
38+
has_posts = DB.query_single("SELECT 1 FROM posts WHERE user_id = #{user.id} LIMIT 1").present?
39+
40+
if has_posts
41+
user.update!(active: false) if user.active
42+
else
43+
user.destroy!
44+
self.update!(user: nil)
45+
end
46+
end
47+
end
48+
649
def tokenizer_class
750
tokenizer.constantize
851
end
@@ -22,4 +65,7 @@ def tokenizer_class
2265
# updated_at :datetime not null
2366
# url :string
2467
# api_key :string
68+
# bot_username :string
69+
# user_id :integer
70+
# enabled_chat_bot :boolean default(FALSE), not null
2571
#

assets/javascripts/discourse/admin/models/ai-llm.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ export default class AiLlm extends RestModel {
1212
"max_prompt_tokens",
1313
"url",
1414
"api_key",
15-
"bot_username"
15+
"bot_username",
16+
"enabled_chat_bot"
1617
);
1718
}
1819

assets/javascripts/discourse/components/ai-bot-header-icon.gjs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import i18n from "discourse-common/helpers/i18n";
77
import { composeAiBotMessage } from "../lib/ai-bot-helper";
88

99
export default class AiBotHeaderIcon extends Component {
10-
@service siteSettings;
10+
@service currentUser;
1111
@service composer;
1212

1313
get bots() {
14-
return this.siteSettings.ai_bot_add_to_header
15-
? this.siteSettings.ai_bot_enabled_chat_bots.split("|").filter(Boolean)
16-
: [];
14+
const availableBots = this.currentUser.ai_enabled_chat_bots
15+
.filter((bot) => !bot.is_persosna)
16+
.filter(Boolean);
17+
18+
return availableBots ? availableBots.map((bot) => bot.model_name) : [];
1719
}
1820

1921
@action

assets/javascripts/discourse/components/ai-llm-editor.gjs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import i18n from "discourse-common/helpers/i18n";
1212
import I18n from "discourse-i18n";
1313
import ComboBox from "select-kit/components/combo-box";
1414
import DTooltip from "float-kit/components/d-tooltip";
15+
import DToggleSwitch from "discourse/components/d-toggle-switch";
16+
import { on } from "@ember/modifier";
1517

1618
export default class AiLlmEditor extends Component {
1719
@service toasts;
@@ -110,6 +112,21 @@ export default class AiLlmEditor extends Component {
110112
});
111113
}
112114

115+
@action
116+
async toggleEnabledChatBot() {
117+
this.args.model.set("enabled_chat_bot", !this.args.model.enabled_chat_bot);
118+
if (!this.args.model.isNew) {
119+
try {
120+
await this.args.model.update({
121+
enabled_chat_bot: this.args.model.enabled_chat_bot,
122+
});
123+
} catch (e) {
124+
popupAjaxError(e);
125+
}
126+
}
127+
await this.toggleField("enabled_chat_bot", true);
128+
}
129+
113130
<template>
114131
<BackButton
115132
@route="adminPlugins.show.discourse-ai-llms"
@@ -193,7 +210,14 @@ export default class AiLlmEditor extends Component {
193210
@content={{I18n.t "discourse_ai.llms.hints.companion_bot_username"}}
194211
/>
195212
</div>
196-
213+
<div class="control-group">
214+
<DToggleSwitch
215+
class="ai-llm-editor__enabled-chat-bot"
216+
@state={{@model.enabled_chat_bot}}
217+
@label="discourse_ai.llms.enabled_chat_bot"
218+
{{on "click" this.toggleEnabledChatBot}}
219+
/>
220+
</div>
197221
<div class="control-group ai-llm-editor__action_panel">
198222
<DButton
199223
class="ai-llm-editor__test"

assets/javascripts/discourse/connectors/composer-fields/persona-llm-selector.gjs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,15 @@ export default class BotSelector extends Component {
110110
}
111111

112112
get llmOptions() {
113-
return this.siteSettings.ai_bot_enabled_chat_bots
114-
.split("|")
115-
.filter(Boolean)
113+
const availableBots = this.currentUser.ai_enabled_chat_bots
114+
.filter((bot) => !bot.is_persosna)
115+
.filter(Boolean);
116+
117+
return availableBots
116118
.map((bot) => {
117119
return {
118-
id: bot,
119-
name: I18n.t(`discourse_ai.ai_bot.bot_names.${bot}`),
120+
id: bot.model_name,
121+
name: bot.model_name,
120122
};
121123
});
122124
}

config/locales/client.en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ en:
211211
url: "URL of the service hosting the model"
212212
api_key: "API Key of the service hosting the model"
213213
companion_bot_username: "Companion user's username"
214+
enabled_chat_bot: "Allow Companion user to act as an AI Bot"
214215
save: "Save"
215216
edit: "Edit"
216217
saved: "LLM Model Saved"

config/settings.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,10 @@ discourse_ai:
349349
default: "1|2" # 1: admins, 2: moderators
350350
allow_any: false
351351
refresh: true
352-
ai_bot_enabled_chat_bots: # TODO(roman): Make this dynamic
352+
ai_bot_enabled_chat_bots: # TODO(roman): Remove setting. Deprecated
353353
type: list
354354
default: ""
355-
client: true
355+
hidden: true
356356
validator: "DiscourseAi::Configuration::LlmModelValidator"
357357
choices: "DiscourseAi::Configuration::LlmEnumerator.available_ai_bots"
358358
ai_bot_add_to_header:

db/migrate/20240528132059_add_companion_user_to_llm_model.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ class AddCompanionUserToLlmModel < ActiveRecord::Migration[7.0]
44
def change
55
add_column :llm_models, :bot_username, :string
66
add_column :llm_models, :user_id, :integer
7+
add_column :llm_models, :enabled_chat_bot, :boolean, null: false, default: false
78
end
89
end

db/post_migrate/20240528144216_seed_open_ai_models.rb

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ def up
55
models = []
66

77
open_ai_api_key = fetch_setting("ai_openai_api_key")
8+
enabled_models = fetch_setting("ai_bot_enabled_chat_bots").to_a.split("|")
89

910
if open_ai_api_key.present?
1011
models << mirror_open_ai(
@@ -15,6 +16,7 @@ def up
1516
open_ai_api_key,
1617
"gpt3.5_bot",
1718
-111,
19+
enabled_models,
1820
)
1921
models << mirror_open_ai(
2022
"GPT-3.5 Turbo 16K",
@@ -24,6 +26,7 @@ def up
2426
open_ai_api_key,
2527
"gpt3.5_bot",
2628
-111,
29+
enabled_models,
2730
)
2831
models << mirror_open_ai(
2932
"GPT-4",
@@ -33,6 +36,7 @@ def up
3336
open_ai_api_key,
3437
"gpt4_bot",
3538
-110,
39+
enabled_models,
3640
)
3741
models << mirror_open_ai(
3842
"GPT-4 32K",
@@ -42,6 +46,7 @@ def up
4246
open_ai_api_key,
4347
"gpt4_bot",
4448
-110,
49+
enabled_models,
4550
)
4651
models << mirror_open_ai(
4752
"GPT-4 Turbo",
@@ -51,6 +56,7 @@ def up
5156
open_ai_api_key,
5257
"gpt4t_bot",
5358
-113,
59+
enabled_models,
5460
)
5561
models << mirror_open_ai(
5662
"GPT-4o",
@@ -60,14 +66,15 @@ def up
6066
open_ai_api_key,
6167
"gpt4o_bot",
6268
-121,
69+
enabled_models,
6370
)
6471
end
6572

6673
if models.present?
6774
rows = models.compact.join(",")
6875

6976
DB.exec(<<~SQL, rows: rows) if rows.present?
70-
INSERT INTO llm_models (display_name, name, provider, tokenizer, max_prompt_tokens, url, api_key, bot_username, user_id, created_at, updated_at)
77+
INSERT INTO llm_models (display_name, name, provider, tokenizer, max_prompt_tokens, url, api_key, bot_username, user_id, enabled_chat_bot, created_at, updated_at)
7178
VALUES :rows;
7279
SQL
7380
end
@@ -84,13 +91,23 @@ def fetch_setting(name)
8491
).first
8592
end
8693

87-
def mirror_open_ai(display_name, name, max_prompt_tokens, setting_name, key, bot_username, bot_id)
94+
def mirror_open_ai(
95+
display_name,
96+
name,
97+
max_prompt_tokens,
98+
setting_name,
99+
key,
100+
bot_username,
101+
bot_id,
102+
enabled_models
103+
)
88104
url = fetch_setting(setting_name)
89105

90106
user_id = has_companion_user?(bot_id) ? bot_id : "NULL"
91107

92108
if url
93-
"(#{name.titleize}, #{name}, open_ai, OpenAiTokenizer, #{max_prompt_tokens}, #{url}, #{key}, #{bot_username}, #{user_id}, NOW(), NOW())"
109+
enabled = enabled_models.include?(name)
110+
"(#{name.titleize}, #{name}, open_ai, OpenAiTokenizer, #{max_prompt_tokens}, #{url}, #{key}, #{bot_username}, #{user_id}, #{enabled}, NOW(), NOW())"
94111
end
95112
end
96113

0 commit comments

Comments
 (0)