Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ba091aa8b |
@@ -1,5 +1,3 @@
|
||||
< 3.5.0.beta7-dev: cd14b0c0bee0cf63c59b64b6f7213e31a37f11a7
|
||||
< 3.5.0.beta6-dev: 3e74eea1e5e3143888d67a8d8a11206df214dc24
|
||||
< 3.5.0.beta3-dev: 09a68414804a1447f52e5d60691ba59742cda9ec
|
||||
< 3.5.0.beta2-dev: de8624416a15b3d8e7ad350b083cc1420451ccec
|
||||
< 3.5.0.beta1-dev: bdef136080074a993e7c4f5ca562edc31a8ba756
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class AdminPluginsShowDiscourseAiAgentsEdit extends DiscourseRoute {
|
||||
async model(params) {
|
||||
const allAgents = this.modelFor(
|
||||
"adminPlugins.show.discourse-ai-agents"
|
||||
);
|
||||
const id = parseInt(params.id, 10);
|
||||
return allAgents.findBy("id", id);
|
||||
}
|
||||
|
||||
setupController(controller, model) {
|
||||
super.setupController(controller, model);
|
||||
controller.set(
|
||||
"allAgents",
|
||||
this.modelFor("adminPlugins.show.discourse-ai-agents")
|
||||
);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -1,16 +1,16 @@
|
||||
import { AUTO_GROUPS } from "discourse/lib/constants";
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class AdminPluginsShowDiscourseAiPersonasNew extends DiscourseRoute {
|
||||
export default class AdminPluginsShowDiscourseAiAgentsNew extends DiscourseRoute {
|
||||
async model() {
|
||||
const record = this.store.createRecord("ai-persona");
|
||||
const record = this.store.createRecord("ai-agent");
|
||||
record.set("allowed_group_ids", [AUTO_GROUPS.trust_level_0.id]);
|
||||
record.set("rag_uploads", []);
|
||||
// these match the defaults on the table
|
||||
record.set("rag_chunk_tokens", 374);
|
||||
record.set("rag_chunk_overlap_tokens", 10);
|
||||
record.set("rag_conversation_chunks", 10);
|
||||
record.set("allow_personal_messages", true);
|
||||
record.set("allow_agentl_messages", true);
|
||||
record.set("tool_details", false);
|
||||
return record;
|
||||
}
|
||||
@@ -18,8 +18,8 @@ export default class AdminPluginsShowDiscourseAiPersonasNew extends DiscourseRou
|
||||
setupController(controller, model) {
|
||||
super.setupController(controller, model);
|
||||
controller.set(
|
||||
"allPersonas",
|
||||
this.modelFor("adminPlugins.show.discourse-ai-personas")
|
||||
"allAgents",
|
||||
this.modelFor("adminPlugins.show.discourse-ai-agents")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class DiscourseAiAiAgentsRoute extends DiscourseRoute {
|
||||
model() {
|
||||
return this.store.findAll("ai-agent");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@ export default class AdminPluginsShowDiscourseAiFeaturesEdit extends DiscourseRo
|
||||
|
||||
const { site_settings } = await ajax("/admin/config/site_settings.json", {
|
||||
data: {
|
||||
filter_area: `ai-features/${currentFeature.module_name}`,
|
||||
filter_area: `ai-features/${currentFeature.ref}`,
|
||||
plugin: "discourse-ai",
|
||||
category: "discourse_ai",
|
||||
},
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class AdminPluginsShowDiscourseAiPersonasEdit extends DiscourseRoute {
|
||||
async model(params) {
|
||||
const allPersonas = this.modelFor(
|
||||
"adminPlugins.show.discourse-ai-personas"
|
||||
);
|
||||
const id = parseInt(params.id, 10);
|
||||
return allPersonas.findBy("id", id);
|
||||
}
|
||||
|
||||
setupController(controller, model) {
|
||||
super.setupController(controller, model);
|
||||
controller.set(
|
||||
"allPersonas",
|
||||
this.modelFor("adminPlugins.show.discourse-ai-personas")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
|
||||
export default class DiscourseAiAiPersonasRoute extends DiscourseRoute {
|
||||
model() {
|
||||
return this.store.findAll("ai-persona");
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
<AiAgentListEditor
|
||||
@agents={{this.allAgents}}
|
||||
@currentAgent={{this.model}}
|
||||
/>
|
||||
+1
@@ -0,0 +1 @@
|
||||
<AiAgentListEditor @agents={{this.model}} />
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
<AiAgentListEditor
|
||||
@agents={{this.allAgents}}
|
||||
@currentAgent={{this.model}}
|
||||
/>
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { service } from "@ember/service";
|
||||
import RouteTemplate from "ember-route-template";
|
||||
import { gt } from "truth-helpers";
|
||||
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DPageSubheader from "discourse/components/d-page-subheader";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default RouteTemplate(
|
||||
class extends Component {
|
||||
@service adminPluginNavManager;
|
||||
|
||||
get tableHeaders() {
|
||||
const prefix = "discourse_ai.features.list.header";
|
||||
return [
|
||||
i18n(`${prefix}.name`),
|
||||
i18n(`${prefix}.agent`),
|
||||
i18n(`${prefix}.groups`),
|
||||
"",
|
||||
];
|
||||
}
|
||||
|
||||
get configuredFeatures() {
|
||||
return this.args.model.filter(
|
||||
(feature) => feature.enable_setting.value === true
|
||||
);
|
||||
}
|
||||
|
||||
get unconfiguredFeatures() {
|
||||
return this.args.model.filter(
|
||||
(feature) => feature.enable_setting.value === false
|
||||
);
|
||||
}
|
||||
|
||||
<template>
|
||||
<DBreadcrumbsItem
|
||||
@path="/admin/plugins/{{this.adminPluginNavManager.currentPlugin.name}}/ai-features"
|
||||
@label={{i18n "discourse_ai.features.short_title"}}
|
||||
/>
|
||||
<section class="ai-feature-list admin-detail">
|
||||
<DPageSubheader
|
||||
@titleLabel={{i18n "discourse_ai.features.short_title"}}
|
||||
@descriptionLabel={{i18n "discourse_ai.features.description"}}
|
||||
@learnMoreUrl="todo"
|
||||
/>
|
||||
|
||||
{{#if (gt this.configuredFeatures.length 0)}}
|
||||
<div class="ai-feature-list__configured-features">
|
||||
<h3>{{i18n "discourse_ai.features.list.configured_features"}}</h3>
|
||||
|
||||
<table class="d-admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
{{#each this.tableHeaders as |header|}}
|
||||
<th>{{header}}</th>
|
||||
{{/each}}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each this.configuredFeatures as |feature|}}
|
||||
<tr
|
||||
class="ai-feature-list__row d-admin-row__content"
|
||||
data-feature-name={{feature.name}}
|
||||
>
|
||||
<td class="d-admin-row__overview ai-feature-list__row-item">
|
||||
<span class="ai-feature-list__row-item-name">
|
||||
<strong>
|
||||
{{feature.name}}
|
||||
</strong>
|
||||
</span>
|
||||
<span class="ai-feature-list__row-item-description">
|
||||
{{feature.description}}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
class="d-admin-row__detail ai-feature-list__row-item ai-feature-list__agent"
|
||||
>
|
||||
<DButton
|
||||
class="btn-flat btn-small ai-feature-list__row-item-agent"
|
||||
@translatedLabel={{feature.agent.name}}
|
||||
@route="adminPlugins.show.discourse-ai-agents.edit"
|
||||
@routeModels={{feature.agent.id}}
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
class="d-admin-row__detail ai-feature-list__row-item ai-feature-list__groups"
|
||||
>
|
||||
{{#if (gt feature.agent.allowed_groups.length 0)}}
|
||||
<ul class="ai-feature-list__row-item-groups">
|
||||
{{#each feature.agent.allowed_groups as |group|}}
|
||||
<li>{{group.name}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td class="d-admin-row_controls">
|
||||
<DButton
|
||||
class="btn-small edit"
|
||||
@label="discourse_ai.features.list.edit"
|
||||
@route="adminPlugins.show.discourse-ai-features.edit"
|
||||
@routeModels={{feature.id}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if (gt this.unconfiguredFeatures.length 0)}}
|
||||
<div class="ai-feature-list__unconfigured-features">
|
||||
<h3>{{i18n "discourse_ai.features.list.unconfigured_features"}}</h3>
|
||||
|
||||
<table class="d-admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{i18n "discourse_ai.features.list.header.name"}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each this.unconfiguredFeatures as |feature|}}
|
||||
<tr class="ai-feature-list__row d-admin-row__content">
|
||||
<td class="d-admin-row__overview ai-feature-list__row-item">
|
||||
<span class="ai-feature-list__row-item-name">
|
||||
<strong>
|
||||
{{feature.name}}
|
||||
</strong>
|
||||
</span>
|
||||
<span class="ai-feature-list__row-item-description">
|
||||
{{feature.description}}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="d-admin-row_controls">
|
||||
<DButton
|
||||
class="btn-small"
|
||||
@label="discourse_ai.features.list.set_up"
|
||||
@route="adminPlugins.show.discourse-ai-features.edit"
|
||||
@routeModels={{feature.id}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
</template>
|
||||
}
|
||||
);
|
||||
-1
@@ -1 +0,0 @@
|
||||
<AiFeatures @features={{this.model}} />
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
<AiPersonaListEditor
|
||||
@personas={{this.allPersonas}}
|
||||
@currentPersona={{this.model}}
|
||||
/>
|
||||
-1
@@ -1 +0,0 @@
|
||||
<AiPersonaListEditor @personas={{this.model}} />
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
<AiPersonaListEditor
|
||||
@personas={{this.allPersonas}}
|
||||
@currentPersona={{this.model}}
|
||||
/>
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<section class="ai-persona-tool-editor__current admin-detail pull-left">
|
||||
<section class="ai-agent-tool-editor__current admin-detail pull-left">
|
||||
<AiToolEditor
|
||||
@tools={{this.allTools}}
|
||||
@model={{this.model}}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<section class="ai-persona-tool-editor__current admin-detail pull-left">
|
||||
<section class="ai-agent-tool-editor__current admin-detail pull-left">
|
||||
<AiToolEditor
|
||||
@tools={{this.allTools}}
|
||||
@model={{this.model}}
|
||||
|
||||
+41
-141
@@ -2,23 +2,22 @@
|
||||
|
||||
module DiscourseAi
|
||||
module Admin
|
||||
class AiPersonasController < ::Admin::AdminController
|
||||
class AiAgentsController < ::Admin::AdminController
|
||||
requires_plugin ::DiscourseAi::PLUGIN_NAME
|
||||
|
||||
before_action :find_ai_persona, only: %i[edit update destroy create_user]
|
||||
before_action :find_ai_agent, only: %i[edit update destroy create_user]
|
||||
|
||||
def index
|
||||
ai_personas =
|
||||
AiPersona
|
||||
.ordered
|
||||
.includes(:user, :uploads)
|
||||
.map { |persona| LocalizedAiPersonaSerializer.new(persona, root: false) }
|
||||
|
||||
ai_agents =
|
||||
AiAgent.ordered.map do |agent|
|
||||
# we use a special serializer here cause names and descriptions are
|
||||
# localized for system agents
|
||||
LocalizedAiAgentSerializer.new(agent, root: false)
|
||||
end
|
||||
tools =
|
||||
DiscourseAi::Personas::Persona.all_available_tools.map do |tool|
|
||||
DiscourseAi::Agents::Agent.all_available_tools.map do |tool|
|
||||
AiToolSerializer.new(tool, root: false)
|
||||
end
|
||||
|
||||
AiTool
|
||||
.where(enabled: true)
|
||||
.each do |tool|
|
||||
@@ -32,14 +31,12 @@ module DiscourseAi
|
||||
),
|
||||
}
|
||||
end
|
||||
|
||||
llms =
|
||||
DiscourseAi::Configuration::LlmEnumerator.values_for_serialization(
|
||||
allowed_seeded_llm_ids: SiteSetting.ai_bot_allowed_seeded_models_map,
|
||||
)
|
||||
|
||||
render json: {
|
||||
ai_personas: ai_personas,
|
||||
ai_agents: ai_agents,
|
||||
meta: {
|
||||
tools: tools,
|
||||
llms: llms,
|
||||
@@ -54,66 +51,55 @@ module DiscourseAi
|
||||
end
|
||||
|
||||
def edit
|
||||
render json: LocalizedAiPersonaSerializer.new(@ai_persona)
|
||||
render json: LocalizedAiAgentSerializer.new(@ai_agent)
|
||||
end
|
||||
|
||||
def create
|
||||
ai_persona = AiPersona.new(ai_persona_params.except(:rag_uploads))
|
||||
if ai_persona.save
|
||||
RagDocumentFragment.link_target_and_uploads(ai_persona, attached_upload_ids)
|
||||
log_ai_persona_creation(ai_persona)
|
||||
ai_agent = AiAgent.new(ai_agent_params.except(:rag_uploads))
|
||||
if ai_agent.save
|
||||
RagDocumentFragment.link_target_and_uploads(ai_agent, attached_upload_ids)
|
||||
|
||||
render json: {
|
||||
ai_persona: LocalizedAiPersonaSerializer.new(ai_persona, root: false),
|
||||
ai_agent: LocalizedAiAgentSerializer.new(ai_agent, root: false),
|
||||
},
|
||||
status: :created
|
||||
else
|
||||
render_json_error ai_persona
|
||||
render_json_error ai_agent
|
||||
end
|
||||
end
|
||||
|
||||
def create_user
|
||||
user = @ai_persona.create_user!
|
||||
user = @ai_agent.create_user!
|
||||
render json: BasicUserSerializer.new(user, root: "user")
|
||||
end
|
||||
|
||||
def update
|
||||
initial_attributes = @ai_persona.attributes.dup
|
||||
if @ai_agent.update(ai_agent_params.except(:rag_uploads))
|
||||
RagDocumentFragment.update_target_uploads(@ai_agent, attached_upload_ids)
|
||||
|
||||
if @ai_persona.update(ai_persona_params.except(:rag_uploads))
|
||||
RagDocumentFragment.update_target_uploads(@ai_persona, attached_upload_ids)
|
||||
log_ai_persona_update(@ai_persona, initial_attributes)
|
||||
|
||||
render json: LocalizedAiPersonaSerializer.new(@ai_persona, root: false)
|
||||
render json: LocalizedAiAgentSerializer.new(@ai_agent, root: false)
|
||||
else
|
||||
render_json_error @ai_persona
|
||||
render_json_error @ai_agent
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
persona_details = {
|
||||
persona_id: @ai_persona.id,
|
||||
name: @ai_persona.name,
|
||||
description: @ai_persona.description,
|
||||
}
|
||||
|
||||
if @ai_persona.destroy
|
||||
log_ai_persona_deletion(persona_details)
|
||||
if @ai_agent.destroy
|
||||
head :no_content
|
||||
else
|
||||
render_json_error @ai_persona
|
||||
render_json_error @ai_agent
|
||||
end
|
||||
end
|
||||
|
||||
def stream_reply
|
||||
persona =
|
||||
AiPersona.find_by(name: params[:persona_name]) ||
|
||||
AiPersona.find_by(id: params[:persona_id])
|
||||
return render_json_error(I18n.t("discourse_ai.errors.persona_not_found")) if persona.nil?
|
||||
agent =
|
||||
AiAgent.find_by(name: params[:agent_name]) ||
|
||||
AiAgent.find_by(id: params[:agent_id])
|
||||
return render_json_error(I18n.t("discourse_ai.errors.agent_not_found")) if agent.nil?
|
||||
|
||||
return render_json_error(I18n.t("discourse_ai.errors.persona_disabled")) if !persona.enabled
|
||||
return render_json_error(I18n.t("discourse_ai.errors.agent_disabled")) if !agent.enabled
|
||||
|
||||
if persona.default_llm.blank?
|
||||
if agent.default_llm.blank?
|
||||
return render_json_error(I18n.t("discourse_ai.errors.no_default_llm"))
|
||||
end
|
||||
|
||||
@@ -121,8 +107,8 @@ module DiscourseAi
|
||||
return render_json_error(I18n.t("discourse_ai.errors.no_query_specified"))
|
||||
end
|
||||
|
||||
if !persona.user_id
|
||||
return render_json_error(I18n.t("discourse_ai.errors.no_user_for_persona"))
|
||||
if !agent.user_id
|
||||
return render_json_error(I18n.t("discourse_ai.errors.no_user_for_agent"))
|
||||
end
|
||||
|
||||
if !params[:username] && !params[:user_unique_id]
|
||||
@@ -156,7 +142,7 @@ module DiscourseAi
|
||||
|
||||
DiscourseAi::AiBot::ResponseHttpStreamer.queue_streamed_reply(
|
||||
io: io,
|
||||
persona: persona,
|
||||
agent: agent,
|
||||
user: user,
|
||||
topic: topic,
|
||||
query: params[:query].to_s,
|
||||
@@ -192,17 +178,17 @@ module DiscourseAi
|
||||
end
|
||||
end
|
||||
|
||||
def find_ai_persona
|
||||
@ai_persona = AiPersona.find(params[:id])
|
||||
def find_ai_agent
|
||||
@ai_agent = AiAgent.find(params[:id])
|
||||
end
|
||||
|
||||
def attached_upload_ids
|
||||
ai_persona_params[:rag_uploads].to_a.map { |h| h[:id] }
|
||||
ai_agent_params[:rag_uploads].to_a.map { |h| h[:id] }
|
||||
end
|
||||
|
||||
def ai_persona_params
|
||||
def ai_agent_params
|
||||
permitted =
|
||||
params.require(:ai_persona).permit(
|
||||
params.require(:ai_agent).permit(
|
||||
:name,
|
||||
:description,
|
||||
:enabled,
|
||||
@@ -223,7 +209,7 @@ module DiscourseAi
|
||||
:allow_chat_channel_mentions,
|
||||
:allow_chat_direct_messages,
|
||||
:allow_topic_mentions,
|
||||
:allow_personal_messages,
|
||||
:allow_agentl_messages,
|
||||
:tool_details,
|
||||
:forced_tool_count,
|
||||
:force_default_llm,
|
||||
@@ -231,15 +217,15 @@ module DiscourseAi
|
||||
rag_uploads: [:id],
|
||||
)
|
||||
|
||||
if tools = params.dig(:ai_persona, :tools)
|
||||
if tools = params.dig(:ai_agent, :tools)
|
||||
permitted[:tools] = permit_tools(tools)
|
||||
end
|
||||
|
||||
if response_format = params.dig(:ai_persona, :response_format)
|
||||
if response_format = params.dig(:ai_agent, :response_format)
|
||||
permitted[:response_format] = permit_response_format(response_format)
|
||||
end
|
||||
|
||||
if examples = params.dig(:ai_persona, :examples)
|
||||
if examples = params.dig(:ai_agent, :examples)
|
||||
permitted[:examples] = permit_examples(examples)
|
||||
end
|
||||
|
||||
@@ -275,92 +261,6 @@ module DiscourseAi
|
||||
|
||||
examples.map { |example_arr| example_arr.take(2).map(&:to_s) }
|
||||
end
|
||||
|
||||
def ai_persona_logger_fields
|
||||
{
|
||||
name: {
|
||||
},
|
||||
description: {
|
||||
},
|
||||
enabled: {
|
||||
},
|
||||
priority: {
|
||||
},
|
||||
system_prompt: {
|
||||
type: :large_text,
|
||||
},
|
||||
default_llm_id: {
|
||||
},
|
||||
temperature: {
|
||||
},
|
||||
top_p: {
|
||||
},
|
||||
user_id: {
|
||||
},
|
||||
max_context_posts: {
|
||||
},
|
||||
vision_enabled: {
|
||||
},
|
||||
vision_max_pixels: {
|
||||
},
|
||||
rag_chunk_tokens: {
|
||||
},
|
||||
rag_chunk_overlap_tokens: {
|
||||
},
|
||||
rag_conversation_chunks: {
|
||||
},
|
||||
rag_llm_model_id: {
|
||||
},
|
||||
question_consolidator_llm_id: {
|
||||
},
|
||||
allow_chat_channel_mentions: {
|
||||
},
|
||||
allow_chat_direct_messages: {
|
||||
},
|
||||
allow_topic_mentions: {
|
||||
},
|
||||
allow_personal_messages: {
|
||||
},
|
||||
tool_details: {
|
||||
type: :large_text,
|
||||
},
|
||||
forced_tool_count: {
|
||||
},
|
||||
force_default_llm: {
|
||||
},
|
||||
# JSON fields
|
||||
json_fields: %i[tools response_format examples allowed_group_ids],
|
||||
}
|
||||
end
|
||||
|
||||
def log_ai_persona_creation(ai_persona)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
entity_details = { persona_id: ai_persona.id, subject: ai_persona.name }
|
||||
entity_details[:tools_count] = (ai_persona.tools || []).size
|
||||
|
||||
logger.log_creation("persona", ai_persona, ai_persona_logger_fields, entity_details)
|
||||
end
|
||||
|
||||
def log_ai_persona_update(ai_persona, initial_attributes)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
entity_details = { persona_id: ai_persona.id, subject: ai_persona.name }
|
||||
entity_details[:tools_count] = ai_persona.tools.size if ai_persona.tools.present?
|
||||
|
||||
logger.log_update(
|
||||
"persona",
|
||||
ai_persona,
|
||||
initial_attributes,
|
||||
ai_persona_logger_fields,
|
||||
entity_details,
|
||||
)
|
||||
end
|
||||
|
||||
def log_ai_persona_deletion(persona_details)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
persona_details[:subject] = persona_details[:name]
|
||||
|
||||
logger.log_deletion("persona", persona_details)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -40,7 +40,6 @@ module DiscourseAi
|
||||
embedding_def = EmbeddingDefinition.new(ai_embeddings_params)
|
||||
|
||||
if embedding_def.save
|
||||
log_ai_embedding_creation(embedding_def)
|
||||
render json: AiEmbeddingDefinitionSerializer.new(embedding_def), status: :created
|
||||
else
|
||||
render_json_error embedding_def
|
||||
@@ -56,10 +55,7 @@ module DiscourseAi
|
||||
)
|
||||
end
|
||||
|
||||
initial_attributes = embedding_def.attributes.dup
|
||||
|
||||
if embedding_def.update(ai_embeddings_params.except(:dimensions))
|
||||
log_ai_embedding_update(embedding_def, initial_attributes)
|
||||
render json: AiEmbeddingDefinitionSerializer.new(embedding_def)
|
||||
else
|
||||
render_json_error embedding_def
|
||||
@@ -79,16 +75,7 @@ module DiscourseAi
|
||||
return render_json_error(I18n.t("discourse_ai.embeddings.delete_failed"), status: 409)
|
||||
end
|
||||
|
||||
embedding_details = {
|
||||
embedding_id: embedding_def.id,
|
||||
display_name: embedding_def.display_name,
|
||||
provider: embedding_def.provider,
|
||||
dimensions: embedding_def.dimensions,
|
||||
subject: embedding_def.display_name,
|
||||
}
|
||||
|
||||
if embedding_def.destroy
|
||||
log_ai_embedding_deletion(embedding_details)
|
||||
head :no_content
|
||||
else
|
||||
render_json_error embedding_def
|
||||
@@ -141,60 +128,6 @@ module DiscourseAi
|
||||
|
||||
permitted
|
||||
end
|
||||
|
||||
def ai_embeddings_logger_fields
|
||||
{
|
||||
display_name: {
|
||||
},
|
||||
provider: {
|
||||
},
|
||||
dimensions: {
|
||||
},
|
||||
url: {
|
||||
},
|
||||
tokenizer_class: {
|
||||
},
|
||||
max_sequence_length: {
|
||||
},
|
||||
embed_prompt: {
|
||||
type: :large_text,
|
||||
},
|
||||
search_prompt: {
|
||||
type: :large_text,
|
||||
},
|
||||
matryoshka_dimensions: {
|
||||
},
|
||||
api_key: {
|
||||
type: :sensitive,
|
||||
},
|
||||
# JSON fields should be tracked as simple changes
|
||||
json_fields: [:provider_params],
|
||||
}
|
||||
end
|
||||
|
||||
def log_ai_embedding_creation(embedding_def)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
entity_details = { embedding_id: embedding_def.id, subject: embedding_def.display_name }
|
||||
logger.log_creation("embedding", embedding_def, ai_embeddings_logger_fields, entity_details)
|
||||
end
|
||||
|
||||
def log_ai_embedding_update(embedding_def, initial_attributes)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
entity_details = { embedding_id: embedding_def.id, subject: embedding_def.display_name }
|
||||
|
||||
logger.log_update(
|
||||
"embedding",
|
||||
embedding_def,
|
||||
initial_attributes,
|
||||
ai_embeddings_logger_fields,
|
||||
entity_details,
|
||||
)
|
||||
end
|
||||
|
||||
def log_ai_embedding_deletion(embedding_details)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
logger.log_deletion("embedding", embedding_details)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,58 +6,30 @@ module DiscourseAi
|
||||
requires_plugin ::DiscourseAi::PLUGIN_NAME
|
||||
|
||||
def index
|
||||
render json: serialize_modules(DiscourseAi::Configuration::Module.all)
|
||||
render json: serialize_features(DiscourseAi::Features.features)
|
||||
end
|
||||
|
||||
def edit
|
||||
raise Discourse::InvalidParameters.new(:id) if params[:id].blank?
|
||||
|
||||
a_module = DiscourseAi::Configuration::Module.find_by(id: params[:id].to_i)
|
||||
|
||||
render json: serialize_module(a_module)
|
||||
render json: serialize_feature(DiscourseAi::Features.find_feature_by_id(params[:id].to_i))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def serialize_modules(modules)
|
||||
modules.map { |a_module| serialize_module(a_module) }
|
||||
end
|
||||
|
||||
def serialize_module(a_module)
|
||||
return nil if a_module.blank?
|
||||
|
||||
{
|
||||
id: a_module.id,
|
||||
module_name: a_module.name,
|
||||
module_enabled: a_module.enabled?,
|
||||
features: a_module.features.map { |f| serialize_feature(f) },
|
||||
}
|
||||
def serialize_features(features)
|
||||
features.map { |feature| feature.merge(agent: serialize_agent(feature[:agent])) }
|
||||
end
|
||||
|
||||
def serialize_feature(feature)
|
||||
{
|
||||
name: feature.name,
|
||||
persona: serialize_persona(persona_id_obj_hash[feature.persona_id]),
|
||||
enabled: feature.enabled?,
|
||||
}
|
||||
return nil if feature.blank?
|
||||
|
||||
feature.merge(agent: serialize_agent(feature[:agent]))
|
||||
end
|
||||
|
||||
def serialize_persona(persona)
|
||||
return nil if persona.blank?
|
||||
def serialize_agent(agent)
|
||||
return nil if agent.blank?
|
||||
|
||||
serialize_data(persona, AiFeaturesPersonaSerializer, root: false)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def persona_id_obj_hash
|
||||
@persona_id_obj_hash ||=
|
||||
begin
|
||||
setting_names = DiscourseAi::Configuration::Feature.all_persona_setting_names
|
||||
ids = setting_names.map { |sn| SiteSetting.public_send(sn) }
|
||||
|
||||
AiPersona.where(id: ids).index_by(&:id)
|
||||
end
|
||||
serialize_data(agent, AiFeaturesAgentSerializer, root: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -47,7 +47,6 @@ module DiscourseAi
|
||||
|
||||
if llm_model.save
|
||||
llm_model.toggle_companion_user
|
||||
log_llm_model_creation(llm_model)
|
||||
render json: LlmModelSerializer.new(llm_model), status: :created
|
||||
else
|
||||
render_json_error llm_model
|
||||
@@ -57,10 +56,6 @@ module DiscourseAi
|
||||
def update
|
||||
llm_model = LlmModel.find(params[:id])
|
||||
|
||||
# Capture initial state for logging
|
||||
initial_attributes = llm_model.attributes.dup
|
||||
initial_quotas = llm_model.llm_quotas.map(&:attributes)
|
||||
|
||||
if params[:ai_llm].key?(:llm_quotas)
|
||||
if quota_params
|
||||
existing_quota_group_ids = llm_model.llm_quotas.pluck(:group_id)
|
||||
@@ -86,7 +81,6 @@ module DiscourseAi
|
||||
|
||||
if llm_model.update(ai_llm_params(updating: llm_model))
|
||||
llm_model.toggle_companion_user
|
||||
log_llm_model_update(llm_model, initial_attributes, initial_quotas)
|
||||
render json: LlmModelSerializer.new(llm_model)
|
||||
else
|
||||
render_json_error llm_model
|
||||
@@ -115,20 +109,11 @@ module DiscourseAi
|
||||
)
|
||||
end
|
||||
|
||||
# Capture model details for logging before destruction
|
||||
model_details = {
|
||||
model_id: llm_model.id,
|
||||
display_name: llm_model.display_name,
|
||||
name: llm_model.name,
|
||||
provider: llm_model.provider,
|
||||
}
|
||||
|
||||
# Clean up companion users
|
||||
llm_model.enabled_chat_bot = false
|
||||
llm_model.toggle_companion_user
|
||||
|
||||
if llm_model.destroy
|
||||
log_llm_model_deletion(model_details)
|
||||
head :no_content
|
||||
else
|
||||
render_json_error llm_model
|
||||
@@ -205,89 +190,6 @@ module DiscourseAi
|
||||
|
||||
permitted
|
||||
end
|
||||
|
||||
def ai_llm_logger_fields
|
||||
{
|
||||
display_name: {
|
||||
},
|
||||
name: {
|
||||
},
|
||||
provider: {
|
||||
},
|
||||
tokenizer: {
|
||||
},
|
||||
url: {
|
||||
},
|
||||
max_prompt_tokens: {
|
||||
},
|
||||
max_output_tokens: {
|
||||
},
|
||||
enabled_chat_bot: {
|
||||
},
|
||||
vision_enabled: {
|
||||
},
|
||||
api_key: {
|
||||
type: :sensitive,
|
||||
},
|
||||
input_cost: {
|
||||
},
|
||||
output_cost: {
|
||||
},
|
||||
# JSON fields should be tracked as simple changes
|
||||
json_fields: [:provider_params],
|
||||
}
|
||||
end
|
||||
|
||||
def log_llm_model_creation(llm_model)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
entity_details = { model_id: llm_model.id, subject: llm_model.display_name }
|
||||
|
||||
# Add quota information as a special case
|
||||
if llm_model.llm_quotas.any?
|
||||
entity_details[:quotas] = llm_model
|
||||
.llm_quotas
|
||||
.map do |quota|
|
||||
"Group #{quota.group_id}: #{quota.max_tokens} tokens, #{quota.max_usages} usages, #{quota.duration_seconds}s"
|
||||
end
|
||||
.join("; ")
|
||||
end
|
||||
|
||||
logger.log_creation("llm_model", llm_model, ai_llm_logger_fields, entity_details)
|
||||
end
|
||||
|
||||
def log_llm_model_update(llm_model, initial_attributes, initial_quotas)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
entity_details = { model_id: llm_model.id, subject: llm_model.display_name }
|
||||
|
||||
# Track quota changes separately as they're a special case
|
||||
current_quotas = llm_model.llm_quotas.reload.map(&:attributes)
|
||||
if initial_quotas != current_quotas
|
||||
initial_quota_summary =
|
||||
initial_quotas
|
||||
.map { |q| "Group #{q["group_id"]}: #{q["max_tokens"]} tokens" }
|
||||
.join("; ")
|
||||
current_quota_summary =
|
||||
current_quotas
|
||||
.map { |q| "Group #{q["group_id"]}: #{q["max_tokens"]} tokens" }
|
||||
.join("; ")
|
||||
entity_details[:quotas_changed] = true
|
||||
entity_details[:quotas] = "#{initial_quota_summary} → #{current_quota_summary}"
|
||||
end
|
||||
|
||||
logger.log_update(
|
||||
"llm_model",
|
||||
llm_model,
|
||||
initial_attributes,
|
||||
ai_llm_logger_fields,
|
||||
entity_details,
|
||||
)
|
||||
end
|
||||
|
||||
def log_llm_model_deletion(model_details)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
model_details[:subject] = model_details[:display_name]
|
||||
logger.log_deletion("llm_model", model_details)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,10 +10,6 @@ module DiscourseAi
|
||||
end
|
||||
|
||||
def update
|
||||
initial_settings = AiModerationSetting.spam
|
||||
initial_custom_instructions = initial_settings&.data&.dig("custom_instructions")
|
||||
initial_llm_model_id = initial_settings&.llm_model_id
|
||||
|
||||
updated_params = {}
|
||||
if allowed_params.key?(:llm_model_id)
|
||||
llm_model_id = updated_params[:llm_model_id] = allowed_params[:llm_model_id]
|
||||
@@ -40,8 +36,6 @@ module DiscourseAi
|
||||
else
|
||||
AiModerationSetting.create!(updated_params.merge(setting_type: :spam))
|
||||
end
|
||||
|
||||
log_ai_spam_update(initial_llm_model_id, initial_custom_instructions, allowed_params)
|
||||
end
|
||||
|
||||
is_enabled = ActiveModel::Type::Boolean.new.cast(allowed_params[:is_enabled])
|
||||
@@ -119,30 +113,6 @@ module DiscourseAi
|
||||
|
||||
private
|
||||
|
||||
def log_ai_spam_update(initial_llm_model_id, initial_custom_instructions, params)
|
||||
changes_to_log = {}
|
||||
|
||||
if params.key?(:llm_model_id) && initial_llm_model_id.to_s != params[:llm_model_id].to_s
|
||||
old_model_name =
|
||||
LlmModel.find_by(id: initial_llm_model_id)&.display_name || initial_llm_model_id
|
||||
new_model_name =
|
||||
LlmModel.find_by(id: params[:llm_model_id])&.display_name || params[:llm_model_id]
|
||||
|
||||
changes_to_log[:llm_model_id] = "#{old_model_name} → #{new_model_name}"
|
||||
end
|
||||
|
||||
if params.key?(:custom_instructions) &&
|
||||
initial_custom_instructions != params[:custom_instructions]
|
||||
changes_to_log[:custom_instructions] = params[:custom_instructions]
|
||||
end
|
||||
|
||||
if changes_to_log.present?
|
||||
changes_to_log[:subject] = I18n.t("discourse_ai.spam_detection.logging_subject")
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
logger.log_custom("update_ai_spam_settings", changes_to_log)
|
||||
end
|
||||
end
|
||||
|
||||
def allowed_params
|
||||
params.permit(:is_enabled, :llm_model_id, :custom_instructions)
|
||||
end
|
||||
|
||||
@@ -25,7 +25,6 @@ module DiscourseAi
|
||||
|
||||
if ai_tool.save
|
||||
RagDocumentFragment.link_target_and_uploads(ai_tool, attached_upload_ids)
|
||||
log_ai_tool_creation(ai_tool)
|
||||
render_serialized(ai_tool, AiCustomToolSerializer, status: :created)
|
||||
else
|
||||
render_json_error ai_tool
|
||||
@@ -33,11 +32,8 @@ module DiscourseAi
|
||||
end
|
||||
|
||||
def update
|
||||
initial_attributes = @ai_tool.attributes.dup
|
||||
|
||||
if @ai_tool.update(ai_tool_params)
|
||||
RagDocumentFragment.update_target_uploads(@ai_tool, attached_upload_ids)
|
||||
log_ai_tool_update(@ai_tool, initial_attributes)
|
||||
render_serialized(@ai_tool, AiCustomToolSerializer)
|
||||
else
|
||||
render_json_error @ai_tool
|
||||
@@ -45,15 +41,7 @@ module DiscourseAi
|
||||
end
|
||||
|
||||
def destroy
|
||||
tool_logger_details = {
|
||||
tool_id: @ai_tool.id,
|
||||
name: @ai_tool.name,
|
||||
tool_name: @ai_tool.tool_name,
|
||||
subject: @ai_tool.name,
|
||||
}
|
||||
|
||||
if @ai_tool.destroy
|
||||
log_ai_tool_deletion(tool_logger_details)
|
||||
head :no_content
|
||||
else
|
||||
render_json_error @ai_tool
|
||||
@@ -108,60 +96,6 @@ module DiscourseAi
|
||||
)
|
||||
.except(:rag_uploads)
|
||||
end
|
||||
|
||||
def ai_tool_logger_fields
|
||||
{
|
||||
name: {
|
||||
},
|
||||
tool_name: {
|
||||
},
|
||||
description: {
|
||||
},
|
||||
summary: {
|
||||
},
|
||||
enabled: {
|
||||
},
|
||||
rag_chunk_tokens: {
|
||||
},
|
||||
rag_chunk_overlap_tokens: {
|
||||
},
|
||||
rag_llm_model_id: {
|
||||
},
|
||||
script: {
|
||||
type: :large_text,
|
||||
},
|
||||
parameters: {
|
||||
type: :large_text,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
def log_ai_tool_creation(ai_tool)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
|
||||
entity_details = { tool_id: ai_tool.id, subject: ai_tool.name }
|
||||
entity_details[:parameter_count] = ai_tool.parameters.size if ai_tool.parameters.present?
|
||||
|
||||
logger.log_creation("tool", ai_tool, ai_tool_logger_fields, entity_details)
|
||||
end
|
||||
|
||||
def log_ai_tool_update(ai_tool, initial_attributes)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
entity_details = { tool_id: ai_tool.id, subject: ai_tool.name }
|
||||
|
||||
logger.log_update(
|
||||
"tool",
|
||||
ai_tool,
|
||||
initial_attributes,
|
||||
ai_tool_logger_fields,
|
||||
entity_details,
|
||||
)
|
||||
end
|
||||
|
||||
def log_ai_tool_deletion(tool_details)
|
||||
logger = DiscourseAi::Utils::AiStaffActionLogger.new(current_user)
|
||||
logger.log_deletion("tool", tool_details)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,8 +6,8 @@ module DiscourseAi
|
||||
requires_plugin ::DiscourseAi::PLUGIN_NAME
|
||||
|
||||
def indexing_status_check
|
||||
if params[:target_type] == "AiPersona"
|
||||
@target = AiPersona.find(params[:target_id])
|
||||
if params[:target_type] == "AiAgent"
|
||||
@target = AiAgent.find(params[:target_id])
|
||||
elsif params[:target_type] == "AiTool"
|
||||
@target = AiTool.find(params[:target_id])
|
||||
else
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module DiscourseAi
|
||||
module AiBot
|
||||
class ArtifactKeyValuesController < ::ApplicationController
|
||||
requires_plugin DiscourseAi::PLUGIN_NAME
|
||||
before_action :ensure_logged_in, only: %i[set destroy]
|
||||
before_action :find_artifact
|
||||
|
||||
PER_PAGE_MAX = 100
|
||||
|
||||
def index
|
||||
page = index_params[:page].to_i
|
||||
page = 1 if page < 1
|
||||
per_page = index_params[:per_page].to_i
|
||||
per_page = PER_PAGE_MAX if per_page < 1 || per_page > PER_PAGE_MAX
|
||||
|
||||
query = build_index_query
|
||||
|
||||
total_count = query.count
|
||||
key_values =
|
||||
query
|
||||
.includes(:user)
|
||||
.order(:user_id, :key, :created_at)
|
||||
.offset((page - 1) * per_page)
|
||||
.limit(per_page + 1)
|
||||
|
||||
has_more = key_values.length > per_page
|
||||
key_values = key_values.first(per_page) if has_more
|
||||
|
||||
render json: {
|
||||
key_values:
|
||||
ActiveModel::ArraySerializer.new(
|
||||
key_values,
|
||||
each_serializer: AiArtifactKeyValueSerializer,
|
||||
keys_only: params[:keys_only] == "true",
|
||||
).as_json,
|
||||
has_more: has_more,
|
||||
total_count: total_count,
|
||||
users:
|
||||
key_values
|
||||
.map { |kv| kv.user }
|
||||
.uniq
|
||||
.map { |u| BasicUserSerializer.new(u, root: nil).as_json },
|
||||
}
|
||||
end
|
||||
|
||||
def destroy
|
||||
if params[:key].blank?
|
||||
render json: { error: "Key parameter is required" }, status: :bad_request
|
||||
return
|
||||
end
|
||||
|
||||
key_value = @artifact.key_values.find_by(user_id: current_user.id, key: params[:key])
|
||||
|
||||
if key_value.nil?
|
||||
render json: { error: "Key not found" }, status: :not_found
|
||||
elsif key_value.destroy
|
||||
head :ok
|
||||
else
|
||||
render json: { errors: key_value.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def set
|
||||
key_value =
|
||||
@artifact.key_values.find_or_initialize_by(
|
||||
user: current_user,
|
||||
key: key_value_params[:key],
|
||||
)
|
||||
|
||||
key_value.assign_attributes(key_value_params.except(:key))
|
||||
|
||||
if key_value.save
|
||||
render json: AiArtifactKeyValueSerializer.new(key_value).as_json
|
||||
else
|
||||
render json: { errors: key_value.errors.full_messages }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def key_value_params
|
||||
params.permit(:key, :value, :public)
|
||||
end
|
||||
|
||||
def index_params
|
||||
@index_params ||= params.permit(:page, :per_page, :key, :keys_only, :all_users)
|
||||
end
|
||||
|
||||
def build_index_query
|
||||
query = @artifact.key_values
|
||||
|
||||
query =
|
||||
if current_user&.admin?
|
||||
query
|
||||
elsif current_user
|
||||
query.where("user_id = ? OR public = true", current_user.id)
|
||||
else
|
||||
query.where(public: true)
|
||||
end
|
||||
|
||||
query = query.where("key = ?", index_params[:key]) if index_params[:key].present?
|
||||
|
||||
if index_params[:all_users].to_s != "true"
|
||||
if current_user
|
||||
query = query.where(user_id: current_user.id)
|
||||
else
|
||||
query = query.where("1 = 0")
|
||||
end
|
||||
end
|
||||
|
||||
query
|
||||
end
|
||||
|
||||
def find_artifact
|
||||
@artifact = AiArtifact.find_by(id: params[:artifact_id])
|
||||
raise Discourse::NotFound if !@artifact
|
||||
raise Discourse::NotFound if [email protected]? && guardian.anonymous?
|
||||
raise Discourse::NotFound if [email protected]? && !guardian.can_see?(@artifact.post)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,17 +46,17 @@ module DiscourseAi
|
||||
end
|
||||
|
||||
def discover
|
||||
ai_persona =
|
||||
AiPersona
|
||||
.all_personas(enabled_only: false)
|
||||
.find { |persona| persona.id == SiteSetting.ai_bot_discover_persona.to_i }
|
||||
ai_agent =
|
||||
AiAgent
|
||||
.all_agents(enabled_only: false)
|
||||
.find { |agent| agent.id == SiteSetting.ai_bot_discover_agent.to_i }
|
||||
|
||||
if ai_persona.nil? || !current_user.in_any_groups?(ai_persona.allowed_group_ids.to_a)
|
||||
if ai_agent.nil? || !current_user.in_any_groups?(ai_agent.allowed_group_ids.to_a)
|
||||
raise Discourse::InvalidAccess.new
|
||||
end
|
||||
|
||||
if ai_persona.default_llm_id.blank?
|
||||
render_json_error "Discover persona is missing a default LLM model.", status: 503
|
||||
if ai_agent.default_llm_id.blank?
|
||||
render_json_error "Discover agent is missing a default LLM model.", status: 503
|
||||
return
|
||||
end
|
||||
|
||||
@@ -77,7 +77,7 @@ module DiscourseAi
|
||||
|
||||
user = User.find(params[:user_id])
|
||||
|
||||
bot_user_id = AiPersona.find_by(id: SiteSetting.ai_bot_discover_persona).user_id
|
||||
bot_user_id = AiAgent.find_by(id: SiteSetting.ai_bot_discover_agent).user_id
|
||||
bot_username = User.find_by(id: bot_user_id).username
|
||||
|
||||
query = params[:query]
|
||||
|
||||
@@ -25,24 +25,25 @@ module DiscourseAi
|
||||
input = get_text_param!
|
||||
force_default_locale = params[:force_default_locale] || false
|
||||
|
||||
raise Discourse::InvalidParameters.new(:mode) if params[:mode].blank?
|
||||
prompt = CompletionPrompt.find_by(id: params[:mode])
|
||||
|
||||
if params[:mode] == DiscourseAi::AiHelper::Assistant::CUSTOM_PROMPT
|
||||
raise Discourse::InvalidParameters.new(:mode) if !prompt || !prompt.enabled?
|
||||
|
||||
if prompt.id == CompletionPrompt::CUSTOM_PROMPT
|
||||
raise Discourse::InvalidParameters.new(:custom_prompt) if params[:custom_prompt].blank?
|
||||
|
||||
prompt.custom_instruction = params[:custom_prompt]
|
||||
end
|
||||
|
||||
if params[:mode] == DiscourseAi::AiHelper::Assistant::ILLUSTRATE_POST
|
||||
return suggest_thumbnails(input)
|
||||
end
|
||||
return suggest_thumbnails(input) if prompt.id == CompletionPrompt::ILLUSTRATE_POST
|
||||
|
||||
hijack do
|
||||
render json:
|
||||
DiscourseAi::AiHelper::Assistant.new.generate_and_send_prompt(
|
||||
params[:mode],
|
||||
prompt,
|
||||
input,
|
||||
current_user,
|
||||
force_default_locale: force_default_locale,
|
||||
custom_prompt: params[:custom_prompt],
|
||||
),
|
||||
status: 200
|
||||
end
|
||||
@@ -59,10 +60,13 @@ module DiscourseAi
|
||||
input = get_text_param!
|
||||
end
|
||||
|
||||
prompt = CompletionPrompt.enabled_by_name("generate_titles")
|
||||
raise Discourse::InvalidParameters.new(:mode) if !prompt
|
||||
|
||||
hijack do
|
||||
render json:
|
||||
DiscourseAi::AiHelper::Assistant.new.generate_and_send_prompt(
|
||||
DiscourseAi::AiHelper::Assistant::GENERATE_TITLES,
|
||||
prompt,
|
||||
input,
|
||||
current_user,
|
||||
),
|
||||
@@ -111,12 +115,12 @@ module DiscourseAi
|
||||
location = params[:location]
|
||||
raise Discourse::InvalidParameters.new(:location) if !location
|
||||
|
||||
raise Discourse::InvalidParameters.new(:mode) if params[:mode].blank?
|
||||
if params[:mode] == DiscourseAi::AiHelper::Assistant::ILLUSTRATE_POST
|
||||
return suggest_thumbnails(input)
|
||||
end
|
||||
prompt = CompletionPrompt.find_by(id: params[:mode])
|
||||
|
||||
if params[:mode] == DiscourseAi::AiHelper::Assistant::CUSTOM_PROMPT
|
||||
raise Discourse::InvalidParameters.new(:mode) if !prompt || !prompt.enabled?
|
||||
return suggest_thumbnails(input) if prompt.id == CompletionPrompt::ILLUSTRATE_POST
|
||||
|
||||
if prompt.id == CompletionPrompt::CUSTOM_PROMPT
|
||||
raise Discourse::InvalidParameters.new(:custom_prompt) if params[:custom_prompt].blank?
|
||||
end
|
||||
|
||||
@@ -129,7 +133,7 @@ module DiscourseAi
|
||||
:stream_composer_helper,
|
||||
user_id: current_user.id,
|
||||
text: text,
|
||||
prompt: params[:mode],
|
||||
prompt: prompt.name,
|
||||
custom_prompt: params[:custom_prompt],
|
||||
force_default_locale: params[:force_default_locale] || false,
|
||||
client_id: params[:client_id],
|
||||
@@ -145,7 +149,7 @@ module DiscourseAi
|
||||
post_id: post.id,
|
||||
user_id: current_user.id,
|
||||
text: text,
|
||||
prompt: params[:mode],
|
||||
prompt: prompt.name,
|
||||
custom_prompt: params[:custom_prompt],
|
||||
client_id: params[:client_id],
|
||||
)
|
||||
|
||||
@@ -11,12 +11,12 @@ module ::Jobs
|
||||
message = ::Chat::Message.find_by(id: args[:message_id])
|
||||
return if message.blank?
|
||||
|
||||
personaClass =
|
||||
DiscourseAi::Personas::Persona.find_by(id: args[:persona_id], user: message.user)
|
||||
return if personaClass.blank?
|
||||
agentClass =
|
||||
DiscourseAi::Agents::Agent.find_by(id: args[:agent_id], user: message.user)
|
||||
return if agentClass.blank?
|
||||
|
||||
user = User.find_by(id: personaClass.user_id)
|
||||
bot = DiscourseAi::Personas::Bot.as(user, persona: personaClass.new)
|
||||
user = User.find_by(id: agentClass.user_id)
|
||||
bot = DiscourseAi::Agents::Bot.as(user, agent: agentClass.new)
|
||||
|
||||
DiscourseAi::AiBot::Playground.new(bot).reply_to_chat_message(
|
||||
message,
|
||||
|
||||
@@ -7,18 +7,18 @@ module ::Jobs
|
||||
def execute(args)
|
||||
return unless bot_user = User.find_by(id: args[:bot_user_id])
|
||||
return unless post = Post.includes(:topic).find_by(id: args[:post_id])
|
||||
persona_id = args[:persona_id]
|
||||
agent_id = args[:agent_id]
|
||||
|
||||
begin
|
||||
persona = DiscourseAi::Personas::Persona.find_by(user: post.user, id: persona_id)
|
||||
raise DiscourseAi::Personas::Bot::BOT_NOT_FOUND if persona.nil?
|
||||
agent = DiscourseAi::Agents::Agent.find_by(user: post.user, id: agent_id)
|
||||
raise DiscourseAi::Agents::Bot::BOT_NOT_FOUND if agent.nil?
|
||||
|
||||
bot = DiscourseAi::Personas::Bot.as(bot_user, persona: persona.new)
|
||||
bot = DiscourseAi::Agents::Bot.as(bot_user, agent: agent.new)
|
||||
|
||||
DiscourseAi::AiBot::Playground.new(bot).reply_to(post, feature_name: "bot")
|
||||
rescue DiscourseAi::Personas::Bot::BOT_NOT_FOUND
|
||||
DiscourseAi::AiBot::Playground.new(bot).reply_to(post)
|
||||
rescue DiscourseAi::Agents::Bot::BOT_NOT_FOUND
|
||||
Rails.logger.warn(
|
||||
"Bot not found for post #{post.id} - perhaps persona was deleted or bot was disabled",
|
||||
"Bot not found for post #{post.id} - perhaps agent was deleted or bot was disabled",
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user