Compare commits

..
Author SHA1 Message Date
Sam Saffron 6351c401f8 work in progress adding roles to personas
# Conflicts:
#	app/models/ai_persona.rb
2024-05-01 15:39:13 +10:00
Sam Saffron acd3ac2371 minor fix to read ... complete is just confusing 2024-04-30 17:08:23 +10:00
Sam Saffron c61af76d86 Responder for categories 2024-04-30 17:08:23 +10:00
Sam Saffron cd7790f39a message responder backend now works 2024-04-30 17:08:21 +10:00
Sam Saffron 4fcf12287f work in progress adding roles to personas 2024-04-30 17:07:22 +10:00
161 changed files with 415 additions and 157 deletions
@@ -0,0 +1,7 @@
import DiscourseRoute from "discourse/routes/discourse";
export default DiscourseRoute.extend({
model() {
return this.modelFor("adminPlugins.show.discourse-ai.ai-personas");
},
});
@@ -17,7 +17,7 @@ export default DiscourseRoute.extend({
this._super(controller, model);
controller.set(
"allPersonas",
this.modelFor("adminPlugins.show.discourse-ai-personas")
this.modelFor("adminPlugins.show.discourse-ai.ai-personas")
);
},
});
@@ -3,7 +3,7 @@ import DiscourseRoute from "discourse/routes/discourse";
export default DiscourseRoute.extend({
async model(params) {
const allPersonas = this.modelFor(
"adminPlugins.show.discourse-ai-personas"
"adminPlugins.show.discourse-ai.ai-personas"
);
const id = parseInt(params.id, 10);
return allPersonas.findBy("id", id);
@@ -13,7 +13,7 @@ export default DiscourseRoute.extend({
this._super(controller, model);
controller.set(
"allPersonas",
this.modelFor("adminPlugins.show.discourse-ai-personas")
this.modelFor("adminPlugins.show.discourse-ai.ai-personas")
);
},
});
@@ -0,0 +1,12 @@
import { inject as service } from "@ember/service";
import DiscourseRoute from "discourse/routes/discourse";
export default class DiscourseAiIndexRoute extends DiscourseRoute {
@service router;
beforeModel() {
return this.router.transitionTo(
"adminPlugins.show.discourse-ai.ai-personas.index"
);
}
}
@@ -125,6 +125,7 @@ module DiscourseAi
:rag_chunk_overlap_tokens,
:rag_conversation_chunks,
:question_consolidator_llm,
:role,
allowed_group_ids: [],
rag_uploads: [:id],
)
+7 -1
View File
@@ -10,7 +10,13 @@ module ::Jobs
persona_id = args[:persona_id]
begin
persona = DiscourseAi::AiBot::Personas::Persona.find_by(user: post.user, id: persona_id)
persona =
if args[:skip_persona_security_check]
persona = AiPersona.all_personas.find { |persona| persona.id == persona_id }
else
persona = DiscourseAi::AiBot::Personas::Persona.find_by(user: post.user, id: persona_id)
end
raise DiscourseAi::AiBot::Bot::BOT_NOT_FOUND if persona.nil?
bot = DiscourseAi::AiBot::Bot.as(bot_user, persona: persona.new)
+66 -2
View File
@@ -46,6 +46,10 @@ class AiPersona < ActiveRecord::Base
.map(&:class_instance)
end
def self.persona_class_by_id(id)
AiPersona.all_personas.find { |persona| persona.id == id } if id
end
def self.persona_users(user: nil)
persona_users =
persona_cache[:persona_users] ||= AiPersona
@@ -72,6 +76,42 @@ class AiPersona < ActiveRecord::Base
end
end
def self.topic_responder_for(category_id:)
return nil if !category_id
all_responders =
persona_cache[:topic_responders] ||= AiPersona
.where(role: "topic_responder")
.where(enabled: true)
.pluck(:id, :role_category_ids)
id, _ = all_responders.find { |id, role_category_ids| role_category_ids.include?(category_id) }
if id
{ id: id }
else
nil
end
end
def self.message_responder_for(group_id: nil)
return nil if !group_id
all_responders =
persona_cache[:message_responders] ||= AiPersona
.where(role: "message_responder")
.where(enabled: true)
.pluck(:id, :role_group_ids)
id, _ = all_responders.find { |id, role_group_ids| role_group_ids.include?(group_id) }
if id
{ id: id }
else
nil
end
end
def self.mentionables(user: nil)
all_mentionables =
persona_cache[:mentionable_usernames] ||= AiPersona
@@ -114,6 +154,8 @@ class AiPersona < ActiveRecord::Base
vision_max_pixels = self.vision_max_pixels
rag_conversation_chunks = self.rag_conversation_chunks
question_consolidator_llm = self.question_consolidator_llm
role = self.role
role_whispers = self.role_whispers
persona_class = DiscourseAi::AiBot::Personas::Persona.system_personas_by_id[self.id]
if persona_class
@@ -161,6 +203,14 @@ class AiPersona < ActiveRecord::Base
rag_conversation_chunks
end
persona_class.define_singleton_method :role_whispers do
role_whispers
end
persona_class.define_singleton_method :role do
role
end
return persona_class
end
@@ -252,6 +302,14 @@ class AiPersona < ActiveRecord::Base
question_consolidator_llm
end
define_singleton_method :role do
role
end
define_singleton_method :role_whispers do
role_whispers
end
define_singleton_method :to_s do
"#<DiscourseAi::AiBot::Personas::Persona::Custom @name=#{self.name} @allowed_group_ids=#{self.allowed_group_ids.join(",")}>"
end
@@ -343,8 +401,8 @@ class AiPersona < ActiveRecord::Base
private
def system_persona_unchangeable
if top_p_changed? || temperature_changed? || system_prompt_changed? || commands_changed? ||
name_changed? || description_changed?
if role_changed? || top_p_changed? || temperature_changed? || system_prompt_changed? ||
commands_changed? || name_changed? || description_changed?
errors.add(:base, I18n.t("discourse_ai.ai_bot.personas.cannot_edit_system_persona"))
end
end
@@ -387,6 +445,12 @@ end
# rag_chunk_overlap_tokens :integer default(10), not null
# rag_conversation_chunks :integer default(10), not null
# question_consolidator_llm :text
# 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
#
# Indexes
#
@@ -23,7 +23,12 @@ class LocalizedAiPersonaSerializer < ApplicationSerializer
:rag_chunk_tokens,
:rag_chunk_overlap_tokens,
:rag_conversation_chunks,
:question_consolidator_llm
:question_consolidator_llm,
:role,
:role_tags,
:role_category_ids,
:role_whispers,
:role_max_responses_per_hour
has_one :user, serializer: BasicUserSerializer, embed: :object
has_many :rag_uploads, serializer: UploadSerializer, embed: :object
@@ -4,9 +4,11 @@ export default {
path: "/plugins",
map() {
this.route("discourse-ai-personas", { path: "ai-personas" }, function () {
this.route("new");
this.route("show", { path: "/:id" });
this.route("discourse-ai", { path: "/" }, function () {
this.route("ai-personas", function () {
this.route("new");
this.route("show", { path: "/:id" });
});
});
},
};
@@ -26,6 +26,9 @@ const CREATE_ATTRIBUTES = [
"rag_chunk_overlap_tokens",
"rag_conversation_chunks",
"question_consolidator_llm",
"role",
"role_category_ids",
"role_whispers",
];
const SYSTEM_ATTRIBUTES = [
@@ -23,6 +23,7 @@ import DTooltip from "float-kit/components/d-tooltip";
import AiCommandSelector from "./ai-command-selector";
import AiLlmSelector from "./ai-llm-selector";
import AiPersonaCommandOptions from "./ai-persona-command-options";
import RoleSelector from "./ai-persona-role-selector";
import PersonaRagUploader from "./persona-rag-uploader";
export default class PersonaEditor extends Component {
@@ -102,7 +103,7 @@ export default class PersonaEditor extends Component {
if (isNew && this.args.model.rag_uploads.length === 0) {
this.args.personas.addObject(this.args.model);
this.router.transitionTo(
"adminPlugins.show.discourse-ai-personas.show",
"adminPlugins.show.discourse-ai.ai-personas.show",
this.args.model
);
} else {
@@ -175,7 +176,7 @@ export default class PersonaEditor extends Component {
return this.args.model.destroyRecord().then(() => {
this.args.personas.removeObject(this.args.model);
this.router.transitionTo(
"adminPlugins.show.discourse-ai-personas.index"
"adminPlugins.show.discourse-ai.ai-personas.index"
);
});
},
@@ -265,7 +266,7 @@ export default class PersonaEditor extends Component {
<template>
<BackButton
@route="adminPlugins.show.discourse-ai-personas"
@route="adminPlugins.show.discourse-ai.ai-personas"
@label="discourse_ai.ai_persona.back"
/>
<form
@@ -336,6 +337,14 @@ export default class PersonaEditor extends Component {
disabled={{this.editingModel.system}}
/>
</div>
<div class="control-group ai-persona-editor__role">
<label>{{I18n.t "discourse_ai.ai_persona.role"}}</label>
<RoleSelector
class="ai-persona-editor__role_selctor"
@value={{this.editingModel.role}}
@disabled={{this.editingModel.system}}
/>
</div>
<div class="control-group">
<label>{{I18n.t "discourse_ai.ai_persona.default_llm"}}</label>
<AiLlmSelector
@@ -50,7 +50,7 @@ export default class AiPersonaListEditor extends Component {
<h3>{{i18n "discourse_ai.ai_persona.short_title"}}</h3>
{{#unless @currentPersona.isNew}}
<LinkTo
@route="adminPlugins.show.discourse-ai-personas.new"
@route="adminPlugins.show.discourse-ai.ai-personas.new"
class="btn btn-small btn-primary"
>
{{icon "plus"}}
@@ -105,7 +105,7 @@ export default class AiPersonaListEditor extends Component {
</td>
<td>
<LinkTo
@route="adminPlugins.show.discourse-ai-personas.show"
@route="adminPlugins.show.discourse-ai.ai-personas.show"
@model={{persona}}
class="btn btn-text btn-small"
>{{i18n "discourse_ai.ai_persona.edit"}} </LinkTo>
@@ -0,0 +1,26 @@
import { computed, observer } from "@ember/object";
import I18n from "discourse-i18n";
import ComboBox from "select-kit/components/combo-box";
export default ComboBox.extend({
_modelDisabledChanged: observer("attrs.disabled", function () {
this.selectKit.options.set("disabled", this.get("attrs.disabled.value"));
}),
content: computed(function () {
return [
{
id: "bot",
name: I18n.t("discourse_ai.ai_persona.role_options.bot"),
},
{
id: "message_responder",
name: I18n.t("discourse_ai.ai_persona.role_options.message_responder"),
},
];
}),
selectKitOptions: {
filterable: false,
},
});
@@ -0,0 +1 @@
<AiPersonaListEditor @personas={{this.model}} />
@@ -0,0 +1 @@
<AiPersonaListEditor @personas={{this.model}} />
@@ -12,9 +12,13 @@ export default {
withPluginApi("1.1.0", (api) => {
api.addAdminPluginConfigurationNav("discourse-ai", PLUGIN_NAV_MODE_TOP, [
{
label: "admin.plugins.change_settings_short",
route: "adminPlugins.show.settings",
},
{
label: "discourse_ai.ai_persona.short_title",
route: "adminPlugins.show.discourse-ai-personas",
route: "adminPlugins.show.discourse-ai.ai-personas",
},
]);
});
+4 -5
View File
@@ -144,11 +144,9 @@ de:
create_user_help: Du kannst dieser Persona optional einen Benutzer zuordnen. Wenn du das tust, wird die KI diesen Benutzer verwenden, um auf Anfragen zu antworten.
default_llm: Standard-Sprachmodell
default_llm_help: Das Standard-Sprachmodell, das für diese Persona verwendet werden soll. Erforderlich, wenn du die Persona in öffentlichen Beiträgen erwähnen möchtest.
question_consolidator_llm: Sprachmodell für Fragenkonsolidierer
question_consolidator_llm_help: Das Sprachmodell, das für den Fragenkonsolidierer verwendet werden soll. Du kannst ein weniger leistungsfähiges Modell wählen, um Kosten zu sparen.
system_prompt: System-Eingabeaufforderung
show_indexing_options: "Upload-Optionen anzeigen"
hide_indexing_options: "Upload-Optionen ausblenden"
show_indexing_options: "Indizierungsoptionen anzeigen"
hide_indexing_options: "Indizierungsoptionen ausblenden"
save: Speichern
saved: KI-Persona gespeichert
enabled: "Aktiviert?"
@@ -185,7 +183,8 @@ de:
Außerdem kannst du ihn so einrichten, dass bestimmte Benutzergruppen Zugriff auf bestimmte Personas haben. Das bedeutet, dass Sie für verschiedene Bereiche Ihres Forums unterschiedliche KI-Verhaltensweisen verwenden können, was die Vielfalt und den Reichtum der Interaktionen Ihrer Community weiter verbessert.
uploads:
title: "Uploads"
description: "Deine KI-Persona wird in der Lage sein, den Inhalt der enthaltenen Dateien zu durchsuchen und zu referenzieren. Hochgeladene Dateien sollten als Plaintext (.txt) oder Markdown (.md) formatiert sein."
description: "Deine KI-Persona wird in der Lage sein, den Inhalt der enthaltenen Dateien zu durchsuchen und zu referenzieren. Hochgeladene Dateien müssen als Klartext (.txt) formatiert sein."
hint: "Um zu kontrollieren, wo der Inhalt der Datei in der System-Eingabeaufforderung platziert wird, füge den Platzhalter {uploads} in die obige System-Eingabeaufforderung ein."
button: "Dateien hinzufügen"
filter: "Uploads filtern"
indexed: "Indiziert"
+4
View File
@@ -137,6 +137,10 @@ en:
mentionable: Mentionable
mentionable_help: If enabled, users in allowed groups can mention this user in posts and messages, the AI will respond as this persona.
user: User
role: Role
role_options:
bot: Bot
message_responder: Message Responder
create_user: Create User
create_user_help: You can optionally attach a user to this persona. If you do, the AI will use this user to respond to requests.
default_llm: Default Language Model
+2 -5
View File
@@ -144,11 +144,9 @@ he:
create_user_help: אפשר לצרף משתמש לדמות הזאת כרשות. אם האפשרות הזאת תסומן, הבינה המלאכותית תשתמש במשתמש הזה כדי להגיב לבקשות.
default_llm: דגם שפה כברירת מחדל
default_llm_help: דגם ברירת המחדל לשימוש לדמות הזאת. נחוץ כדי לאזכר דמות בפוסטים ציבוריים.
question_consolidator_llm: מודל שפה למגבש השאלות
question_consolidator_llm_help: מודל השפה לשימוש עבור מגבש השאלות, אפשר לבחור במודל פחות חזק כדי לחסוך בעלויות.
system_prompt: בקשת מערכת
show_indexing_options: "הצגת אפשרויות העלאה"
hide_indexing_options: "הסתרת אפשרויות העלאה"
show_indexing_options: "הצגת אפשרויות סידור במפתח"
hide_indexing_options: "הסתרת אפשרויות סידור במפתח"
save: שמירה
saved: דמות בינה מלאכותית נשמרה
enabled: "מאופשר?"
@@ -182,7 +180,6 @@ he:
יתרה מכך, אפשר להגדיר אותה כך שרק לקבוצות מסוימות תהיינה גישה לדמויות מסוימות. משמעות הדבר היא שאפשר לנהל התנהגויות שונות לבינה המלאכותית לאזורים שונים בפורום שלך, ובכך להרחיב את הגיוון ואת העושר של ההתנהלות בקהילה שלך.
uploads:
title: "העלאות"
description: "דמות הבינה המלאכותית שלך תוכל לחפש ולהפנות לתוכן של קבצים כלולים. קבצים שהועלו אמורים להיות בתסדירי טקסט פשוט (‎.txt) או markdown‏ (‎.md)."
button: "הוספת קבצים"
filter: "סינון העלאות"
indexed: "סודר במפתח"
-5
View File
@@ -107,15 +107,10 @@ id:
edit: Ubah
description: Deskripsi
user: Pengguna
question_consolidator_llm: Model Bahasa untuk Konsolidator Pertanyaan
question_consolidator_llm_help: Model bahasa yang digunakan untuk konsolidator pertanyaan, Anda dapat memilih model yang kurang kuat untuk menghemat biaya.
show_indexing_options: "Tampilkan Opsi Unggah"
hide_indexing_options: "Sembunyikan Opsi Unggah"
save: Simpan
enabled: "Diaktifkan?"
delete: Hapus
uploads:
description: "Persona AI Anda akan dapat mencari dan mereferensikan konten file yang disertakan. File yang diunggah harus diformat sebagai teks biasa (.txt) atau markdown (.md)."
uploading: "Mengunggah..."
ai_helper:
missing_content: "Silakan masukkan beberapa konten untuk menghasilkan saran."
+2
View File
@@ -170,6 +170,8 @@ tr_TR:
Dahası, belirli kullanıcı gruplarının belirli kişiliklere erişime sahip olacak şekilde de belirleyebilirsiniz. Bu, forumunuzun farklı bölümleri için farklı YZ davranışlarına sahip olabileceğiniz anlamına gelir ve böylece topluluğunuzun etkileşimlerinin çeşitliliğini ve zenginliğini geliştirebilirsiniz.
uploads:
title: "Yüklemeler"
description: "Yapay zeka personanız, dahil edilen dosyaların içeriğini arayabilecek ve referans verebilecektir. Yüklenen dosyalar düz metin (.txt) olarak biçimlendirilmelidir"
hint: "Dosyanın içeriğinin sistem isteminde nereye yerleştirileceğini kontrol etmek için, yukarıdaki sistem istemine {uploads} yer tutucusunu ekleyin."
button: "Dosya Ekle"
filter: "Yüklemeleri filtrele"
uploading: "Yükleniyor..."
@@ -0,0 +1,14 @@
# frozen_string_literal: true
class AddRoleToAiPersona < ActiveRecord::Migration[7.0]
def change
create_enum :ai_persona_role, %w[bot topic_responder message_responder summarizer]
add_column :ai_personas, :role, :enum, default: "bot", null: false, enum_type: :ai_persona_role
add_column :ai_personas, :role_category_ids, :integer, array: true, default: [], null: false
add_column :ai_personas, :role_tags, :string, array: true, default: [], null: false
add_column :ai_personas, :role_group_ids, :integer, array: true, default: [], null: false
add_column :ai_personas, :role_whispers, :boolean, default: false, null: false
add_column :ai_personas, :role_max_responses_per_hour, :integer, default: 50, null: false
end
end

Some files were not shown because too many files have changed in this diff Show More