FEATURE: optional tool detail blocks (#662)
This is a rather huge refactor with 1 new feature (tool details can be suppressed) Previously we use the name "Command" to describe "Tools", this unifies all the internal language and simplifies the code. We also amended the persona UI to use less DToggles which aligns with our design guidelines. Co-authored-by: Martin Brennan <martin@discourse.org>
This commit is contained in:
parent
875bb04467
commit
52a7dd2a4b
|
@ -23,7 +23,7 @@ module DiscourseAi
|
|||
DiscourseAi::Configuration::LlmEnumerator.values.map do |hash|
|
||||
{ id: hash[:value], name: hash[:name] }
|
||||
end
|
||||
render json: { ai_personas: ai_personas, meta: { commands: tools, llms: llms } }
|
||||
render json: { ai_personas: ai_personas, meta: { tools: tools, llms: llms } }
|
||||
end
|
||||
|
||||
def show
|
||||
|
@ -126,28 +126,29 @@ module DiscourseAi
|
|||
:rag_conversation_chunks,
|
||||
:question_consolidator_llm,
|
||||
:allow_chat,
|
||||
:tool_details,
|
||||
allowed_group_ids: [],
|
||||
rag_uploads: [:id],
|
||||
)
|
||||
|
||||
if commands = params.dig(:ai_persona, :commands)
|
||||
permitted[:commands] = permit_commands(commands)
|
||||
if tools = params.dig(:ai_persona, :tools)
|
||||
permitted[:tools] = permit_tools(tools)
|
||||
end
|
||||
|
||||
permitted
|
||||
end
|
||||
|
||||
def permit_commands(commands)
|
||||
return [] if !commands.is_a?(Array)
|
||||
def permit_tools(tools)
|
||||
return [] if !tools.is_a?(Array)
|
||||
|
||||
commands.filter_map do |command, options|
|
||||
break nil if !command.is_a?(String)
|
||||
tools.filter_map do |tool, options|
|
||||
break nil if !tool.is_a?(String)
|
||||
options&.permit! if options && options.is_a?(ActionController::Parameters)
|
||||
|
||||
if options
|
||||
[command, options]
|
||||
[tool, options]
|
||||
else
|
||||
command
|
||||
tool
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AiPersona < ActiveRecord::Base
|
||||
# TODO remove this line 01-11-2024
|
||||
self.ignored_columns = [:commands]
|
||||
|
||||
# places a hard limit, so per site we cache a maximum of 500 classes
|
||||
MAX_PERSONAS_PER_SITE = 500
|
||||
|
||||
|
@ -102,96 +105,49 @@ class AiPersona < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def class_instance
|
||||
allowed_group_ids = self.allowed_group_ids
|
||||
id = self.id
|
||||
system = self.system
|
||||
user_id = self.user_id
|
||||
mentionable = self.mentionable
|
||||
default_llm = self.default_llm
|
||||
max_context_posts = self.max_context_posts
|
||||
vision_enabled = self.vision_enabled
|
||||
vision_max_pixels = self.vision_max_pixels
|
||||
rag_conversation_chunks = self.rag_conversation_chunks
|
||||
question_consolidator_llm = self.question_consolidator_llm
|
||||
allow_chat = self.allow_chat
|
||||
attributes = %i[
|
||||
id
|
||||
user_id
|
||||
system
|
||||
mentionable
|
||||
default_llm
|
||||
max_context_posts
|
||||
vision_enabled
|
||||
vision_max_pixels
|
||||
rag_conversation_chunks
|
||||
question_consolidator_llm
|
||||
allow_chat
|
||||
name
|
||||
description
|
||||
allowed_group_ids
|
||||
tool_details
|
||||
]
|
||||
|
||||
persona_class = DiscourseAi::AiBot::Personas::Persona.system_personas_by_id[self.id]
|
||||
|
||||
instance_attributes = {}
|
||||
attributes.each do |attr|
|
||||
value = self.read_attribute(attr)
|
||||
instance_attributes[attr] = value
|
||||
end
|
||||
|
||||
if persona_class
|
||||
persona_class.define_singleton_method :allowed_group_ids do
|
||||
allowed_group_ids
|
||||
instance_attributes.each do |key, value|
|
||||
# description/name are localized
|
||||
persona_class.define_singleton_method(key) { value } if key != :description && key != :name
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :id do
|
||||
id
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :system do
|
||||
system
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :user_id do
|
||||
user_id
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :allow_chat do
|
||||
allow_chat
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :mentionable do
|
||||
mentionable
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :default_llm do
|
||||
default_llm
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :max_context_posts do
|
||||
max_context_posts
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :vision_enabled do
|
||||
vision_enabled
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :vision_max_pixels do
|
||||
vision_max_pixels
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :question_consolidator_llm do
|
||||
question_consolidator_llm
|
||||
end
|
||||
|
||||
persona_class.define_singleton_method :rag_conversation_chunks do
|
||||
rag_conversation_chunks
|
||||
end
|
||||
|
||||
return persona_class
|
||||
end
|
||||
|
||||
name = self.name
|
||||
description = self.description
|
||||
ai_persona_id = self.id
|
||||
|
||||
options = {}
|
||||
|
||||
tools = self.respond_to?(:commands) ? self.commands : self.tools
|
||||
|
||||
tools =
|
||||
tools.filter_map do |element|
|
||||
inner_name = element
|
||||
current_options = nil
|
||||
|
||||
if element.is_a?(Array)
|
||||
inner_name = element[0]
|
||||
current_options = element[1]
|
||||
end
|
||||
|
||||
# Won't migrate data yet. Let's rewrite to the tool name.
|
||||
inner_name = inner_name.gsub("Command", "")
|
||||
self.tools.filter_map do |element|
|
||||
inner_name, current_options = element.is_a?(Array) ? element : [element, nil]
|
||||
inner_name = inner_name.gsub("Tool", "")
|
||||
inner_name = "List#{inner_name}" if %w[Categories Tags].include?(inner_name)
|
||||
|
||||
begin
|
||||
klass = ("DiscourseAi::AiBot::Tools::#{inner_name}").constantize
|
||||
klass = "DiscourseAi::AiBot::Tools::#{inner_name}".constantize
|
||||
options[klass] = current_options if current_options
|
||||
klass
|
||||
rescue StandardError
|
||||
|
@ -199,107 +155,28 @@ class AiPersona < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
ai_persona_id = self.id
|
||||
|
||||
Class.new(DiscourseAi::AiBot::Personas::Persona) do
|
||||
define_singleton_method :id do
|
||||
id
|
||||
instance_attributes.each { |key, value| define_singleton_method(key) { value } }
|
||||
|
||||
define_singleton_method(:to_s) do
|
||||
"#<#{self.class.name} @name=#{name} @allowed_group_ids=#{allowed_group_ids.join(",")}>"
|
||||
end
|
||||
|
||||
define_singleton_method :name do
|
||||
name
|
||||
end
|
||||
define_singleton_method(:inspect) { to_s }
|
||||
|
||||
define_singleton_method :user_id do
|
||||
user_id
|
||||
end
|
||||
|
||||
define_singleton_method :description do
|
||||
description
|
||||
end
|
||||
|
||||
define_singleton_method :system do
|
||||
system
|
||||
end
|
||||
|
||||
define_singleton_method :allowed_group_ids do
|
||||
allowed_group_ids
|
||||
end
|
||||
|
||||
define_singleton_method :user_id do
|
||||
user_id
|
||||
end
|
||||
|
||||
define_singleton_method :mentionable do
|
||||
mentionable
|
||||
end
|
||||
|
||||
define_singleton_method :default_llm do
|
||||
default_llm
|
||||
end
|
||||
|
||||
define_singleton_method :max_context_posts do
|
||||
max_context_posts
|
||||
end
|
||||
|
||||
define_singleton_method :vision_enabled do
|
||||
vision_enabled
|
||||
end
|
||||
|
||||
define_singleton_method :vision_max_pixels do
|
||||
vision_max_pixels
|
||||
end
|
||||
|
||||
define_singleton_method :rag_conversation_chunks do
|
||||
rag_conversation_chunks
|
||||
end
|
||||
|
||||
define_singleton_method :question_consolidator_llm do
|
||||
question_consolidator_llm
|
||||
end
|
||||
|
||||
define_singleton_method :allow_chat do
|
||||
allow_chat
|
||||
end
|
||||
|
||||
define_singleton_method :to_s do
|
||||
"#<DiscourseAi::AiBot::Personas::Persona::Custom @name=#{self.name} @allowed_group_ids=#{self.allowed_group_ids.join(",")}>"
|
||||
end
|
||||
|
||||
define_singleton_method :inspect do
|
||||
"#<DiscourseAi::AiBot::Personas::Persona::Custom @name=#{self.name} @allowed_group_ids=#{self.allowed_group_ids.join(",")}>"
|
||||
end
|
||||
|
||||
define_method :initialize do |*args, **kwargs|
|
||||
define_method(:initialize) do |*args, **kwargs|
|
||||
@ai_persona = AiPersona.find_by(id: ai_persona_id)
|
||||
super(*args, **kwargs)
|
||||
end
|
||||
|
||||
define_method :persona_id do
|
||||
@ai_persona&.id
|
||||
end
|
||||
|
||||
define_method :tools do
|
||||
tools
|
||||
end
|
||||
|
||||
define_method :options do
|
||||
options
|
||||
end
|
||||
|
||||
define_method :temperature do
|
||||
@ai_persona&.temperature
|
||||
end
|
||||
|
||||
define_method :top_p do
|
||||
@ai_persona&.top_p
|
||||
end
|
||||
|
||||
define_method :system_prompt do
|
||||
@ai_persona&.system_prompt || "You are a helpful bot."
|
||||
end
|
||||
|
||||
define_method :uploads do
|
||||
@ai_persona&.uploads
|
||||
end
|
||||
define_method(:tools) { tools }
|
||||
define_method(:options) { options }
|
||||
define_method(:temperature) { @ai_persona&.temperature }
|
||||
define_method(:top_p) { @ai_persona&.top_p }
|
||||
define_method(:system_prompt) { @ai_persona&.system_prompt || "You are a helpful bot." }
|
||||
define_method(:uploads) { @ai_persona&.uploads }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -357,7 +234,7 @@ class AiPersona < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def system_persona_unchangeable
|
||||
if top_p_changed? || temperature_changed? || system_prompt_changed? || commands_changed? ||
|
||||
if top_p_changed? || temperature_changed? || system_prompt_changed? || tools_changed? ||
|
||||
name_changed? || description_changed?
|
||||
errors.add(:base, I18n.t("discourse_ai.ai_bot.personas.cannot_edit_system_persona"))
|
||||
end
|
||||
|
@ -378,7 +255,7 @@ end
|
|||
# id :bigint not null, primary key
|
||||
# name :string(100) not null
|
||||
# description :string(2000) not null
|
||||
# commands :json 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
|
||||
|
@ -408,6 +285,7 @@ end
|
|||
# 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
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
|
|
@ -9,7 +9,7 @@ class LocalizedAiPersonaSerializer < ApplicationSerializer
|
|||
:enabled,
|
||||
:system,
|
||||
:priority,
|
||||
:commands,
|
||||
:tools,
|
||||
:system_prompt,
|
||||
:allowed_group_ids,
|
||||
:temperature,
|
||||
|
@ -24,7 +24,8 @@ class LocalizedAiPersonaSerializer < ApplicationSerializer
|
|||
:rag_chunk_overlap_tokens,
|
||||
:rag_conversation_chunks,
|
||||
:question_consolidator_llm,
|
||||
:allow_chat
|
||||
:allow_chat,
|
||||
:tool_details
|
||||
|
||||
has_one :user, serializer: BasicUserSerializer, embed: :object
|
||||
has_many :rag_uploads, serializer: UploadSerializer, embed: :object
|
||||
|
|
|
@ -6,7 +6,7 @@ const CREATE_ATTRIBUTES = [
|
|||
"id",
|
||||
"name",
|
||||
"description",
|
||||
"commands",
|
||||
"tools",
|
||||
"system_prompt",
|
||||
"allowed_group_ids",
|
||||
"enabled",
|
||||
|
@ -27,6 +27,7 @@ const CREATE_ATTRIBUTES = [
|
|||
"rag_conversation_chunks",
|
||||
"question_consolidator_llm",
|
||||
"allow_chat",
|
||||
"tool_details",
|
||||
];
|
||||
|
||||
const SYSTEM_ATTRIBUTES = [
|
||||
|
@ -48,37 +49,37 @@ const SYSTEM_ATTRIBUTES = [
|
|||
"rag_conversation_chunks",
|
||||
"question_consolidator_llm",
|
||||
"allow_chat",
|
||||
"tool_details",
|
||||
];
|
||||
|
||||
class CommandOption {
|
||||
class ToolOption {
|
||||
@tracked value = null;
|
||||
}
|
||||
|
||||
export default class AiPersona extends RestModel {
|
||||
// this code is here to convert the wire schema to easier to work with object
|
||||
// on the wire we pass in/out commands as an Array.
|
||||
// [[CommandName, {option1: value, option2: value}], CommandName2, CommandName3]
|
||||
// So we rework this into a "commands" property and nested commandOptions
|
||||
// on the wire we pass in/out tools as an Array.
|
||||
// [[ToolName, {option1: value, option2: value}], ToolName2, ToolName3]
|
||||
// So we rework this into a "tools" property and nested toolOptions
|
||||
init(properties) {
|
||||
if (properties.commands) {
|
||||
properties.commands = properties.commands.map((command) => {
|
||||
if (typeof command === "string") {
|
||||
return command;
|
||||
if (properties.tools) {
|
||||
properties.tools = properties.tools.map((tool) => {
|
||||
if (typeof tool === "string") {
|
||||
return tool;
|
||||
} else {
|
||||
let [commandId, options] = command;
|
||||
let [toolId, options] = tool;
|
||||
for (let optionId in options) {
|
||||
if (!options.hasOwnProperty(optionId)) {
|
||||
continue;
|
||||
}
|
||||
this.getCommandOption(commandId, optionId).value =
|
||||
options[optionId];
|
||||
this.getToolOption(toolId, optionId).value = options[optionId];
|
||||
}
|
||||
return commandId;
|
||||
return toolId;
|
||||
}
|
||||
});
|
||||
}
|
||||
super.init(properties);
|
||||
this.commands = properties.commands;
|
||||
this.tools = properties.tools;
|
||||
}
|
||||
|
||||
async createUser() {
|
||||
|
@ -93,23 +94,23 @@ export default class AiPersona extends RestModel {
|
|||
return this.user;
|
||||
}
|
||||
|
||||
getCommandOption(commandId, optionId) {
|
||||
this.commandOptions ||= {};
|
||||
this.commandOptions[commandId] ||= {};
|
||||
return (this.commandOptions[commandId][optionId] ||= new CommandOption());
|
||||
getToolOption(toolId, optionId) {
|
||||
this.toolOptions ||= {};
|
||||
this.toolOptions[toolId] ||= {};
|
||||
return (this.toolOptions[toolId][optionId] ||= new ToolOption());
|
||||
}
|
||||
|
||||
populateCommandOptions(attrs) {
|
||||
if (!attrs.commands) {
|
||||
populateToolOptions(attrs) {
|
||||
if (!attrs.tools) {
|
||||
return;
|
||||
}
|
||||
let commandsWithOptions = [];
|
||||
attrs.commands.forEach((commandId) => {
|
||||
if (typeof commandId !== "string") {
|
||||
commandId = commandId[0];
|
||||
let toolsWithOptions = [];
|
||||
attrs.tools.forEach((toolId) => {
|
||||
if (typeof toolId !== "string") {
|
||||
toolId = toolId[0];
|
||||
}
|
||||
if (this.commandOptions && this.commandOptions[commandId]) {
|
||||
let options = this.commandOptions[commandId];
|
||||
if (this.toolOptions && this.toolOptions[toolId]) {
|
||||
let options = this.toolOptions[toolId];
|
||||
let optionsWithValues = {};
|
||||
for (let optionId in options) {
|
||||
if (!options.hasOwnProperty(optionId)) {
|
||||
|
@ -118,12 +119,12 @@ export default class AiPersona extends RestModel {
|
|||
let option = options[optionId];
|
||||
optionsWithValues[optionId] = option.value;
|
||||
}
|
||||
commandsWithOptions.push([commandId, optionsWithValues]);
|
||||
toolsWithOptions.push([toolId, optionsWithValues]);
|
||||
} else {
|
||||
commandsWithOptions.push(commandId);
|
||||
toolsWithOptions.push(toolId);
|
||||
}
|
||||
});
|
||||
attrs.commands = commandsWithOptions;
|
||||
attrs.tools = toolsWithOptions;
|
||||
}
|
||||
|
||||
updateProperties() {
|
||||
|
@ -131,20 +132,20 @@ export default class AiPersona extends RestModel {
|
|||
? this.getProperties(SYSTEM_ATTRIBUTES)
|
||||
: this.getProperties(CREATE_ATTRIBUTES);
|
||||
attrs.id = this.id;
|
||||
this.populateCommandOptions(attrs);
|
||||
this.populateToolOptions(attrs);
|
||||
|
||||
return attrs;
|
||||
}
|
||||
|
||||
createProperties() {
|
||||
let attrs = this.getProperties(CREATE_ATTRIBUTES);
|
||||
this.populateCommandOptions(attrs);
|
||||
this.populateToolOptions(attrs);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
workingCopy() {
|
||||
let attrs = this.getProperties(CREATE_ATTRIBUTES);
|
||||
this.populateCommandOptions(attrs);
|
||||
this.populateToolOptions(attrs);
|
||||
return AiPersona.create(attrs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
import Component from "@glimmer/component";
|
||||
import I18n from "discourse-i18n";
|
||||
import AiPersonaCommandOptionEditor from "./ai-persona-command-option-editor";
|
||||
|
||||
export default class AiPersonaCommandOptions extends Component {
|
||||
get showCommandOptions() {
|
||||
const allCommands = this.args.allCommands;
|
||||
if (!allCommands) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.commandNames.any(
|
||||
(command) => allCommands.find((c) => c.id === command)?.options
|
||||
);
|
||||
}
|
||||
|
||||
get commandNames() {
|
||||
if (!this.args.commands) {
|
||||
return [];
|
||||
}
|
||||
return this.args.commands.map((command) => {
|
||||
if (typeof command === "string") {
|
||||
return command;
|
||||
} else {
|
||||
return command[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get commandOptions() {
|
||||
if (!this.args.commands) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const allCommands = this.args.allCommands;
|
||||
if (!allCommands) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const options = [];
|
||||
this.commandNames.forEach((commandId) => {
|
||||
const command = allCommands.find((c) => c.id === commandId);
|
||||
|
||||
const commandName = command?.name;
|
||||
const commandOptions = command?.options;
|
||||
|
||||
if (commandOptions) {
|
||||
const mappedOptions = Object.keys(commandOptions).map((key) => {
|
||||
const value = this.args.persona.getCommandOption(commandId, key);
|
||||
return Object.assign({}, commandOptions[key], { id: key, value });
|
||||
});
|
||||
|
||||
options.push({ commandName, options: mappedOptions });
|
||||
}
|
||||
});
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
<template>
|
||||
{{#if this.showCommandOptions}}
|
||||
<div class="control-group">
|
||||
<label>{{I18n.t "discourse_ai.ai_persona.command_options"}}</label>
|
||||
<div>
|
||||
{{#each this.commandOptions as |commandOption|}}
|
||||
<div class="ai-persona-editor__command-options">
|
||||
<div class="ai-persona-editor__command-options-name">
|
||||
{{commandOption.commandName}}
|
||||
</div>
|
||||
<div class="ai-persona-editor__command-option-options">
|
||||
{{#each commandOption.options as |option|}}
|
||||
<AiPersonaCommandOptionEditor @option={{option}} />
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
|
@ -20,9 +20,9 @@ import AdminUser from "admin/models/admin-user";
|
|||
import ComboBox from "select-kit/components/combo-box";
|
||||
import GroupChooser from "select-kit/components/group-chooser";
|
||||
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 AiPersonaToolOptions from "./ai-persona-tool-options";
|
||||
import AiToolSelector from "./ai-tool-selector";
|
||||
import PersonaRagUploader from "./persona-rag-uploader";
|
||||
|
||||
export default class PersonaEditor extends Component {
|
||||
|
@ -201,21 +201,6 @@ export default class PersonaEditor extends Component {
|
|||
await this.toggleField("priority", true);
|
||||
}
|
||||
|
||||
@action
|
||||
async toggleMentionable() {
|
||||
await this.toggleField("mentionable");
|
||||
}
|
||||
|
||||
@action
|
||||
async toggleAllowChat() {
|
||||
await this.toggleField("allow_chat");
|
||||
}
|
||||
|
||||
@action
|
||||
async toggleVisionEnabled() {
|
||||
await this.toggleField("vision_enabled");
|
||||
}
|
||||
|
||||
@action
|
||||
async createUser() {
|
||||
try {
|
||||
|
@ -303,45 +288,6 @@ export default class PersonaEditor extends Component {
|
|||
@content={{I18n.t "discourse_ai.ai_persona.priority_help"}}
|
||||
/>
|
||||
</div>
|
||||
{{#if this.editingModel.user}}
|
||||
{{#if this.chatPluginEnabled}}
|
||||
<div class="control-group ai-persona-editor__allow_chat">
|
||||
<DToggleSwitch
|
||||
class="ai-persona-editor__allow_chat_toggle"
|
||||
@state={{@model.allow_chat}}
|
||||
@label="discourse_ai.ai_persona.allow_chat"
|
||||
{{on "click" this.toggleAllowChat}}
|
||||
/>
|
||||
<DTooltip
|
||||
@icon="question-circle"
|
||||
@content={{I18n.t "discourse_ai.ai_persona.allow_chat_help"}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="control-group ai-persona-editor__mentionable">
|
||||
<DToggleSwitch
|
||||
class="ai-persona-editor__mentionable_toggle"
|
||||
@state={{@model.mentionable}}
|
||||
@label="discourse_ai.ai_persona.mentionable"
|
||||
{{on "click" this.toggleMentionable}}
|
||||
/>
|
||||
<DTooltip
|
||||
@icon="question-circle"
|
||||
@content={{I18n.t "discourse_ai.ai_persona.mentionable_help"}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="control-group ai-persona-editor__vision_enabled">
|
||||
<DToggleSwitch
|
||||
@state={{@model.vision_enabled}}
|
||||
@label="discourse_ai.ai_persona.vision_enabled"
|
||||
{{on "click" this.toggleVisionEnabled}}
|
||||
/>
|
||||
<DTooltip
|
||||
@icon="question-circle"
|
||||
@content={{I18n.t "discourse_ai.ai_persona.vision_enabled_help"}}
|
||||
/>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label>{{I18n.t "discourse_ai.ai_persona.name"}}</label>
|
||||
<Input
|
||||
|
@ -400,19 +346,19 @@ export default class PersonaEditor extends Component {
|
|||
</div>
|
||||
{{/unless}}
|
||||
<div class="control-group">
|
||||
<label>{{I18n.t "discourse_ai.ai_persona.commands"}}</label>
|
||||
<AiCommandSelector
|
||||
class="ai-persona-editor__commands"
|
||||
@value={{this.editingModel.commands}}
|
||||
<label>{{I18n.t "discourse_ai.ai_persona.tools"}}</label>
|
||||
<AiToolSelector
|
||||
class="ai-persona-editor__tools"
|
||||
@value={{this.editingModel.tools}}
|
||||
@disabled={{this.editingModel.system}}
|
||||
@commands={{@personas.resultSetMeta.commands}}
|
||||
@tools={{@personas.resultSetMeta.tools}}
|
||||
/>
|
||||
</div>
|
||||
{{#unless this.editingModel.system}}
|
||||
<AiPersonaCommandOptions
|
||||
<AiPersonaToolOptions
|
||||
@persona={{this.editingModel}}
|
||||
@commands={{this.editingModel.commands}}
|
||||
@allCommands={{@personas.resultSetMeta.commands}}
|
||||
@tools={{this.editingModel.tools}}
|
||||
@allTools={{@personas.resultSetMeta.tools}}
|
||||
/>
|
||||
{{/unless}}
|
||||
<div class="control-group">
|
||||
|
@ -433,6 +379,65 @@ export default class PersonaEditor extends Component {
|
|||
disabled={{this.editingModel.system}}
|
||||
/>
|
||||
</div>
|
||||
{{#if this.editingModel.user}}
|
||||
{{#if this.chatPluginEnabled}}
|
||||
<div class="control-group ai-persona-editor__allow_chat">
|
||||
<label>
|
||||
<Input
|
||||
@type="checkbox"
|
||||
@checked={{this.editingModel.allow_chat}}
|
||||
/>
|
||||
{{I18n.t "discourse_ai.ai_persona.allow_chat"}}</label>
|
||||
<DTooltip
|
||||
@icon="question-circle"
|
||||
@content={{I18n.t "discourse_ai.ai_persona.allow_chat_help"}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="control-group ai-persona-editor__mentionable">
|
||||
<label>
|
||||
<Input
|
||||
@type="checkbox"
|
||||
@checked={{this.editingModel.mentionable}}
|
||||
/>
|
||||
{{I18n.t "discourse_ai.ai_persona.mentionable"}}</label>
|
||||
<DTooltip
|
||||
@icon="question-circle"
|
||||
@content={{I18n.t "discourse_ai.ai_persona.mentionable_help"}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="control-group ai-persona-editor__tool-details">
|
||||
<label>
|
||||
<Input @type="checkbox" @checked={{this.editingModel.tool_details}} />
|
||||
{{I18n.t "discourse_ai.ai_persona.tool_details"}}</label>
|
||||
<DTooltip
|
||||
@icon="question-circle"
|
||||
@content={{I18n.t "discourse_ai.ai_persona.tool_details_help"}}
|
||||
/>
|
||||
</div>
|
||||
<div class="control-group ai-persona-editor__vision_enabled">
|
||||
<label>
|
||||
<Input
|
||||
@type="checkbox"
|
||||
@checked={{this.editingModel.vision_enabled}}
|
||||
/>
|
||||
{{I18n.t "discourse_ai.ai_persona.vision_enabled"}}</label>
|
||||
<DTooltip
|
||||
@icon="question-circle"
|
||||
@content={{I18n.t "discourse_ai.ai_persona.vision_enabled_help"}}
|
||||
/>
|
||||
</div>
|
||||
{{#if this.editingModel.vision_enabled}}
|
||||
<div class="control-group">
|
||||
<label>{{I18n.t "discourse_ai.ai_persona.vision_max_pixels"}}</label>
|
||||
<ComboBox
|
||||
@value={{this.maxPixelsValue}}
|
||||
@content={{this.maxPixelValues}}
|
||||
@onChange={{this.onChangeMaxPixels}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="control-group">
|
||||
<label>{{I18n.t "discourse_ai.ai_persona.max_context_posts"}}</label>
|
||||
<Input
|
||||
|
@ -446,18 +451,8 @@ export default class PersonaEditor extends Component {
|
|||
@content={{I18n.t "discourse_ai.ai_persona.max_context_posts_help"}}
|
||||
/>
|
||||
</div>
|
||||
{{#if @model.vision_enabled}}
|
||||
{{#if this.showTemperature}}
|
||||
<div class="control-group">
|
||||
<label>{{I18n.t "discourse_ai.ai_persona.vision_max_pixels"}}</label>
|
||||
<ComboBox
|
||||
@value={{this.maxPixelsValue}}
|
||||
@content={{this.maxPixelValues}}
|
||||
@onChange={{this.onChangeMaxPixels}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
<div class="control-group">
|
||||
{{#if this.showTemperature}}
|
||||
<label>{{I18n.t "discourse_ai.ai_persona.temperature"}}</label>
|
||||
<Input
|
||||
@type="number"
|
||||
|
@ -471,8 +466,10 @@ export default class PersonaEditor extends Component {
|
|||
@icon="question-circle"
|
||||
@content={{I18n.t "discourse_ai.ai_persona.temperature_help"}}
|
||||
/>
|
||||
{{/if}}
|
||||
{{#if this.showTopP}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.showTopP}}
|
||||
<div class="control-group">
|
||||
<label>{{I18n.t "discourse_ai.ai_persona.top_p"}}</label>
|
||||
<Input
|
||||
@type="number"
|
||||
|
@ -486,8 +483,8 @@ export default class PersonaEditor extends Component {
|
|||
@icon="question-circle"
|
||||
@content={{I18n.t "discourse_ai.ai_persona.top_p_help"}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if this.siteSettings.ai_embeddings_enabled}}
|
||||
<div class="control-group">
|
||||
<PersonaRagUploader
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Input } from "@ember/component";
|
|||
import { on } from "@ember/modifier";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default class AiPersonaCommandOptionEditor extends Component {
|
||||
export default class AiPersonaToolOptionEditor extends Component {
|
||||
get isBoolean() {
|
||||
return this.args.option.type === "boolean";
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ export default class AiPersonaCommandOptionEditor extends Component {
|
|||
}
|
||||
|
||||
<template>
|
||||
<div class="control-group ai-persona-command-option-editor">
|
||||
<div class="control-group ai-persona-tool-option-editor">
|
||||
<label>
|
||||
{{@option.name}}
|
||||
</label>
|
||||
|
@ -35,7 +35,7 @@ export default class AiPersonaCommandOptionEditor extends Component {
|
|||
{{/if}}
|
||||
</div>
|
||||
{{#unless this.isBoolean}}
|
||||
<div class="ai-persona-command-option-editor__instructions">
|
||||
<div class="ai-persona-tool-option-editor__instructions">
|
||||
{{@option.description}}
|
||||
</div>
|
||||
{{/unless}}
|
|
@ -0,0 +1,79 @@
|
|||
import Component from "@glimmer/component";
|
||||
import I18n from "discourse-i18n";
|
||||
import AiPersonaToolOptionEditor from "./ai-persona-tool-option-editor";
|
||||
|
||||
export default class AiPersonaToolOptions extends Component {
|
||||
get showToolOptions() {
|
||||
const allTools = this.args.allTools;
|
||||
if (!allTools) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.toolNames.any((tool) => allTools.findBy("id", tool)?.options);
|
||||
}
|
||||
|
||||
get toolNames() {
|
||||
if (!this.args.tools) {
|
||||
return [];
|
||||
}
|
||||
return this.args.tools.map((tool) => {
|
||||
if (typeof tool === "string") {
|
||||
return tool;
|
||||
} else {
|
||||
return tool[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get toolOptions() {
|
||||
if (!this.args.tools) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const allTools = this.args.allTools;
|
||||
if (!allTools) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const options = [];
|
||||
this.toolNames.forEach((toolId) => {
|
||||
const tool = allTools.findBy("id", toolId);
|
||||
|
||||
const toolName = tool?.name;
|
||||
const toolOptions = tool?.options;
|
||||
|
||||
if (toolOptions) {
|
||||
const mappedOptions = Object.keys(toolOptions).map((key) => {
|
||||
const value = this.args.persona.getToolOption(toolId, key);
|
||||
return Object.assign({}, toolOptions[key], { id: key, value });
|
||||
});
|
||||
|
||||
options.push({ toolName, options: mappedOptions });
|
||||
}
|
||||
});
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
<template>
|
||||
{{#if this.showToolOptions}}
|
||||
<div class="control-group">
|
||||
<label>{{I18n.t "discourse_ai.ai_persona.tool_options"}}</label>
|
||||
<div>
|
||||
{{#each this.toolOptions as |toolOption|}}
|
||||
<div class="ai-persona-editor__tool-options">
|
||||
<div class="ai-persona-editor__tool-options-name">
|
||||
{{toolOption.toolName}}
|
||||
</div>
|
||||
<div class="ai-persona-editor__tool-option-options">
|
||||
{{#each toolOption.options as |option|}}
|
||||
<AiPersonaToolOptionEditor @option={{option}} />
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
||||
}
|
|
@ -7,7 +7,7 @@ export default MultiSelectComponent.extend({
|
|||
}),
|
||||
|
||||
content: computed(function () {
|
||||
return this.commands;
|
||||
return this.tools;
|
||||
}),
|
||||
|
||||
value: "",
|
|
@ -23,7 +23,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.ai-persona-command-option-editor {
|
||||
.ai-persona-tool-option-editor {
|
||||
&__instructions {
|
||||
color: var(--primary-medium);
|
||||
font-size: var(--font-down-1);
|
||||
|
@ -49,12 +49,12 @@
|
|||
label {
|
||||
display: block;
|
||||
}
|
||||
&__command-options {
|
||||
&__tool-options {
|
||||
padding: 5px 10px 5px;
|
||||
border: 1px solid var(--primary-low-mid);
|
||||
width: 480px;
|
||||
}
|
||||
&__command-options-name {
|
||||
&__tool-options-name {
|
||||
margin-bottom: 10px;
|
||||
font-size: var(--font-down-1);
|
||||
}
|
||||
|
@ -65,25 +65,16 @@
|
|||
width: 500px;
|
||||
height: 400px;
|
||||
}
|
||||
&__priority {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__tool-details,
|
||||
&__vision_enabled,
|
||||
&__allow_chat,
|
||||
&__priority,
|
||||
&__mentionable {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__allow_chat {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__vision_enabled {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__indexing-options {
|
||||
display: block;
|
||||
margin-top: 1em;
|
||||
|
|
|
@ -111,7 +111,7 @@ ar:
|
|||
delete: حذف
|
||||
priority: الأولوية
|
||||
priority_help: يتم عرض الشخصيات ذات الأولوية للمستخدمين في أعلى قائمة الشخصيات. إذا كانت الأولوية لعدة أشخاص، فسيتم فرزهم أبجديًا.
|
||||
command_options: "خيارات الأوامر"
|
||||
tool_options: "خيارات الأوامر"
|
||||
uploads:
|
||||
title: "التحميلات"
|
||||
uploading: "جارٍ التحميل..."
|
||||
|
|
|
@ -169,7 +169,7 @@ de:
|
|||
top_p_help: Top P für die LLM, erhöhen, um die Zufälligkeit zu erhöhen (leer lassen, um die Modellvorgabe zu verwenden, in der Regel ein Wert zwischen 0,0 und 1,0)
|
||||
priority: Priorität
|
||||
priority_help: Personas mit Priorität werden den Benutzern am Anfang der Persona-Liste angezeigt. Wenn mehrere Personas Priorität haben, werden sie alphabetisch sortiert.
|
||||
command_options: "Befehlsoptionen"
|
||||
tool_options: "Befehlsoptionen"
|
||||
rag_chunk_tokens: "Chunk-Token hochladen"
|
||||
rag_chunk_tokens_help: "Die Anzahl der Token, die für jeden Chunk im RAG-Modell verwendet werden. Erhöhen, um die Menge des Kontexts zu erhöhen, den die KI verwenden kann. (Eine Änderung führt zu einer Neuindizierung aller Uploads)"
|
||||
rag_chunk_overlap_tokens: "Chunk-Überlappungs-Token hochladen"
|
||||
|
|
|
@ -131,12 +131,14 @@ en:
|
|||
max_context_posts: "Max Context Posts"
|
||||
max_context_posts_help: "The maximum number of posts to use as context for the AI when responding to a user. (empty for default)"
|
||||
vision_enabled: Vision Enabled
|
||||
vision_enabled_help: If enabled, the AI will attempt to understand images users post in the topic, depends on the model being used supporting vision. Anthropic Claude 3 models support vision.
|
||||
vision_enabled_help: If enabled, the AI will attempt to understand images users post in the topic, depends on the model being used supporting vision. Supported by latest models from Anthropic, Google, and OpenAI.
|
||||
vision_max_pixels: Supported image size
|
||||
vision_max_pixel_sizes:
|
||||
low: Low Quality - cheapest (256x256)
|
||||
medium: Medium Quality (512x512)
|
||||
high: High Quality - slowest (1024x1024)
|
||||
tool_details: Show Tool Details
|
||||
tool_details_help: Will show end users details on which tools the language model has triggered.
|
||||
mentionable: Allow Mentions
|
||||
mentionable_help: If enabled, users in allowed groups can mention this user in posts, the AI will respond as this persona.
|
||||
user: User
|
||||
|
@ -154,7 +156,7 @@ en:
|
|||
save: Save
|
||||
saved: AI Persona Saved
|
||||
enabled: "Enabled?"
|
||||
commands: Enabled Commands
|
||||
tools: Enabled Tools
|
||||
allowed_groups: Allowed Groups
|
||||
confirm_delete: Are you sure you want to delete this persona?
|
||||
new: "New Persona"
|
||||
|
@ -167,7 +169,7 @@ en:
|
|||
top_p_help: Top P to use for the LLM, increase to increase randomness (leave empty to use model default, generally a value from 0.0 to 1.0)
|
||||
priority: Priority
|
||||
priority_help: Priority personas are displayed to users at the top of the persona list. If multiple personas have priority, they will be sorted alphabetically.
|
||||
command_options: "Command Options"
|
||||
tool_options: "Tool Options"
|
||||
rag_chunk_tokens: "Upload Chunk Tokens"
|
||||
rag_chunk_tokens_help: "The number of tokens to use for each chunk in the RAG model. Increase to increase the amount of context the AI can use. (changing will re-index all uploads)"
|
||||
rag_chunk_overlap_tokens: "Upload Chunk Overlap Tokens"
|
||||
|
|
|
@ -111,7 +111,7 @@ es:
|
|||
delete: Eliminar
|
||||
priority: Prioridad
|
||||
priority_help: Las personas prioritarias se muestran a los usuarios en la parte superior de la lista de personas. Si varias personas tienen prioridad, se ordenarán alfabéticamente.
|
||||
command_options: "Opciones de comando"
|
||||
tool_options: "Opciones de comando"
|
||||
uploads:
|
||||
title: "Subidos"
|
||||
uploading: "Subiendo..."
|
||||
|
|
|
@ -111,7 +111,7 @@ fi:
|
|||
delete: Poista
|
||||
priority: Prioriteetti
|
||||
priority_help: Prioriteettipersoonat näytetään käyttäjille ensimmäisinä persoonaluettelossa. Jos useilla persoonilla on prioriteetti, ne järjestetään aakkosjärjestyksessä.
|
||||
command_options: "Komentoasetukset"
|
||||
tool_options: "Komentoasetukset"
|
||||
uploads:
|
||||
title: "Lataukset"
|
||||
uploading: "Ladataan..."
|
||||
|
|
|
@ -111,7 +111,7 @@ fr:
|
|||
delete: Supprimer
|
||||
priority: Priorité
|
||||
priority_help: Les personnages prioritaires sont affichés aux utilisateurs en haut de la liste des personnages. Si plusieurs personnages sont prioritaires, ils seront triés par ordre alphabétique.
|
||||
command_options: "Options de commande"
|
||||
tool_options: "Options de commande"
|
||||
uploads:
|
||||
title: "Fichiers envoyés"
|
||||
uploading: "Envoi en cours…"
|
||||
|
|
|
@ -169,7 +169,7 @@ he:
|
|||
top_p_help: ה־P המובילים לשימוש למודל השפה הגדול (LLM), הגדלה תגדיל את היצירתיות (אפשר להשאיר ריק לשימוש בברירת המחדל של הדגם, בדרך כלל זה ערך בין 0.0 לבין 1.0)
|
||||
priority: עדיפות
|
||||
priority_help: דמויות בעדיפות גבוהה מוצגות למשתמשים בראש רשימת הדמויות. אם מספר דמויות הן בעדיפות הן תסודרנה לפי האלפבית.
|
||||
command_options: "אפשרויות פקודה"
|
||||
tool_options: "אפשרויות פקודה"
|
||||
rag_chunk_tokens: "העלאת אסימוני חלקים"
|
||||
rag_chunk_tokens_help: "מספר האסימונים לשימוש לכל נתח במודל ה־RAG. הגדלה תגדיל את כמות ההקשר בו יכולה להשתמש הבינה המלאכותית. (שינוי יסדר את כל ההעלאות במפתח מחדש)"
|
||||
rag_chunk_overlap_tokens: "העלאת אסימוני חפיפת חלקים"
|
||||
|
|
|
@ -111,7 +111,7 @@ it:
|
|||
delete: Elimina
|
||||
priority: Priorità
|
||||
priority_help: I personaggi prioritari vengono visualizzati agli utenti nella parte superiore dell'elenco dei personaggi. Se più personaggi hanno la priorità, verranno ordinati in ordine alfabetico.
|
||||
command_options: "Opzioni di comando"
|
||||
tool_options: "Opzioni di comando"
|
||||
uploads:
|
||||
title: "Caricamenti"
|
||||
uploading: "Caricamento..."
|
||||
|
|
|
@ -111,7 +111,7 @@ ja:
|
|||
delete: 削除
|
||||
priority: 優先度
|
||||
priority_help: 優先ペルソナはペルソナリストの先頭に表示されます。複数のペルソナが優先されている場合は、アルファベット順に並べ替えられます。
|
||||
command_options: "コマンドオプション"
|
||||
tool_options: "コマンドオプション"
|
||||
uploads:
|
||||
title: "アップロード"
|
||||
uploading: "アップロード中..."
|
||||
|
|
|
@ -111,7 +111,7 @@ nl:
|
|||
delete: Verwijderen
|
||||
priority: Prioriteit
|
||||
priority_help: Prioritaire persona's worden bovenaan de personalijst weergegeven voor gebruikers. Als meerdere persona's prioriteit hebben, worden deze alfabetisch gesorteerd.
|
||||
command_options: "Opdrachtopties"
|
||||
tool_options: "Opdrachtopties"
|
||||
uploads:
|
||||
title: "Uploads"
|
||||
uploading: "Uploaden..."
|
||||
|
|
|
@ -137,7 +137,7 @@ pl_PL:
|
|||
temperature_help: Temperatura do zastosowania w LLM, zwiększ, aby zwiększyć kreatywność (pozostaw puste, aby użyć domyślnego modelu, zazwyczaj wartość od 0,0 do 2,0)
|
||||
priority: Priorytet
|
||||
priority_help: Priorytetowe persony są wyświetlane użytkownikom na górze listy person. Jeśli wiele person ma priorytet, zostaną one posortowane alfabetycznie.
|
||||
command_options: "Opcje poleceń"
|
||||
tool_options: "Opcje poleceń"
|
||||
uploads:
|
||||
title: "Pliki"
|
||||
button: "Dodaj pliki"
|
||||
|
|
|
@ -112,7 +112,7 @@ pt_BR:
|
|||
delete: Excluir
|
||||
priority: Prioridade
|
||||
priority_help: Personas de prioridade são exibidas aos(às) usuários(as) no topo da lista de personas. Se várias personas tiverem prioridade, serão escolhidas em ordem alfabética.
|
||||
command_options: "Opções de comando"
|
||||
tool_options: "Opções de comando"
|
||||
uploads:
|
||||
title: "Envios"
|
||||
uploading: "Enviando..."
|
||||
|
|
|
@ -111,7 +111,7 @@ ru:
|
|||
delete: Удалить
|
||||
priority: Приоритет
|
||||
priority_help: Приоритетные персоны показываются пользователям вверху списка персон. Если приоритет имеют несколько персон, они будут отсортированы в алфавитном порядке.
|
||||
command_options: "Параметры команды"
|
||||
tool_options: "Параметры команды"
|
||||
uploads:
|
||||
title: "Загрузки"
|
||||
uploading: "Загрузка…"
|
||||
|
|
|
@ -153,7 +153,7 @@ tr_TR:
|
|||
top_p_help: LLM için kullanılacak en yüksek P, rastgeleliği artırmak için artırın (model varsayılanını kullanmak için boş bırakın, genellikle 0.0 ila 1.0 arasında bir değer)
|
||||
priority: Öncelik
|
||||
priority_help: Öncelikli kişilikler kullanıcılara kişilik listesinin en üstünde gösterilir. Birden fazla kişiliğin önceliği varsa bunlar alfabetik olarak sıralanır.
|
||||
command_options: "Komut Seçenekleri"
|
||||
tool_options: "Komut Seçenekleri"
|
||||
what_are_personas: "Yapay Zeka Personaları nedir?"
|
||||
no_persona_selected: |
|
||||
YZ Kişilikleri, Discourse forumunuzda YZ motorunun davranışını özelleştirebilmenizi sağlayan güçlü bir özelliktir. YZ'nin yanıt ve etkileşimlerine rehberlik eden bir "sistem mesajı" görevi görerek daha kişiselleştirilmiş ve etkileşimli bir kullanıcı deneyimi oluşturmaya yardımcı olurlar.
|
||||
|
|
|
@ -128,7 +128,7 @@ zh_CN:
|
|||
top_p_help: 用于 LLM 的 Top P,增大它可提升创造力(留空以使用模型默认值,通常为 0.0 到 1.0 之间的值)
|
||||
priority: 优先
|
||||
priority_help: 优先角色会在角色列表的顶部向用户显示。如果多个角色都具有优先级,将按字母顺序排序。
|
||||
command_options: "命令选项"
|
||||
tool_options: "命令选项"
|
||||
uploads:
|
||||
title: "上传"
|
||||
uploading: "正在上传…"
|
||||
|
|
|
@ -151,7 +151,7 @@ ar:
|
|||
topic_not_found: "الملخص غير متوفر، الموضوع غير موجود!"
|
||||
summarizing: "جارٍ تلخيص الموضوع"
|
||||
searching: "جارٍ البحث عن: '%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "الحد الأقصى لعدد النتائج"
|
||||
|
@ -159,7 +159,7 @@ ar:
|
|||
base_query:
|
||||
name: "استعلام البحث الأساسي"
|
||||
description: "استعلام البحث الأساسي الذي سيتم استخدامه عند البحث. على سبيل المثال: سيسبق \"#urgent\" \"#urgent\" في استعلام البحث وسيتضمن الموضوعات ذات الفئة أو الوسم العاجل فقط."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "إدراج الفئات"
|
||||
search: "البحث"
|
||||
tags: "إدراج الوسوم"
|
||||
|
@ -172,7 +172,7 @@ ar:
|
|||
schema: "البحث عن مخطط قاعدة البيانات"
|
||||
search_settings: "جارٍ البحث في إعدادات الموقع"
|
||||
dall_e: "إنشاء صورة"
|
||||
command_help:
|
||||
tool_help:
|
||||
categories: "إدراج جميع الفئات المرئية بشكلٍ عام في المنتدى"
|
||||
search: "البحث في جميع الموضوعات العامة في المنتدى"
|
||||
tags: "إدراج جميع الوسوم في المنتدى"
|
||||
|
@ -185,7 +185,7 @@ ar:
|
|||
schema: "البحث عن مخطط قاعدة البيانات"
|
||||
search_settings: "البحث في إعدادات الموقع"
|
||||
dall_e: "إنشاء صورة باستخدام DALL-E 3"
|
||||
command_description:
|
||||
tool_description:
|
||||
read: "القراءة: <a href='%{url}'>%{title}</a>"
|
||||
time: "الوقت في المنطقة الزمنية %{timezone} هو %{time}"
|
||||
summarize: "تم تلخيص <a href='%{url}'>%{title}</a>"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
be:
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Пошук"
|
||||
sentiment:
|
||||
reports:
|
||||
|
|
|
@ -10,7 +10,7 @@ bg:
|
|||
yaxis: "Дата"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Търсене"
|
||||
time: "Време "
|
||||
summarize: "Обобщаване"
|
||||
|
|
|
@ -10,6 +10,6 @@ bs_BA:
|
|||
yaxis: "Datum"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Pretraži"
|
||||
time: "Vrijeme"
|
||||
|
|
|
@ -10,7 +10,7 @@ ca:
|
|||
yaxis: "Data"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Cerca"
|
||||
time: "Hora"
|
||||
sentiment:
|
||||
|
|
|
@ -10,7 +10,7 @@ cs:
|
|||
yaxis: "Datum"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Vyhledat"
|
||||
tags: "Seznam značek"
|
||||
time: "Čas"
|
||||
|
|
|
@ -10,7 +10,7 @@ da:
|
|||
yaxis: "Dato"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Søg"
|
||||
time: "Tidspunkt"
|
||||
sentiment:
|
||||
|
|
|
@ -193,7 +193,7 @@ de:
|
|||
topic_not_found: "Zusammenfassung nicht verfügbar, Thema nicht gefunden!"
|
||||
summarizing: "Thema zusammenfassen"
|
||||
searching: "Suche nach: „%{query}“"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
search_private:
|
||||
name: "Suche Privat"
|
||||
|
@ -204,7 +204,7 @@ de:
|
|||
base_query:
|
||||
name: "Basissuchanfrage"
|
||||
description: "Basisanfrage, die bei der Suche verwendet wird. Beispiel: Bei „#dringend“ wird der Suchanfrage „#dringend“ vorangestellt und es werden nur Themen mit der Kategorie oder dem Schlagwort „dringend“ angezeigt."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
web_browser: "Web durchsuchen"
|
||||
github_search_files: "GitHub Datei-Suche"
|
||||
github_search_code: "GitHub Code-Suche"
|
||||
|
@ -225,7 +225,7 @@ de:
|
|||
dall_e: "Bild generieren"
|
||||
search_meta_discourse: "Suche Meta Discourse"
|
||||
javascript_evaluator: "JavaScript auswerten"
|
||||
command_help:
|
||||
tool_help:
|
||||
web_browser: "Webseite mit dem KI Bot durchsuchen"
|
||||
github_search_code: "Suche nach Code in einem GitHub-Repository"
|
||||
github_search_files: "Suche nach Dateien in einem GitHub-Repository"
|
||||
|
@ -246,7 +246,7 @@ de:
|
|||
dall_e: "Bild mit DALL-E 3 generieren"
|
||||
search_meta_discourse: "Suche Meta Discourse"
|
||||
javascript_evaluator: "JavaScript auswerten"
|
||||
command_description:
|
||||
tool_description:
|
||||
web_browser: "Lesen <a href='%{url}'>%{url}</a>"
|
||||
github_search_files: "Gesucht wurde nach '%{keywords}' in %{repo}/%{branch}"
|
||||
github_search_code: "Gesucht wurde nach '%{query}' in %{repo}"
|
||||
|
|
|
@ -10,6 +10,6 @@ el:
|
|||
yaxis: "Ημερομηνία"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Αναζήτηση"
|
||||
time: "Ώρα"
|
||||
|
|
|
@ -175,7 +175,7 @@ en:
|
|||
personas:
|
||||
default_llm_required: "Default LLM model is required prior to enabling Chat"
|
||||
cannot_delete_system_persona: "System personas cannot be deleted, please disable it instead"
|
||||
cannot_edit_system_persona: "System personas can only be renamed, you may not edit commands or system prompt, instead disable and make a copy"
|
||||
cannot_edit_system_persona: "System personas can only be renamed, you may not edit tools or system prompt, instead disable and make a copy"
|
||||
github_helper:
|
||||
name: "GitHub Helper"
|
||||
description: "AI Bot specialized in assisting with GitHub-related tasks and questions"
|
||||
|
@ -206,7 +206,7 @@ en:
|
|||
topic_not_found: "Summary unavailable, topic not found!"
|
||||
summarizing: "Summarizing topic"
|
||||
searching: "Searching for: '%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
search_private:
|
||||
name: "Search Private"
|
||||
|
@ -217,7 +217,7 @@ en:
|
|||
base_query:
|
||||
name: "Base Search Query"
|
||||
description: "Base query to use when searching. Example: '#urgent' will prepend '#urgent' to the search query and only include topics with the urgent category or tag."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
web_browser: "Browse Web"
|
||||
github_search_files: "GitHub search files"
|
||||
github_search_code: "GitHub code search"
|
||||
|
@ -238,7 +238,7 @@ en:
|
|||
dall_e: "Generate image"
|
||||
search_meta_discourse: "Search Meta Discourse"
|
||||
javascript_evaluator: "Evaluate JavaScript"
|
||||
command_help:
|
||||
tool_help:
|
||||
web_browser: "Browse web page using the AI Bot"
|
||||
github_search_code: "Search for code in a GitHub repository"
|
||||
github_search_files: "Search for files in a GitHub repository"
|
||||
|
@ -259,7 +259,7 @@ en:
|
|||
dall_e: "Generate image using DALL-E 3"
|
||||
search_meta_discourse: "Search Meta Discourse"
|
||||
javascript_evaluator: "Evaluate JavaScript"
|
||||
command_description:
|
||||
tool_description:
|
||||
web_browser: "Reading <a href='%{url}'>%{url}</a>"
|
||||
github_search_files: "Searched for '%{keywords}' in %{repo}/%{branch}"
|
||||
github_search_code: "Searched for '%{query}' in %{repo}"
|
||||
|
|
|
@ -151,7 +151,7 @@ es:
|
|||
topic_not_found: "¡Resumen no disponible, tema no encontrado!"
|
||||
summarizing: "Resumiendo tema"
|
||||
searching: "Buscando: '%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "Número máximo de resultados"
|
||||
|
@ -159,7 +159,7 @@ es:
|
|||
base_query:
|
||||
name: "Consulta de búsqueda básica"
|
||||
description: "Consulta base a utilizar en la búsqueda. Ejemplo: «#urgente» antepondrá «#urgente» a la consulta de búsqueda y solo incluirá temas con la categoría o etiqueta urgente."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "Lista de categorías"
|
||||
search: "Buscar"
|
||||
tags: "Listar etiquetas"
|
||||
|
@ -172,7 +172,7 @@ es:
|
|||
schema: "Buscar esquema de base de datos"
|
||||
search_settings: "Buscando los ajustes del sitio"
|
||||
dall_e: "Generar imagen"
|
||||
command_help:
|
||||
tool_help:
|
||||
categories: "Listar todas las categorías visibles públicamente en el foro"
|
||||
search: "Buscar todos los temas públicos en el foro."
|
||||
tags: "Listar todas las etiquetas en el foro"
|
||||
|
@ -185,7 +185,7 @@ es:
|
|||
schema: "Buscar esquema de base de datos"
|
||||
search_settings: "Buscar ajustes del sitio"
|
||||
dall_e: "Generar imagen usando DALL-E 3"
|
||||
command_description:
|
||||
tool_description:
|
||||
read: "Leyendo: <a href='%{url}'>%{title}</a>"
|
||||
time: "La hora en %{timezone} es %{time}"
|
||||
summarize: "Resumido <a href='%{url}'>%{title}</a>"
|
||||
|
|
|
@ -10,7 +10,7 @@ et:
|
|||
yaxis: "Date"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Otsi"
|
||||
time: "Aeg"
|
||||
sentiment:
|
||||
|
|
|
@ -19,7 +19,7 @@ fa_IR:
|
|||
personas:
|
||||
dall_e3:
|
||||
name: "DALL-E 3"
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "فهرست دستهبندیها"
|
||||
search: "جستجو"
|
||||
tags: "فهرست برچسبها"
|
||||
|
@ -28,7 +28,7 @@ fa_IR:
|
|||
image: "تولید تصویر"
|
||||
google: "جستجو در گوگل"
|
||||
dall_e: "تولید تصویر"
|
||||
command_description:
|
||||
tool_description:
|
||||
summarize: "خلاصه شده <a href='%{url}'>%{title}</a>"
|
||||
dall_e: "%{prompt}"
|
||||
image: "%{prompt}"
|
||||
|
|
|
@ -151,7 +151,7 @@ fi:
|
|||
topic_not_found: "Yhteenveto ei ole saatavilla, ketjua ei löydy!"
|
||||
summarizing: "Laaditaan yhteenvetoa ketjusta"
|
||||
searching: "Haetaan: \"%{query}\""
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "Tulosten enimmäismäärä"
|
||||
|
@ -159,7 +159,7 @@ fi:
|
|||
base_query:
|
||||
name: "Perushakukysely"
|
||||
description: "Peruskysely, jota käytetään haussa. Esimerkki: \"#kiireellinen\" lisää hakukyselyn alkuun \"#kiireellinen\" ja sisältää vain ketjut, joissa on kiireellinen alue tai tunniste."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "Listaa alueet"
|
||||
search: "Haku"
|
||||
tags: "Listaa tunnisteet"
|
||||
|
@ -172,7 +172,7 @@ fi:
|
|||
schema: "Etsi tietokantaskeema"
|
||||
search_settings: "Haetaan sivustoasetuksia"
|
||||
dall_e: "Luo kuva"
|
||||
command_help:
|
||||
tool_help:
|
||||
categories: "Listaa kaikki foorumin julkisesti näkyvät alueet"
|
||||
search: "Hae kaikista foorumin julkisista ketjuista"
|
||||
tags: "Listaa kaikki foorumin tunnisteet"
|
||||
|
@ -185,7 +185,7 @@ fi:
|
|||
schema: "Etsi tietokantaskeema"
|
||||
search_settings: "Hae sivustoasetuksia"
|
||||
dall_e: "Luo kuva DALL-E 3:lla"
|
||||
command_description:
|
||||
tool_description:
|
||||
read: "Luetaan: <a href='%{url}'>%{title}</a>"
|
||||
time: "Aika aikavyöhykkeellä %{timezone} on %{time}"
|
||||
summarize: "Yhteenveto: <a href='%{url}'>%{title}</a>"
|
||||
|
|
|
@ -151,7 +151,7 @@ fr:
|
|||
topic_not_found: "Résumé indisponible, sujet introuvable !"
|
||||
summarizing: "Synthèse du sujet"
|
||||
searching: "Recherche de : '%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "Nombre maximal de résultats"
|
||||
|
@ -159,7 +159,7 @@ fr:
|
|||
base_query:
|
||||
name: "Requête de recherche de base"
|
||||
description: "Requête de base à utiliser lors de la recherche. Exemple : « #urgent » ajoutera « #urgent » à la requête de recherche et inclura uniquement les sujets avec la catégorie ou l'étiquette correspondante."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "Lister les catégories"
|
||||
search: "Rechercher"
|
||||
tags: "Répertorier les étiquettes"
|
||||
|
@ -172,7 +172,7 @@ fr:
|
|||
schema: "Rechercher le schéma de la base de données"
|
||||
search_settings: "Recherche des paramètres du site"
|
||||
dall_e: "Générer une image"
|
||||
command_help:
|
||||
tool_help:
|
||||
categories: "Répertoriez toutes les catégories visibles publiquement sur le forum"
|
||||
search: "Rechercher dans tous les sujets publics sur le forum"
|
||||
tags: "Répertorier toutes les étiquettes du forum"
|
||||
|
@ -185,7 +185,7 @@ fr:
|
|||
schema: "Rechercher le schéma de la base de données"
|
||||
search_settings: "Paramètres du site de recherche"
|
||||
dall_e: "Générer une image à l'aide de DALL-E 3"
|
||||
command_description:
|
||||
tool_description:
|
||||
read: "Lecture : <a href='%{url}'>%{title}</a>"
|
||||
time: "L'heure (%{timezone}) est %{time}"
|
||||
summarize: "Résumé de <a href='%{url}'>%{title}</a>"
|
||||
|
|
|
@ -10,7 +10,7 @@ gl:
|
|||
yaxis: "Data"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Buscar"
|
||||
time: "Hora"
|
||||
sentiment:
|
||||
|
|
|
@ -192,7 +192,7 @@ he:
|
|||
topic_not_found: "תקציר לא זמין, לא נמצא נושא!"
|
||||
summarizing: "הנושא מסוכם"
|
||||
searching: "חיפוש אחר: ‚%{query}’"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
search_private:
|
||||
name: "חיפוש פרטי"
|
||||
|
@ -203,7 +203,7 @@ he:
|
|||
base_query:
|
||||
name: "שאילתת חיפוש בסיסית"
|
||||
description: "שאילתת בסיס לשימוש בעת חיפוש. למשל: ‚#urgent’ יוסיף את ‚#urgent’ לשאילתת החיפוש ויכלול רק נושאים עם הקטגוריה או התגית urgent (דחוף)."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
web_browser: "גלישה באינטרנט"
|
||||
github_search_files: "חיפוש קבצים ב־GitHub"
|
||||
github_search_code: "חיפוש קוד ב־GitHub"
|
||||
|
@ -224,7 +224,7 @@ he:
|
|||
dall_e: "יצירת תמונה"
|
||||
search_meta_discourse: "חיפוש ב־Meta Discrouse"
|
||||
javascript_evaluator: "שערוך JavaScript"
|
||||
command_help:
|
||||
tool_help:
|
||||
web_browser: "גלישה באינטרנט באמצעות בוט בינה מלאכותית"
|
||||
github_search_code: "חיפוש אחר קוד במאגר GitHub"
|
||||
github_search_files: "חיפוש אחר קבצים במאגר GitHub"
|
||||
|
@ -245,7 +245,7 @@ he:
|
|||
dall_e: "יצירת תמונה באמצעות DALL-E 3"
|
||||
search_meta_discourse: "חיפוש ב־Meta Discrouse"
|
||||
javascript_evaluator: "שערוך JavaScript"
|
||||
command_description:
|
||||
tool_description:
|
||||
web_browser: "קורא את <a href='%{url}'>%{url}</a>"
|
||||
github_search_files: "בוצע חיפוש אחר ‚%{keywords}’ בתוך %{repo}/%{branch}"
|
||||
github_search_code: "בוצע חיפוש אחר ‚%{query}’ בתוך %{repo}"
|
||||
|
|
|
@ -10,7 +10,7 @@ hr:
|
|||
yaxis: "Datum"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Pretraživanje"
|
||||
time: "Vrijeme"
|
||||
summarize: "Rezimirati"
|
||||
|
|
|
@ -10,7 +10,7 @@ hu:
|
|||
yaxis: "Dátum"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Keresés"
|
||||
tags: "Címkék listázása"
|
||||
time: "Idő"
|
||||
|
|
|
@ -10,7 +10,7 @@ hy:
|
|||
yaxis: "Ամսաթիվ"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Որոնում"
|
||||
time: "Ժամ"
|
||||
sentiment:
|
||||
|
|
|
@ -71,19 +71,19 @@ id:
|
|||
ai_bot:
|
||||
personas:
|
||||
default_llm_required: "Model LLM default diperlukan sebelum mengaktifkan Obrolan"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
search_private:
|
||||
name: "Pencarian Pribadi"
|
||||
description: "Sertakan semua topik yang dapat diakses pengguna dalam hasil pencarian (secara bawaan hanya topik publik yang disertakan)"
|
||||
command_summary:
|
||||
tool_summary:
|
||||
github_search_files: "File pencarian GitHub"
|
||||
search: "Cari"
|
||||
time: "Waktu"
|
||||
summarize: "Meringkas"
|
||||
command_help:
|
||||
tool_help:
|
||||
github_search_files: "Cari file di repositori GitHub"
|
||||
summary: "Meringkas suatu topik"
|
||||
command_description:
|
||||
tool_description:
|
||||
github_search_files: "Mencari '%{keywords}' di %{repo}/%{branch}"
|
||||
github_search_code: "Mencari '%{query}' di %{repo}"
|
||||
|
|
|
@ -151,7 +151,7 @@ it:
|
|||
topic_not_found: "Riepilogo non disponibile, argomento non trovato!"
|
||||
summarizing: "Riepilogo argomento"
|
||||
searching: "Ricerca di: '%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "Numero massimo di risultati"
|
||||
|
@ -159,7 +159,7 @@ it:
|
|||
base_query:
|
||||
name: "Query di ricerca di base"
|
||||
description: "Query di base da utilizzare durante la ricerca. Esempio: \"#urgente\" anteporrà \"#urgente\" alla query di ricerca e includerà solo gli argomenti con la categoria o l'etichetta urgente."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "Elenca le categorie"
|
||||
search: "Cerca"
|
||||
tags: "Elenca le etichette"
|
||||
|
@ -172,7 +172,7 @@ it:
|
|||
schema: "Cerca lo schema del database"
|
||||
search_settings: "Ricerca nelle impostazioni del sito"
|
||||
dall_e: "Genera immagine"
|
||||
command_help:
|
||||
tool_help:
|
||||
categories: "Elenca tutte le categorie visibili pubblicamente sul forum"
|
||||
search: "Cerca tutti gli argomenti pubblici sul forum"
|
||||
tags: "Elenca tutte le etichette sul forum"
|
||||
|
@ -185,7 +185,7 @@ it:
|
|||
schema: "Cerca lo schema del database"
|
||||
search_settings: "Cerca le impostazioni del sito"
|
||||
dall_e: "Genera immagine utilizzando DALL-E 3"
|
||||
command_description:
|
||||
tool_description:
|
||||
read: "Lettura: <a href='%{url}'>%{title}</a>"
|
||||
time: "L'orario in %{timezone} è %{time}"
|
||||
summarize: "Riassunto di <a href='%{url}'>%{title}</a>"
|
||||
|
|
|
@ -151,7 +151,7 @@ ja:
|
|||
topic_not_found: "要約がありません。トピックが見つかりません!"
|
||||
summarizing: "トピックの要約を生成中"
|
||||
searching: "検索中: '%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "結果の最大件数"
|
||||
|
@ -159,7 +159,7 @@ ja:
|
|||
base_query:
|
||||
name: "ベース検索クエリ"
|
||||
description: "検索時に使用するベースクエリ。例: '#urgent' は検索クエリの先頭に '#urgent' を追加し、緊急のカテゴリまたはタグを持つトピックのみが含まれます。"
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "カテゴリをリスト表示"
|
||||
search: "検索"
|
||||
tags: "タグをリスト"
|
||||
|
@ -172,7 +172,7 @@ ja:
|
|||
schema: "データベーススキーマを検索"
|
||||
search_settings: "サイト設定を検索中"
|
||||
dall_e: "画像を生成"
|
||||
command_help:
|
||||
tool_help:
|
||||
categories: "フォーラムのすべての公開カテゴリをリストします"
|
||||
search: "フォーラムのすべての公開トピックを検索します"
|
||||
tags: "フォーラムのすべてのタグをリストします"
|
||||
|
@ -185,7 +185,7 @@ ja:
|
|||
schema: "データベーススキーマを検索します"
|
||||
search_settings: "サイト設定を検索します"
|
||||
dall_e: "DALL-E 3 を使って画像を生成します"
|
||||
command_description:
|
||||
tool_description:
|
||||
read: "読み取り中: <a href='%{url}'>%{title}</a>"
|
||||
time: "%{timezone} の時刻は %{time} です"
|
||||
summarize: "<a href='%{url}'>%{title}</a> の要約"
|
||||
|
|
|
@ -10,7 +10,7 @@ ko:
|
|||
yaxis: "날짜"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "검색"
|
||||
time: "시간"
|
||||
summarize: "요약하기"
|
||||
|
|
|
@ -17,7 +17,7 @@ lt:
|
|||
image_caption:
|
||||
attribution: "Antraštė teikiama AI"
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Paieška"
|
||||
time: "Laikas"
|
||||
summarize: "Apibendrinti"
|
||||
|
|
|
@ -10,6 +10,6 @@ lv:
|
|||
yaxis: "Datums"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Meklēt"
|
||||
time: "Laiks"
|
||||
|
|
|
@ -10,6 +10,6 @@ nb_NO:
|
|||
yaxis: "Dato"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Søk"
|
||||
time: "Tid"
|
||||
|
|
|
@ -151,7 +151,7 @@ nl:
|
|||
topic_not_found: "Samenvatting niet beschikbaar, topic niet gevonden!"
|
||||
summarizing: "Topic samenvatten"
|
||||
searching: "Zoeken naar: '%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "Maximaal aantal resultaten"
|
||||
|
@ -159,7 +159,7 @@ nl:
|
|||
base_query:
|
||||
name: "Basiszoekopdracht"
|
||||
description: "Basisquery om te gebruiken bij het zoeken. Voorbeeld: '#urgent' voegt '#urgent' toe aan de zoekquery en neemt alleen topics mee met de categorie of tag 'urgent'."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "Categorieën weergeven"
|
||||
search: "Zoeken"
|
||||
tags: "Tags weergeven"
|
||||
|
@ -172,7 +172,7 @@ nl:
|
|||
schema: "Databaseschema opzoeken"
|
||||
search_settings: "Zoeken in site-instellingen"
|
||||
dall_e: "Afbeelding genereren"
|
||||
command_help:
|
||||
tool_help:
|
||||
categories: "Geef een lijst weer van alle openbaar zichtbare categorieën op het forum"
|
||||
search: "Doorzoek alle openbare topics op het forum"
|
||||
tags: "Geef een lijst weer van alle tags op het forum"
|
||||
|
@ -185,7 +185,7 @@ nl:
|
|||
schema: "Zoek een databaseschema op"
|
||||
search_settings: "Zoek site-instellingen"
|
||||
dall_e: "Genereer een afbeelding met DALL-E 3"
|
||||
command_description:
|
||||
tool_description:
|
||||
read: "Lezen: <a href='%{url}'>%{title}</a>"
|
||||
time: "De tijd in %{timezone} is %{time}"
|
||||
summarize: "<a href='%{url}'>%{title}</a> samengevat"
|
||||
|
|
|
@ -150,7 +150,7 @@ pl_PL:
|
|||
topic_not_found: "Podsumowanie niedostępne, nie znaleziono tematu!"
|
||||
summarizing: "Podsumowanie tematu"
|
||||
searching: "Wyszukiwanie: '%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "Maksymalna liczba wyników"
|
||||
|
@ -158,7 +158,7 @@ pl_PL:
|
|||
base_query:
|
||||
name: "Podstawowe zapytanie wyszukiwania"
|
||||
description: "Podstawowe zapytanie używane podczas wyszukiwania. Przykład: '#pilne' spowoduje dodanie '#pilne' do zapytania wyszukiwania i uwzględnienie tylko tematów z kategorią lub tagiem pilne."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
random_picker: "Losowy selektor"
|
||||
categories: "Wymień kategorie"
|
||||
search: "Szukaj"
|
||||
|
@ -172,7 +172,7 @@ pl_PL:
|
|||
schema: "Wyszukaj schemat bazy danych"
|
||||
search_settings: "Wyszukiwanie ustawień witryny"
|
||||
dall_e: "Wygeneruj obraz"
|
||||
command_help:
|
||||
tool_help:
|
||||
random_picker: "Wybierz losową liczbę lub losowy element listy"
|
||||
categories: "Wyświetl wszystkie publicznie widoczne kategorie na forum"
|
||||
search: "Przeszukaj wszystkie publiczne tematy na forum"
|
||||
|
@ -186,7 +186,7 @@ pl_PL:
|
|||
schema: "Wyszukaj schemat bazy danych"
|
||||
search_settings: "Wyszukaj ustawienia witryny"
|
||||
dall_e: "Wygeneruj obraz za pomocą DALL-E 3"
|
||||
command_description:
|
||||
tool_description:
|
||||
random_picker: "Wybieranie z %{options}, wybrane: %{result}"
|
||||
read: "Czytanie: <a href='%{url}'>%{title}</a>"
|
||||
time: "Czas w %{timezone} wynosi %{time}"
|
||||
|
|
|
@ -10,7 +10,7 @@ pt:
|
|||
yaxis: "Data"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Pesquisar"
|
||||
time: "Hora"
|
||||
summarize: "Resumir"
|
||||
|
|
|
@ -151,7 +151,7 @@ pt_BR:
|
|||
topic_not_found: "Resumo indisponível, tópico não encontrado!"
|
||||
summarizing: "Resumindo tópico"
|
||||
searching: "Pesquisando: \"%{query}\""
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "O número máximo de resultados"
|
||||
|
@ -159,7 +159,7 @@ pt_BR:
|
|||
base_query:
|
||||
name: "Consulta de pesquisa básica"
|
||||
description: "A consulta de base para usar ao pesquisar. Exemplo: \"#urgent\" precederá \"#urgent\" para a consulta de pesquisa e incluirá apenas tópicos com a etiqueta ou categoria urgente."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "Listar categorias"
|
||||
search: "Pesquisar"
|
||||
tags: "Listar etiquetas"
|
||||
|
@ -172,7 +172,7 @@ pt_BR:
|
|||
schema: "Procurar esquema de banco de dados"
|
||||
search_settings: "Pesquisando configurações do site"
|
||||
dall_e: "Gerar imagem"
|
||||
command_help:
|
||||
tool_help:
|
||||
categories: "Listar todas as categorias visíveis publicamente no fórum"
|
||||
search: "Pesquisar todos os tópicos públicos no fórum"
|
||||
tags: "Listar todas as etiquetas no fórum"
|
||||
|
@ -185,7 +185,7 @@ pt_BR:
|
|||
schema: "Procurar esquema de banco de dados"
|
||||
search_settings: "Pesquisar configurações do site"
|
||||
dall_e: "Gerar imagem usando DALL-E 3"
|
||||
command_description:
|
||||
tool_description:
|
||||
read: "Lendo: <a href='%{url}'>%{title}</a>"
|
||||
time: "A hora em %{timezone} é %{time}"
|
||||
summarize: "Resumo de <a href='%{url}'>%{title}</a>"
|
||||
|
|
|
@ -10,7 +10,7 @@ ro:
|
|||
yaxis: "Dată"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Caută"
|
||||
time: "Oră"
|
||||
summarize: "Rezumat"
|
||||
|
|
|
@ -151,7 +151,7 @@ ru:
|
|||
topic_not_found: "Сводка недоступна: тема не найдена!"
|
||||
summarizing: "Аналитик темы"
|
||||
searching: "Поиск: '%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "Максимальное количество результатов"
|
||||
|
@ -159,7 +159,7 @@ ru:
|
|||
base_query:
|
||||
name: "Базовый поисковый запрос"
|
||||
description: "Базовый запрос, используемый при поиске. Пример: '#urgent' добавит '#urgent' к поисковому запросу и будет включать только темы со срочной категорией или тегом."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "Вывод списка категорий"
|
||||
search: "Поиск"
|
||||
tags: "Вывод списка тегов"
|
||||
|
@ -172,7 +172,7 @@ ru:
|
|||
schema: "Найти схему базы данных"
|
||||
search_settings: "Поиск настроек сайта"
|
||||
dall_e: "Сгенерировать изображение"
|
||||
command_help:
|
||||
tool_help:
|
||||
categories: "Вывод всех общедоступных категорий на форуме"
|
||||
search: "Поиск по всем общедоступным темам на форуме"
|
||||
tags: "Вывод всех тегов на форуме"
|
||||
|
@ -185,7 +185,7 @@ ru:
|
|||
schema: "Найти схему базы данных"
|
||||
search_settings: "Настройки поиска по сайту"
|
||||
dall_e: "Создать изображение с помощью DALL-E 3"
|
||||
command_description:
|
||||
tool_description:
|
||||
read: "Чтение: <a href='%{url}'>%{title}</a>"
|
||||
time: "Время по часовому поясу %{timezone} — %{time}"
|
||||
summarize: "Получена сводка: <a href='%{url}'>%{title}</a>"
|
||||
|
|
|
@ -10,7 +10,7 @@ sk:
|
|||
yaxis: "Dátum"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Hľadať"
|
||||
tags: "Zoznam značiek"
|
||||
time: "Čas"
|
||||
|
|
|
@ -10,6 +10,6 @@ sl:
|
|||
yaxis: "Datum"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Išči"
|
||||
time: "Čas"
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
sq:
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Kërko"
|
||||
time: "Koha"
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
sr:
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Pretraži"
|
||||
time: "Vreme"
|
||||
|
|
|
@ -10,7 +10,7 @@ sv:
|
|||
yaxis: "Datum"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Sök"
|
||||
time: "Tid"
|
||||
summarize: "Sammanfatta"
|
||||
|
|
|
@ -10,6 +10,6 @@ sw:
|
|||
yaxis: "Tarehe"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Tafuta"
|
||||
time: "Muda"
|
||||
|
|
|
@ -10,7 +10,7 @@ te:
|
|||
yaxis: "తేదీ"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "వెతుకు"
|
||||
time: "కాలం"
|
||||
sentiment:
|
||||
|
|
|
@ -10,6 +10,6 @@ th:
|
|||
yaxis: "วันที่"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "ค้นหา"
|
||||
time: "เวลา"
|
||||
|
|
|
@ -187,7 +187,7 @@ tr_TR:
|
|||
topic_not_found: "Özet mevcut değil, konu bulunamadı!"
|
||||
summarizing: "Konu özetleniyor"
|
||||
searching: "Aranıyor: '%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "Maksimum sonuç sayısı"
|
||||
|
@ -195,7 +195,7 @@ tr_TR:
|
|||
base_query:
|
||||
name: "Temel Arama Sorgusu"
|
||||
description: "Arama yaparken kullanılacak temel sorgu. Örnek: '#urgent', arama sorgusuna '#urgent' ekler ve yalnızca acil kategorisine veya etiketine sahip konuları içerir."
|
||||
command_summary:
|
||||
tool_summary:
|
||||
web_browser: "Web'e Gözat"
|
||||
github_search_code: "GitHub kodu arama"
|
||||
github_file_content: "GitHub dosya içeriği"
|
||||
|
@ -214,7 +214,7 @@ tr_TR:
|
|||
search_settings: "Site ayarları aranıyor"
|
||||
dall_e: "Görüntü oluştur"
|
||||
search_meta_discourse: "Discourse Metada arama yapın"
|
||||
command_help:
|
||||
tool_help:
|
||||
web_browser: "Yapay Zeka Botunu kullanarak web sayfasına göz atın"
|
||||
github_search_code: "GitHub deposunda kod arama"
|
||||
github_file_content: "Bir GitHub deposundan dosyaların içeriğini alma"
|
||||
|
@ -233,7 +233,7 @@ tr_TR:
|
|||
search_settings: "Site ayarlarını ara"
|
||||
dall_e: "DALL-E 3 kullanarak görüntü oluştur"
|
||||
search_meta_discourse: "Discourse Metada arama yapın"
|
||||
command_description:
|
||||
tool_description:
|
||||
web_browser: "Okunuyor <a href='%{url}'>%{url}</a>"
|
||||
github_search_code: "%{repo} içinde '%{query}' araması yapıldı"
|
||||
github_pull_request_diff: "<a href='%{url}'>%{repo} %{pull_id}</a>"
|
||||
|
|
|
@ -10,7 +10,7 @@ ug:
|
|||
yaxis: "چېسلا"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "ئىزدە"
|
||||
tags: "بەلگە تىزىمىنى كۆرسىتىدۇ"
|
||||
time: "ۋاقىت"
|
||||
|
|
|
@ -10,7 +10,7 @@ uk:
|
|||
yaxis: "Дата"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Пошук"
|
||||
tags: "Список тегів"
|
||||
time: "Час"
|
||||
|
|
|
@ -10,7 +10,7 @@ ur:
|
|||
yaxis: "تاریخ"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "تلاش کریں"
|
||||
time: "وقت"
|
||||
summarize: "خلاصہ"
|
||||
|
|
|
@ -10,7 +10,7 @@ vi:
|
|||
yaxis: "Ngày"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "Tìm kiếm"
|
||||
time: "Thời gian"
|
||||
summarize: "Tóm tắt"
|
||||
|
|
|
@ -154,7 +154,7 @@ zh_CN:
|
|||
topic_not_found: "总结不可用,找不到话题!"
|
||||
summarizing: "正在总结话题"
|
||||
searching: "搜索:'%{query}'"
|
||||
command_options:
|
||||
tool_options:
|
||||
search:
|
||||
max_results:
|
||||
name: "最大结果数"
|
||||
|
@ -162,7 +162,7 @@ zh_CN:
|
|||
base_query:
|
||||
name: "基本搜索查询"
|
||||
description: "搜索时要使用的基本查询。示例:'#urgent' 会在搜索查询前面加上 '#urgent',并且仅包含具有紧急类别或标签的话题。"
|
||||
command_summary:
|
||||
tool_summary:
|
||||
categories: "列出类别"
|
||||
search: "搜索"
|
||||
tags: "列出标签"
|
||||
|
@ -175,7 +175,7 @@ zh_CN:
|
|||
schema: "查找数据库架构"
|
||||
search_settings: "正在搜索站点设置"
|
||||
dall_e: "生成图片"
|
||||
command_help:
|
||||
tool_help:
|
||||
categories: "列出论坛上所有公开可见的类别"
|
||||
search: "搜索论坛上的所有公共话题"
|
||||
tags: "列出论坛上的所有标签"
|
||||
|
@ -188,7 +188,7 @@ zh_CN:
|
|||
schema: "查找数据库架构"
|
||||
search_settings: "搜索站点设置"
|
||||
dall_e: "使用 DALL-E 3 生成图片"
|
||||
command_description:
|
||||
tool_description:
|
||||
read: "阅读:<a href='%{url}'>%{title}</a>"
|
||||
time: "%{timezone} 的时间为 %{time}"
|
||||
summarize: "已总结 <a href='%{url}'>%{title}</a>"
|
||||
|
|
|
@ -10,7 +10,7 @@ zh_TW:
|
|||
yaxis: "日期"
|
||||
discourse_ai:
|
||||
ai_bot:
|
||||
command_summary:
|
||||
tool_summary:
|
||||
search: "搜尋"
|
||||
time: "時間"
|
||||
summarize: "總結"
|
||||
|
|
|
@ -32,7 +32,7 @@ DiscourseAi::AiBot::Personas::Persona.system_personas.each do |persona_class, id
|
|||
|
||||
persona.system = true
|
||||
instance = persona_class.new
|
||||
persona.commands = instance.tools.map { |tool| tool.to_s.split("::").last }
|
||||
persona.tools = instance.tools.map { |tool| tool.to_s.split("::").last }
|
||||
persona.system_prompt = instance.system_prompt
|
||||
persona.top_p = instance.top_p
|
||||
persona.temperature = instance.temperature
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ToolDetailsAndCommandRemoval < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :ai_personas, :tool_details, :boolean, default: true, null: false
|
||||
add_column :ai_personas, :tools, :json, null: false, default: []
|
||||
Migration::ColumnDropper.mark_readonly(:ai_personas, :commands)
|
||||
|
||||
execute <<~SQL
|
||||
UPDATE ai_personas
|
||||
SET tools = commands
|
||||
SQL
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
class DropCommandsFromAiPersonas < ActiveRecord::Migration[7.0]
|
||||
def down
|
||||
raise ActiveRecord::IrreversibleMigration
|
||||
end
|
||||
|
||||
def up
|
||||
Migration::ColumnDropper.execute_drop(:ai_personas, [:commands])
|
||||
end
|
||||
end
|
|
@ -420,11 +420,13 @@ module DiscourseAi
|
|||
Discourse.redis.setex(redis_stream_key, 60, 1)
|
||||
end
|
||||
|
||||
context[:skip_tool_details] ||= !bot.persona.class.tool_details
|
||||
|
||||
new_custom_prompts =
|
||||
bot.reply(context) do |partial, cancel, placeholder|
|
||||
reply << partial
|
||||
raw = reply.dup
|
||||
raw << "\n\n" << placeholder if placeholder.present?
|
||||
raw << "\n\n" << placeholder if placeholder.present? && !context[:skip_tool_details]
|
||||
|
||||
if stream_reply && !Discourse.redis.get(redis_stream_key)
|
||||
cancel&.call
|
||||
|
|
|
@ -13,11 +13,11 @@ module DiscourseAi
|
|||
end
|
||||
|
||||
def localized_name
|
||||
I18n.t("discourse_ai.ai_bot.command_options.#{tool.signature[:name]}.#{name}.name")
|
||||
I18n.t("discourse_ai.ai_bot.tool_options.#{tool.signature[:name]}.#{name}.name")
|
||||
end
|
||||
|
||||
def localized_description
|
||||
I18n.t("discourse_ai.ai_bot.command_options.#{tool.signature[:name]}.#{name}.description")
|
||||
I18n.t("discourse_ai.ai_bot.tool_options.#{tool.signature[:name]}.#{name}.description")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,7 +22,7 @@ module DiscourseAi
|
|||
end
|
||||
|
||||
def help
|
||||
I18n.t("discourse_ai.ai_bot.command_help.#{signature[:name]}")
|
||||
I18n.t("discourse_ai.ai_bot.tool_help.#{signature[:name]}")
|
||||
end
|
||||
|
||||
def custom_system_message
|
||||
|
@ -54,15 +54,15 @@ module DiscourseAi
|
|||
end
|
||||
|
||||
def summary
|
||||
I18n.t("discourse_ai.ai_bot.command_summary.#{name}")
|
||||
I18n.t("discourse_ai.ai_bot.tool_summary.#{name}")
|
||||
end
|
||||
|
||||
def details
|
||||
I18n.t("discourse_ai.ai_bot.command_description.#{name}", description_args)
|
||||
I18n.t("discourse_ai.ai_bot.tool_description.#{name}", description_args)
|
||||
end
|
||||
|
||||
def help
|
||||
I18n.t("discourse_ai.ai_bot.command_help.#{name}")
|
||||
I18n.t("discourse_ai.ai_bot.tool_help.#{name}")
|
||||
end
|
||||
|
||||
def options
|
||||
|
|
|
@ -226,7 +226,7 @@ RSpec.describe DiscourseAi::AiBot::Personas::Persona do
|
|||
name: "zzzpun_bot",
|
||||
description: "you write puns",
|
||||
system_prompt: "you are pun bot",
|
||||
commands: ["ImageCommand"],
|
||||
tools: ["Image"],
|
||||
allowed_group_ids: [Group::AUTO_GROUPS[:trust_level_0]],
|
||||
)
|
||||
|
||||
|
|
|
@ -290,7 +290,7 @@ RSpec.describe DiscourseAi::AiBot::Playground do
|
|||
end
|
||||
|
||||
it "can run tools" do
|
||||
persona.update!(commands: ["TimeCommand"])
|
||||
persona.update!(tools: ["Time"])
|
||||
|
||||
responses = [
|
||||
"<function_calls><invoke><tool_name>time</tool_name><tool_id>time</tool_id><parameters><timezone>Buenos Aires</timezone></parameters></invoke></function_calls>",
|
||||
|
@ -590,6 +590,34 @@ RSpec.describe DiscourseAi::AiBot::Playground do
|
|||
expect(last_post.raw).to include("I found stuff")
|
||||
end
|
||||
|
||||
it "supports disabling tool details" do
|
||||
persona = Fabricate(:ai_persona, tool_details: false, tools: ["Search"])
|
||||
bot = DiscourseAi::AiBot::Bot.as(bot_user, persona: persona.class_instance.new)
|
||||
playground = described_class.new(bot)
|
||||
|
||||
response1 = (<<~TXT).strip
|
||||
<function_calls>
|
||||
<invoke>
|
||||
<tool_name>search</tool_name>
|
||||
<tool_id>search</tool_id>
|
||||
<parameters>
|
||||
<search_query>testing various things</search_query>
|
||||
</parameters>
|
||||
</invoke>
|
||||
</function_calls>
|
||||
TXT
|
||||
|
||||
response2 = "I found stuff"
|
||||
|
||||
DiscourseAi::Completions::Llm.with_prepared_responses([response1, response2]) do
|
||||
playground.reply_to(third_post)
|
||||
end
|
||||
|
||||
last_post = third_post.topic.reload.posts.order(:post_number).last
|
||||
|
||||
expect(last_post.raw).to eq("I found stuff")
|
||||
end
|
||||
|
||||
it "does not include placeholders in conversation context but includes all completions" do
|
||||
response1 = (<<~TXT).strip
|
||||
<function_calls>
|
||||
|
|
|
@ -7,7 +7,7 @@ RSpec.describe AiPersona do
|
|||
name: "test",
|
||||
description: "test",
|
||||
system_prompt: "test",
|
||||
commands: [],
|
||||
tools: [],
|
||||
allowed_group_ids: [],
|
||||
)
|
||||
|
||||
|
@ -30,7 +30,7 @@ RSpec.describe AiPersona do
|
|||
name: "test",
|
||||
description: "test",
|
||||
system_prompt: "test",
|
||||
commands: [],
|
||||
tools: [],
|
||||
allowed_group_ids: [],
|
||||
)
|
||||
|
||||
|
@ -47,7 +47,7 @@ RSpec.describe AiPersona do
|
|||
name: "test",
|
||||
description: "test",
|
||||
system_prompt: "test",
|
||||
commands: [],
|
||||
tools: [],
|
||||
allowed_group_ids: [],
|
||||
rag_chunk_tokens: 10,
|
||||
rag_chunk_overlap_tokens: 5,
|
||||
|
@ -94,7 +94,7 @@ RSpec.describe AiPersona do
|
|||
name: "test",
|
||||
description: "test",
|
||||
system_prompt: "test",
|
||||
commands: [],
|
||||
tools: [],
|
||||
allowed_group_ids: [],
|
||||
default_llm: "anthropic:claude-2",
|
||||
max_context_posts: 3,
|
||||
|
@ -135,7 +135,7 @@ RSpec.describe AiPersona do
|
|||
name: "pun_bot",
|
||||
description: "you write puns",
|
||||
system_prompt: "you are pun bot",
|
||||
commands: ["ImageCommand"],
|
||||
tools: ["ImageCommand"],
|
||||
allowed_group_ids: [Group::AUTO_GROUPS[:trust_level_0]],
|
||||
)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ RSpec.describe DiscourseAi::Admin::AiPersonasController do
|
|||
expect(response).to be_successful
|
||||
|
||||
expect(response.parsed_body["ai_personas"].length).to eq(AiPersona.count)
|
||||
expect(response.parsed_body["meta"]["commands"].length).to eq(
|
||||
expect(response.parsed_body["meta"]["tools"].length).to eq(
|
||||
DiscourseAi::AiBot::Personas::Persona.all_available_tools.length,
|
||||
)
|
||||
end
|
||||
|
@ -33,13 +33,13 @@ RSpec.describe DiscourseAi::Admin::AiPersonasController do
|
|||
)
|
||||
end
|
||||
|
||||
it "returns commands options with each command" do
|
||||
persona1 = Fabricate(:ai_persona, name: "search1", commands: ["SearchCommand"])
|
||||
it "returns tool options with each tool" do
|
||||
persona1 = Fabricate(:ai_persona, name: "search1", tools: ["SearchCommand"])
|
||||
persona2 =
|
||||
Fabricate(
|
||||
:ai_persona,
|
||||
name: "search2",
|
||||
commands: [["SearchCommand", { base_query: "test" }]],
|
||||
tools: [["SearchCommand", { base_query: "test" }]],
|
||||
mentionable: true,
|
||||
default_llm: "anthropic:claude-2",
|
||||
)
|
||||
|
@ -56,36 +56,36 @@ RSpec.describe DiscourseAi::Admin::AiPersonasController do
|
|||
expect(serializer_persona2["user_id"]).to eq(persona2.user_id)
|
||||
expect(serializer_persona2["user"]["id"]).to eq(persona2.user_id)
|
||||
|
||||
commands = response.parsed_body["meta"]["commands"]
|
||||
search_command = commands.find { |c| c["id"] == "Search" }
|
||||
tools = response.parsed_body["meta"]["tools"]
|
||||
search_tool = tools.find { |c| c["id"] == "Search" }
|
||||
|
||||
expect(search_command["help"]).to eq(I18n.t("discourse_ai.ai_bot.command_help.search"))
|
||||
expect(search_tool["help"]).to eq(I18n.t("discourse_ai.ai_bot.tool_help.search"))
|
||||
|
||||
expect(search_command["options"]).to eq(
|
||||
expect(search_tool["options"]).to eq(
|
||||
{
|
||||
"base_query" => {
|
||||
"type" => "string",
|
||||
"name" => I18n.t("discourse_ai.ai_bot.command_options.search.base_query.name"),
|
||||
"name" => I18n.t("discourse_ai.ai_bot.tool_options.search.base_query.name"),
|
||||
"description" =>
|
||||
I18n.t("discourse_ai.ai_bot.command_options.search.base_query.description"),
|
||||
I18n.t("discourse_ai.ai_bot.tool_options.search.base_query.description"),
|
||||
},
|
||||
"max_results" => {
|
||||
"type" => "integer",
|
||||
"name" => I18n.t("discourse_ai.ai_bot.command_options.search.max_results.name"),
|
||||
"name" => I18n.t("discourse_ai.ai_bot.tool_options.search.max_results.name"),
|
||||
"description" =>
|
||||
I18n.t("discourse_ai.ai_bot.command_options.search.max_results.description"),
|
||||
I18n.t("discourse_ai.ai_bot.tool_options.search.max_results.description"),
|
||||
},
|
||||
"search_private" => {
|
||||
"type" => "boolean",
|
||||
"name" => I18n.t("discourse_ai.ai_bot.command_options.search.search_private.name"),
|
||||
"name" => I18n.t("discourse_ai.ai_bot.tool_options.search.search_private.name"),
|
||||
"description" =>
|
||||
I18n.t("discourse_ai.ai_bot.command_options.search.search_private.description"),
|
||||
I18n.t("discourse_ai.ai_bot.tool_options.search.search_private.description"),
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
expect(serializer_persona1["commands"]).to eq(["SearchCommand"])
|
||||
expect(serializer_persona2["commands"]).to eq([["SearchCommand", { "base_query" => "test" }]])
|
||||
expect(serializer_persona1["tools"]).to eq(["SearchCommand"])
|
||||
expect(serializer_persona2["tools"]).to eq([["SearchCommand", { "base_query" => "test" }]])
|
||||
end
|
||||
|
||||
context "with translations" do
|
||||
|
@ -160,7 +160,7 @@ RSpec.describe DiscourseAi::Admin::AiPersonasController do
|
|||
name: "superbot",
|
||||
description: "Assists with tasks",
|
||||
system_prompt: "you are a helpful bot",
|
||||
commands: [["search", { "base_query" => "test" }]],
|
||||
tools: [["search", { "base_query" => "test" }]],
|
||||
top_p: 0.1,
|
||||
temperature: 0.5,
|
||||
mentionable: true,
|
||||
|
@ -186,7 +186,7 @@ RSpec.describe DiscourseAi::Admin::AiPersonasController do
|
|||
|
||||
persona = AiPersona.find(persona_json["id"])
|
||||
|
||||
expect(persona.commands).to eq([["search", { "base_query" => "test" }]])
|
||||
expect(persona.tools).to eq([["search", { "base_query" => "test" }]])
|
||||
expect(persona.top_p).to eq(0.1)
|
||||
expect(persona.temperature).to eq(0.5)
|
||||
}.to change(AiPersona, :count).by(1)
|
||||
|
@ -286,7 +286,7 @@ RSpec.describe DiscourseAi::Admin::AiPersonasController do
|
|||
ai_persona: {
|
||||
name: "SuperBot",
|
||||
enabled: false,
|
||||
commands: ["search"],
|
||||
tools: ["search"],
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,7 @@ RSpec.describe DiscourseAi::Admin::AiPersonasController do
|
|||
ai_persona.reload
|
||||
expect(ai_persona.name).to eq("SuperBot")
|
||||
expect(ai_persona.enabled).to eq(false)
|
||||
expect(ai_persona.commands).to eq(["search"])
|
||||
expect(ai_persona.tools).to eq(["search"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -314,11 +314,11 @@ RSpec.describe DiscourseAi::Admin::AiPersonasController do
|
|||
expect(response.parsed_body["errors"].join).not_to include("en.discourse")
|
||||
end
|
||||
|
||||
it "does not allow editing of commands" do
|
||||
it "does not allow editing of tools" do
|
||||
put "/admin/plugins/discourse-ai/ai-personas/#{DiscourseAi::AiBot::Personas::Persona.system_personas.values.first}.json",
|
||||
params: {
|
||||
ai_persona: {
|
||||
commands: %w[SearchCommand ImageCommand],
|
||||
tools: %w[SearchCommand ImageCommand],
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -38,9 +38,9 @@ RSpec.describe "AI personas", type: :system, js: true do
|
|||
find(".ai-persona-editor__description").fill_in(with: "I am a test persona")
|
||||
find(".ai-persona-editor__system_prompt").fill_in(with: "You are a helpful bot")
|
||||
|
||||
command_selector = PageObjects::Components::SelectKit.new(".ai-persona-editor__commands")
|
||||
command_selector.expand
|
||||
command_selector.select_row_by_value("Read")
|
||||
tool_selector = PageObjects::Components::SelectKit.new(".ai-persona-editor__tools")
|
||||
tool_selector.expand
|
||||
tool_selector.select_row_by_value("Read")
|
||||
|
||||
find(".ai-persona-editor__save").click()
|
||||
|
||||
|
@ -52,7 +52,7 @@ RSpec.describe "AI personas", type: :system, js: true do
|
|||
expect(persona.name).to eq("Test Persona")
|
||||
expect(persona.description).to eq("I am a test persona")
|
||||
expect(persona.system_prompt).to eq("You are a helpful bot")
|
||||
expect(persona.commands).to eq(["Read"])
|
||||
expect(persona.tools).to eq(["Read"])
|
||||
end
|
||||
|
||||
it "will not allow deletion or editing of system personas" do
|
||||
|
|
|
@ -4,26 +4,22 @@ import AiPersona from "discourse/plugins/discourse-ai/discourse/admin/models/ai-
|
|||
module("Discourse AI | Unit | Model | ai-persona", function () {
|
||||
test("init properties", function (assert) {
|
||||
const properties = {
|
||||
commands: [
|
||||
["CommandName", { option1: "value1", option2: "value2" }],
|
||||
"CommandName2",
|
||||
"CommandName3",
|
||||
tools: [
|
||||
["ToolName", { option1: "value1", option2: "value2" }],
|
||||
"ToolName2",
|
||||
"ToolName3",
|
||||
],
|
||||
};
|
||||
|
||||
const aiPersona = AiPersona.create(properties);
|
||||
|
||||
assert.deepEqual(aiPersona.commands, [
|
||||
"CommandName",
|
||||
"CommandName2",
|
||||
"CommandName3",
|
||||
]);
|
||||
assert.deepEqual(aiPersona.tools, ["ToolName", "ToolName2", "ToolName3"]);
|
||||
assert.equal(
|
||||
aiPersona.getCommandOption("CommandName", "option1").value,
|
||||
aiPersona.getToolOption("ToolName", "option1").value,
|
||||
"value1"
|
||||
);
|
||||
assert.equal(
|
||||
aiPersona.getCommandOption("CommandName", "option2").value,
|
||||
aiPersona.getToolOption("ToolName", "option2").value,
|
||||
"value2"
|
||||
);
|
||||
});
|
||||
|
@ -32,7 +28,7 @@ module("Discourse AI | Unit | Model | ai-persona", function () {
|
|||
const properties = {
|
||||
id: 1,
|
||||
name: "Test",
|
||||
commands: ["CommandName"],
|
||||
tools: ["ToolName"],
|
||||
allowed_group_ids: [12],
|
||||
system: false,
|
||||
enabled: true,
|
||||
|
@ -54,16 +50,17 @@ module("Discourse AI | Unit | Model | ai-persona", function () {
|
|||
rag_conversation_chunks: 10,
|
||||
question_consolidator_llm: "Question Consolidator LLM",
|
||||
allow_chat: false,
|
||||
tool_details: true,
|
||||
};
|
||||
|
||||
const aiPersona = AiPersona.create({ ...properties });
|
||||
|
||||
aiPersona.getCommandOption("CommandName", "option1").value = "value1";
|
||||
aiPersona.getToolOption("ToolName", "option1").value = "value1";
|
||||
|
||||
const updatedProperties = aiPersona.updateProperties();
|
||||
|
||||
// perform remapping for save
|
||||
properties.commands = [["CommandName", { option1: "value1" }]];
|
||||
properties.tools = [["ToolName", { option1: "value1" }]];
|
||||
|
||||
assert.deepEqual(updatedProperties, properties);
|
||||
});
|
||||
|
@ -72,7 +69,7 @@ module("Discourse AI | Unit | Model | ai-persona", function () {
|
|||
const properties = {
|
||||
id: 1,
|
||||
name: "Test",
|
||||
commands: ["CommandName"],
|
||||
tools: ["ToolName"],
|
||||
allowed_group_ids: [12],
|
||||
system: false,
|
||||
enabled: true,
|
||||
|
@ -94,15 +91,16 @@ module("Discourse AI | Unit | Model | ai-persona", function () {
|
|||
rag_conversation_chunks: 10,
|
||||
question_consolidator_llm: "Question Consolidator LLM",
|
||||
allow_chat: false,
|
||||
tool_details: true,
|
||||
};
|
||||
|
||||
const aiPersona = AiPersona.create({ ...properties });
|
||||
|
||||
aiPersona.getCommandOption("CommandName", "option1").value = "value1";
|
||||
aiPersona.getToolOption("ToolName", "option1").value = "value1";
|
||||
|
||||
const createdProperties = aiPersona.createProperties();
|
||||
|
||||
properties.commands = [["CommandName", { option1: "value1" }]];
|
||||
properties.tools = [["ToolName", { option1: "value1" }]];
|
||||
|
||||
assert.deepEqual(createdProperties, properties);
|
||||
});
|
||||
|
@ -110,18 +108,18 @@ module("Discourse AI | Unit | Model | ai-persona", function () {
|
|||
test("working copy", function (assert) {
|
||||
const aiPersona = AiPersona.create({
|
||||
name: "Test",
|
||||
commands: ["CommandName"],
|
||||
tools: ["ToolName"],
|
||||
});
|
||||
|
||||
aiPersona.getCommandOption("CommandName", "option1").value = "value1";
|
||||
aiPersona.getToolOption("ToolName", "option1").value = "value1";
|
||||
|
||||
const workingCopy = aiPersona.workingCopy();
|
||||
|
||||
assert.equal(workingCopy.name, "Test");
|
||||
assert.equal(
|
||||
workingCopy.getCommandOption("CommandName", "option1").value,
|
||||
workingCopy.getToolOption("ToolName", "option1").value,
|
||||
"value1"
|
||||
);
|
||||
assert.deepEqual(workingCopy.commands, ["CommandName"]);
|
||||
assert.deepEqual(workingCopy.tools, ["ToolName"]);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue