Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9369d9d0d7 |
@@ -1,5 +1,3 @@
|
|||||||
< 3.5.0.beta3-dev: 09a68414804a1447f52e5d60691ba59742cda9ec
|
|
||||||
< 3.5.0.beta2-dev: de8624416a15b3d8e7ad350b083cc1420451ccec
|
|
||||||
< 3.5.0.beta1-dev: bdef136080074a993e7c4f5ca562edc31a8ba756
|
< 3.5.0.beta1-dev: bdef136080074a993e7c4f5ca562edc31a8ba756
|
||||||
< 3.4.0.beta4-dev: a53719ab8eb071459f215227421b3ea4987e5f87
|
< 3.4.0.beta4-dev: a53719ab8eb071459f215227421b3ea4987e5f87
|
||||||
< 3.4.0.beta4-dev: 20612fde52d3f740cad64823ef8aadb0748b567f
|
< 3.4.0.beta4-dev: 20612fde52d3f740cad64823ef8aadb0748b567f
|
||||||
|
|||||||
@@ -5,6 +5,3 @@ node_modules
|
|||||||
evals/log
|
evals/log
|
||||||
evals/cases
|
evals/cases
|
||||||
config/eval-llms.local.yml
|
config/eval-llms.local.yml
|
||||||
# this gets rid of search results from ag, ripgrep, etc
|
|
||||||
tokenizers/
|
|
||||||
public/ai-share/highlight.min.js
|
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ GEM
|
|||||||
racc
|
racc
|
||||||
prettier_print (1.2.1)
|
prettier_print (1.2.1)
|
||||||
racc (1.8.1)
|
racc (1.8.1)
|
||||||
rack (3.1.14)
|
rack (3.1.12)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
regexp_parser (2.10.0)
|
regexp_parser (2.10.0)
|
||||||
rubocop (1.74.0)
|
rubocop (1.74.0)
|
||||||
|
|||||||
+1
-2
@@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
"tests": {
|
"tests": {
|
||||||
"requiredPlugins": [
|
"requiredPlugins": [
|
||||||
"https://github.com/discourse/discourse-prometheus",
|
"https://github.com/discourse/discourse-prometheus"
|
||||||
"https://github.com/discourse/discourse-solved.git"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-27
@@ -1,27 +0,0 @@
|
|||||||
import { ajax } from "discourse/lib/ajax";
|
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
|
||||||
import SiteSetting from "admin/models/site-setting";
|
|
||||||
|
|
||||||
export default class AdminPluginsShowDiscourseAiFeaturesEdit extends DiscourseRoute {
|
|
||||||
async model(params) {
|
|
||||||
const allFeatures = this.modelFor(
|
|
||||||
"adminPlugins.show.discourse-ai-features"
|
|
||||||
);
|
|
||||||
const id = parseInt(params.id, 10);
|
|
||||||
const currentFeature = allFeatures.find((feature) => feature.id === id);
|
|
||||||
|
|
||||||
const { site_settings } = await ajax("/admin/config/site_settings.json", {
|
|
||||||
data: {
|
|
||||||
filter_area: `ai-features/${currentFeature.ref}`,
|
|
||||||
plugin: "discourse-ai",
|
|
||||||
category: "discourse_ai",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
currentFeature.feature_settings = site_settings.map((setting) =>
|
|
||||||
SiteSetting.create(setting)
|
|
||||||
);
|
|
||||||
|
|
||||||
return currentFeature;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import { service } from "@ember/service";
|
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
|
||||||
|
|
||||||
export default class AdminPluginsShowDiscourseAiFeatures extends DiscourseRoute {
|
|
||||||
@service store;
|
|
||||||
|
|
||||||
async model() {
|
|
||||||
return this.store.findAll("ai-feature");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-10
@@ -2,17 +2,8 @@ import DiscourseRoute from "discourse/routes/discourse";
|
|||||||
|
|
||||||
export default class AdminPluginsShowDiscourseAiLlmsEdit extends DiscourseRoute {
|
export default class AdminPluginsShowDiscourseAiLlmsEdit extends DiscourseRoute {
|
||||||
async model(params) {
|
async model(params) {
|
||||||
const id = parseInt(params.id, 10);
|
|
||||||
|
|
||||||
if (id < 0) {
|
|
||||||
// You shouldn't be able to access the edit page
|
|
||||||
// if the model is seeded
|
|
||||||
return this.router.transitionTo(
|
|
||||||
"adminPlugins.show.discourse-ai-llms.index"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const allLlms = this.modelFor("adminPlugins.show.discourse-ai-llms");
|
const allLlms = this.modelFor("adminPlugins.show.discourse-ai-llms");
|
||||||
|
const id = parseInt(params.id, 10);
|
||||||
const record = allLlms.findBy("id", id);
|
const record = allLlms.findBy("id", id);
|
||||||
record.provider_params = record.provider_params || {};
|
record.provider_params = record.provider_params || {};
|
||||||
return record;
|
return record;
|
||||||
|
|||||||
-24
@@ -1,24 +0,0 @@
|
|||||||
import RouteTemplate from "ember-route-template";
|
|
||||||
import BackButton from "discourse/components/back-button";
|
|
||||||
import SiteSettingComponent from "admin/components/site-setting";
|
|
||||||
|
|
||||||
export default RouteTemplate(
|
|
||||||
<template>
|
|
||||||
<BackButton
|
|
||||||
@route="adminPlugins.show.discourse-ai-features"
|
|
||||||
@label="discourse_ai.features.back"
|
|
||||||
/>
|
|
||||||
<section class="ai-feature-editor__header">
|
|
||||||
<h2>{{@model.name}}</h2>
|
|
||||||
<p>{{@model.description}}</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="ai-feature-editor">
|
|
||||||
{{#each @model.feature_settings as |setting|}}
|
|
||||||
<div>
|
|
||||||
<SiteSettingComponent @setting={{setting}} />
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</section>
|
|
||||||
</template>
|
|
||||||
);
|
|
||||||
-156
@@ -1,156 +0,0 @@
|
|||||||
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}.persona`),
|
|
||||||
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__persona"
|
|
||||||
>
|
|
||||||
<DButton
|
|
||||||
class="btn-flat btn-small ai-feature-list__row-item-persona"
|
|
||||||
@translatedLabel={{feature.persona.name}}
|
|
||||||
@route="adminPlugins.show.discourse-ai-personas.edit"
|
|
||||||
@routeModels={{feature.persona.id}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="d-admin-row__detail ai-feature-list__row-item ai-feature-list__groups"
|
|
||||||
>
|
|
||||||
{{#if (gt feature.persona.allowed_groups.length 0)}}
|
|
||||||
<ul class="ai-feature-list__row-item-groups">
|
|
||||||
{{#each feature.persona.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,36 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module DiscourseAi
|
|
||||||
module Admin
|
|
||||||
class AiFeaturesController < ::Admin::AdminController
|
|
||||||
requires_plugin ::DiscourseAi::PLUGIN_NAME
|
|
||||||
|
|
||||||
def index
|
|
||||||
render json: serialize_features(DiscourseAi::Features.features)
|
|
||||||
end
|
|
||||||
|
|
||||||
def edit
|
|
||||||
raise Discourse::InvalidParameters.new(:id) if params[:id].blank?
|
|
||||||
render json: serialize_feature(DiscourseAi::Features.find_feature_by_id(params[:id].to_i))
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def serialize_features(features)
|
|
||||||
features.map { |feature| feature.merge(persona: serialize_persona(feature[:persona])) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def serialize_feature(feature)
|
|
||||||
return nil if feature.blank?
|
|
||||||
|
|
||||||
feature.merge(persona: serialize_persona(feature[:persona]))
|
|
||||||
end
|
|
||||||
|
|
||||||
def serialize_persona(persona)
|
|
||||||
return nil if persona.blank?
|
|
||||||
|
|
||||||
serialize_data(persona, AiFeaturesPersonaSerializer, root: false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -157,13 +157,9 @@ module DiscourseAi
|
|||||||
:provider,
|
:provider,
|
||||||
:tokenizer,
|
:tokenizer,
|
||||||
:max_prompt_tokens,
|
:max_prompt_tokens,
|
||||||
:max_output_tokens,
|
|
||||||
:api_key,
|
:api_key,
|
||||||
:enabled_chat_bot,
|
:enabled_chat_bot,
|
||||||
:vision_enabled,
|
:vision_enabled,
|
||||||
:input_cost,
|
|
||||||
:cached_input_cost,
|
|
||||||
:output_cost,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = updating ? updating.provider : permitted[:provider]
|
provider = updating ? updating.provider : permitted[:provider]
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ module DiscourseAi
|
|||||||
LocalizedAiPersonaSerializer.new(persona, root: false)
|
LocalizedAiPersonaSerializer.new(persona, root: false)
|
||||||
end
|
end
|
||||||
tools =
|
tools =
|
||||||
DiscourseAi::Personas::Persona.all_available_tools.map do |tool|
|
DiscourseAi::AiBot::Personas::Persona.all_available_tools.map do |tool|
|
||||||
AiToolSerializer.new(tool, root: false)
|
AiToolSerializer.new(tool, root: false)
|
||||||
end
|
end
|
||||||
AiTool
|
AiTool
|
||||||
@@ -221,14 +221,6 @@ module DiscourseAi
|
|||||||
permitted[:tools] = permit_tools(tools)
|
permitted[:tools] = permit_tools(tools)
|
||||||
end
|
end
|
||||||
|
|
||||||
if response_format = params.dig(:ai_persona, :response_format)
|
|
||||||
permitted[:response_format] = permit_response_format(response_format)
|
|
||||||
end
|
|
||||||
|
|
||||||
if examples = params.dig(:ai_persona, :examples)
|
|
||||||
permitted[:examples] = permit_examples(examples)
|
|
||||||
end
|
|
||||||
|
|
||||||
permitted
|
permitted
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -243,24 +235,6 @@ module DiscourseAi
|
|||||||
[tool, options, !!force_tool]
|
[tool, options, !!force_tool]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def permit_response_format(response_format)
|
|
||||||
return [] if !response_format.is_a?(Array)
|
|
||||||
|
|
||||||
response_format.map do |element|
|
|
||||||
if element && element.is_a?(ActionController::Parameters)
|
|
||||||
element.permit!
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def permit_examples(examples)
|
|
||||||
return [] if !examples.is_a?(Array)
|
|
||||||
|
|
||||||
examples.map { |example_arr| example_arr.take(2).map(&:to_s) }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ module DiscourseAi
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
SiteSetting.set_and_log("ai_spam_detection_enabled", is_enabled, current_user)
|
SiteSetting.ai_spam_detection_enabled = is_enabled
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: AiSpamSerializer.new(spam_config, root: false)
|
render json: AiSpamSerializer.new(spam_config, root: false)
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ module DiscourseAi
|
|||||||
# we need an llm so we have a tokenizer
|
# we need an llm so we have a tokenizer
|
||||||
# but will do without if none is available
|
# but will do without if none is available
|
||||||
llm = LlmModel.first&.to_llm
|
llm = LlmModel.first&.to_llm
|
||||||
runner = @ai_tool.runner(parameters, llm: llm, bot_user: current_user)
|
runner = @ai_tool.runner(parameters, llm: llm, bot_user: current_user, context: {})
|
||||||
result = runner.invoke
|
result = runner.invoke
|
||||||
|
|
||||||
if result.is_a?(Hash) && result[:error]
|
if result.is_a?(Hash) && result[:error]
|
||||||
|
|||||||
@@ -42,21 +42,6 @@ module DiscourseAi
|
|||||||
<style>
|
<style>
|
||||||
#{artifact.css}
|
#{artifact.css}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
|
||||||
window._discourse_user_data = {
|
|
||||||
#{current_user ? "username: #{current_user.username.to_json}" : "username: null"}
|
|
||||||
};
|
|
||||||
window.discourseArtifactReady = new Promise(resolve => {
|
|
||||||
window._resolveArtifactData = resolve;
|
|
||||||
});
|
|
||||||
window.addEventListener('message', function(event) {
|
|
||||||
if (event.data && event.data.type === 'discourse-artifact-data') {
|
|
||||||
window.discourseArtifactData = event.data.dataset || {};
|
|
||||||
Object.assign(window.discourseArtifactData, window._discourse_user_data);
|
|
||||||
window._resolveArtifactData(window.discourseArtifactData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
#{artifact.html}
|
#{artifact.html}
|
||||||
@@ -89,19 +74,6 @@ module DiscourseAi
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<iframe sandbox="allow-scripts allow-forms" height="100%" width="100%" srcdoc="#{ERB::Util.html_escape(untrusted_html)}" frameborder="0"></iframe>
|
<iframe sandbox="allow-scripts allow-forms" height="100%" width="100%" srcdoc="#{ERB::Util.html_escape(untrusted_html)}" frameborder="0"></iframe>
|
||||||
<script>
|
|
||||||
document.querySelector('iframe').addEventListener('load', function() {
|
|
||||||
try {
|
|
||||||
const iframeWindow = this.contentWindow;
|
|
||||||
const message = { type: 'discourse-artifact-data', dataset: {} };
|
|
||||||
|
|
||||||
if (window.frameElement && window.frameElement.dataset) {
|
|
||||||
Object.assign(message.dataset, window.frameElement.dataset);
|
|
||||||
}
|
|
||||||
iframeWindow.postMessage(message, '*');
|
|
||||||
} catch (e) { console.error('Error passing data to artifact:', e); }
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
HTML
|
HTML
|
||||||
|
|||||||
@@ -47,9 +47,9 @@ module DiscourseAi
|
|||||||
|
|
||||||
def discover
|
def discover
|
||||||
ai_persona =
|
ai_persona =
|
||||||
AiPersona
|
AiPersona.all_personas.find do |persona|
|
||||||
.all_personas(enabled_only: false)
|
persona.id == SiteSetting.ai_bot_discover_persona.to_i
|
||||||
.find { |persona| persona.id == SiteSetting.ai_bot_discover_persona.to_i }
|
end
|
||||||
|
|
||||||
if ai_persona.nil? || !current_user.in_any_groups?(ai_persona.allowed_group_ids.to_a)
|
if ai_persona.nil? || !current_user.in_any_groups?(ai_persona.allowed_group_ids.to_a)
|
||||||
raise Discourse::InvalidAccess.new
|
raise Discourse::InvalidAccess.new
|
||||||
@@ -69,40 +69,6 @@ module DiscourseAi
|
|||||||
|
|
||||||
render json: {}, status: 200
|
render json: {}, status: 200
|
||||||
end
|
end
|
||||||
|
|
||||||
def discover_continue_convo
|
|
||||||
raise Discourse::InvalidParameters.new("user_id") if !params[:user_id]
|
|
||||||
raise Discourse::InvalidParameters.new("query") if !params[:query]
|
|
||||||
raise Discourse::InvalidParameters.new("context") if !params[:context]
|
|
||||||
|
|
||||||
user = User.find(params[:user_id])
|
|
||||||
|
|
||||||
bot_user_id = AiPersona.find_by(id: SiteSetting.ai_bot_discover_persona).user_id
|
|
||||||
bot_username = User.find_by(id: bot_user_id).username
|
|
||||||
|
|
||||||
query = params[:query]
|
|
||||||
context = "[quote]\n#{params[:context]}\n[/quote]"
|
|
||||||
|
|
||||||
post =
|
|
||||||
PostCreator.create!(
|
|
||||||
user,
|
|
||||||
title:
|
|
||||||
I18n.t("discourse_ai.ai_bot.discoveries.continue_conversation.title", query: query),
|
|
||||||
raw:
|
|
||||||
I18n.t(
|
|
||||||
"discourse_ai.ai_bot.discoveries.continue_conversation.raw",
|
|
||||||
query: query,
|
|
||||||
context: context,
|
|
||||||
),
|
|
||||||
archetype: Archetype.private_message,
|
|
||||||
target_usernames: bot_username,
|
|
||||||
skip_validations: true,
|
|
||||||
)
|
|
||||||
|
|
||||||
render json: success_json.merge(topic_id: post.topic_id)
|
|
||||||
rescue StandardError => e
|
|
||||||
render json: failed_json.merge(errors: [e.message]), status: 422
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module DiscourseAi
|
|
||||||
module AiBot
|
|
||||||
class ConversationsController < ::ApplicationController
|
|
||||||
requires_plugin ::DiscourseAi::PLUGIN_NAME
|
|
||||||
requires_login
|
|
||||||
|
|
||||||
def index
|
|
||||||
page = params[:page].to_i
|
|
||||||
per_page = params[:per_page]&.to_i || 40
|
|
||||||
|
|
||||||
base_query =
|
|
||||||
Topic
|
|
||||||
.private_messages_for_user(current_user)
|
|
||||||
.where(user: current_user) # Only show PMs where the current user is the author
|
|
||||||
.joins(
|
|
||||||
"INNER JOIN topic_custom_fields tcf ON tcf.topic_id = topics.id
|
|
||||||
AND tcf.name = '#{DiscourseAi::AiBot::TOPIC_AI_BOT_PM_FIELD}'
|
|
||||||
AND tcf.value = 't'",
|
|
||||||
)
|
|
||||||
.distinct
|
|
||||||
|
|
||||||
total = base_query.count
|
|
||||||
pms = base_query.order(last_posted_at: :desc).offset(page * per_page).limit(per_page)
|
|
||||||
|
|
||||||
render json: {
|
|
||||||
conversations: serialize_data(pms, ListableTopicSerializer),
|
|
||||||
meta: {
|
|
||||||
total: total,
|
|
||||||
page: page,
|
|
||||||
per_page: per_page,
|
|
||||||
has_more: total > (page + 1) * per_page,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -8,7 +8,7 @@ module DiscourseAi
|
|||||||
before_action :require_site_settings!
|
before_action :require_site_settings!
|
||||||
|
|
||||||
skip_before_action :preload_json, :check_xhr, only: %i[show asset]
|
skip_before_action :preload_json, :check_xhr, only: %i[show asset]
|
||||||
skip_before_action :redirect_to_login_if_required, :verify_authenticity_token, only: %i[asset]
|
skip_before_action :verify_authenticity_token, only: ["asset"]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
ensure_allowed_create!
|
ensure_allowed_create!
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ module DiscourseAi
|
|||||||
prompt,
|
prompt,
|
||||||
input,
|
input,
|
||||||
current_user,
|
current_user,
|
||||||
force_default_locale: force_default_locale,
|
force_default_locale,
|
||||||
),
|
),
|
||||||
status: 200
|
status: 200
|
||||||
end
|
end
|
||||||
@@ -110,50 +110,26 @@ module DiscourseAi
|
|||||||
end
|
end
|
||||||
|
|
||||||
def stream_suggestion
|
def stream_suggestion
|
||||||
|
post_id = get_post_param!
|
||||||
text = get_text_param!
|
text = get_text_param!
|
||||||
|
post = Post.includes(:topic).find_by(id: post_id)
|
||||||
location = params[:location]
|
|
||||||
raise Discourse::InvalidParameters.new(:location) if !location
|
|
||||||
|
|
||||||
prompt = CompletionPrompt.find_by(id: params[:mode])
|
prompt = CompletionPrompt.find_by(id: params[:mode])
|
||||||
|
|
||||||
raise Discourse::InvalidParameters.new(:mode) if !prompt || !prompt.enabled?
|
raise Discourse::InvalidParameters.new(:mode) if !prompt || !prompt.enabled?
|
||||||
return suggest_thumbnails(input) if prompt.id == CompletionPrompt::ILLUSTRATE_POST
|
raise Discourse::InvalidParameters.new(:post_id) unless post
|
||||||
|
|
||||||
if prompt.id == CompletionPrompt::CUSTOM_PROMPT
|
if prompt.id == CompletionPrompt::CUSTOM_PROMPT
|
||||||
raise Discourse::InvalidParameters.new(:custom_prompt) if params[:custom_prompt].blank?
|
raise Discourse::InvalidParameters.new(:custom_prompt) if params[:custom_prompt].blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
# to stream we must have an appropriate client_id
|
Jobs.enqueue(
|
||||||
# otherwise we may end up streaming the data to the wrong client
|
:stream_post_helper,
|
||||||
raise Discourse::InvalidParameters.new(:client_id) if params[:client_id].blank?
|
post_id: post.id,
|
||||||
|
user_id: current_user.id,
|
||||||
if location == "composer"
|
text: text,
|
||||||
Jobs.enqueue(
|
prompt: prompt.name,
|
||||||
:stream_composer_helper,
|
custom_prompt: params[:custom_prompt],
|
||||||
user_id: current_user.id,
|
)
|
||||||
text: text,
|
|
||||||
prompt: prompt.name,
|
|
||||||
custom_prompt: params[:custom_prompt],
|
|
||||||
force_default_locale: params[:force_default_locale] || false,
|
|
||||||
client_id: params[:client_id],
|
|
||||||
)
|
|
||||||
else
|
|
||||||
post_id = get_post_param!
|
|
||||||
post = Post.includes(:topic).find_by(id: post_id)
|
|
||||||
|
|
||||||
raise Discourse::InvalidParameters.new(:post_id) unless post
|
|
||||||
|
|
||||||
Jobs.enqueue(
|
|
||||||
:stream_post_helper,
|
|
||||||
post_id: post.id,
|
|
||||||
user_id: current_user.id,
|
|
||||||
text: text,
|
|
||||||
prompt: prompt.name,
|
|
||||||
custom_prompt: params[:custom_prompt],
|
|
||||||
client_id: params[:client_id],
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
render json: { success: true }, status: 200
|
render json: { success: true }, status: 200
|
||||||
rescue DiscourseAi::Completions::Endpoints::Base::CompletionFailed
|
rescue DiscourseAi::Completions::Endpoints::Base::CompletionFailed
|
||||||
|
|||||||
@@ -46,19 +46,11 @@ module DiscourseAi
|
|||||||
end
|
end
|
||||||
|
|
||||||
hijack do
|
hijack do
|
||||||
begin
|
semantic_search
|
||||||
semantic_search
|
.search_for_topics(query, _page = 1, hyde: !skip_hyde)
|
||||||
.search_for_topics(query, _page = 1, hyde: !skip_hyde)
|
.each { |topic_post| grouped_results.add(topic_post) }
|
||||||
.each { |topic_post| grouped_results.add(topic_post) }
|
|
||||||
|
|
||||||
render_serialized(
|
render_serialized(grouped_results, GroupedSearchResultSerializer, result: grouped_results)
|
||||||
grouped_results,
|
|
||||||
GroupedSearchResultSerializer,
|
|
||||||
result: grouped_results,
|
|
||||||
)
|
|
||||||
rescue Discourse::InvalidAccess
|
|
||||||
render_json_error(I18n.t("invalid_access"), status: 403)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ module DiscourseAi
|
|||||||
u.name,
|
u.name,
|
||||||
u.uploaded_avatar_id,
|
u.uploaded_avatar_id,
|
||||||
c.id AS category_id,
|
c.id AS category_id,
|
||||||
|
c.name AS category_name,
|
||||||
|
c.color AS category_color,
|
||||||
|
c.slug AS category_slug,
|
||||||
|
c.description AS category_description,
|
||||||
(CASE
|
(CASE
|
||||||
WHEN (cr.classification::jsonb->'positive')::float > :threshold THEN 'positive'
|
WHEN (cr.classification::jsonb->'positive')::float > :threshold THEN 'positive'
|
||||||
WHEN (cr.classification::jsonb->'negative')::float > :threshold THEN 'negative'
|
WHEN (cr.classification::jsonb->'negative')::float > :threshold THEN 'negative'
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ module ::Jobs
|
|||||||
return if message.blank?
|
return if message.blank?
|
||||||
|
|
||||||
personaClass =
|
personaClass =
|
||||||
DiscourseAi::Personas::Persona.find_by(id: args[:persona_id], user: message.user)
|
DiscourseAi::AiBot::Personas::Persona.find_by(id: args[:persona_id], user: message.user)
|
||||||
return if personaClass.blank?
|
return if personaClass.blank?
|
||||||
|
|
||||||
user = User.find_by(id: personaClass.user_id)
|
user = User.find_by(id: personaClass.user_id)
|
||||||
bot = DiscourseAi::Personas::Bot.as(user, persona: personaClass.new)
|
bot = DiscourseAi::AiBot::Bot.as(user, persona: personaClass.new)
|
||||||
|
|
||||||
DiscourseAi::AiBot::Playground.new(bot).reply_to_chat_message(
|
DiscourseAi::AiBot::Playground.new(bot).reply_to_chat_message(
|
||||||
message,
|
message,
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ module ::Jobs
|
|||||||
persona_id = args[:persona_id]
|
persona_id = args[:persona_id]
|
||||||
|
|
||||||
begin
|
begin
|
||||||
persona = DiscourseAi::Personas::Persona.find_by(user: post.user, id: persona_id)
|
persona = DiscourseAi::AiBot::Personas::Persona.find_by(user: post.user, id: persona_id)
|
||||||
raise DiscourseAi::Personas::Bot::BOT_NOT_FOUND if persona.nil?
|
raise DiscourseAi::AiBot::Bot::BOT_NOT_FOUND if persona.nil?
|
||||||
|
|
||||||
bot = DiscourseAi::Personas::Bot.as(bot_user, persona: persona.new)
|
bot = DiscourseAi::AiBot::Bot.as(bot_user, persona: persona.new)
|
||||||
|
|
||||||
DiscourseAi::AiBot::Playground.new(bot).reply_to(post)
|
DiscourseAi::AiBot::Playground.new(bot).reply_to(post)
|
||||||
rescue DiscourseAi::Personas::Bot::BOT_NOT_FOUND
|
rescue DiscourseAi::AiBot::Bot::BOT_NOT_FOUND
|
||||||
Rails.logger.warn(
|
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 persona was deleted or bot was disabled",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Jobs
|
|
||||||
class DetectTranslatePost < ::Jobs::Base
|
|
||||||
sidekiq_options retry: false
|
|
||||||
|
|
||||||
def execute(args)
|
|
||||||
return if !SiteSetting.discourse_ai_enabled
|
|
||||||
return if !SiteSetting.ai_translation_enabled
|
|
||||||
return if args[:post_id].blank?
|
|
||||||
|
|
||||||
post = Post.find_by(id: args[:post_id])
|
|
||||||
return if post.blank? || post.raw.blank? || post.deleted_at.present? || post.user_id <= 0
|
|
||||||
|
|
||||||
if SiteSetting.ai_translation_backfill_limit_to_public_content
|
|
||||||
topic = post.topic
|
|
||||||
if topic.blank? || topic.category&.read_restricted? ||
|
|
||||||
topic.archetype == Archetype.private_message
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
detected_locale = DiscourseAi::Translation::PostLocaleDetector.detect_locale(post)
|
|
||||||
rescue FinalDestination::SSRFDetector::LookupFailedError
|
|
||||||
# this job is non-critical
|
|
||||||
# the backfill job will handle failures
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
locales = SiteSetting.experimental_content_localization_supported_locales.split("|")
|
|
||||||
return if locales.blank?
|
|
||||||
|
|
||||||
locales.each do |locale|
|
|
||||||
next if locale == detected_locale
|
|
||||||
|
|
||||||
begin
|
|
||||||
DiscourseAi::Translation::PostLocalizer.localize(post, locale)
|
|
||||||
rescue FinalDestination::SSRFDetector::LookupFailedError
|
|
||||||
# do nothing, there are too many sporadic lookup failures
|
|
||||||
rescue => e
|
|
||||||
DiscourseAi::Translation::VerboseLogger.log(
|
|
||||||
"Failed to translate post #{post.id} to #{locale}: #{e.message}",
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
MessageBus.publish("/topic/#{post.topic_id}", type: :localized, id: post.id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Jobs
|
|
||||||
class DetectTranslateTopic < ::Jobs::Base
|
|
||||||
sidekiq_options retry: false
|
|
||||||
|
|
||||||
def execute(args)
|
|
||||||
return if !SiteSetting.discourse_ai_enabled
|
|
||||||
return if !SiteSetting.ai_translation_enabled
|
|
||||||
return if args[:topic_id].blank?
|
|
||||||
|
|
||||||
topic = Topic.find_by(id: args[:topic_id])
|
|
||||||
if topic.blank? || topic.title.blank? || topic.deleted_at.present? || topic.user_id <= 0
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if SiteSetting.ai_translation_backfill_limit_to_public_content
|
|
||||||
return if topic.category&.read_restricted?
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
detected_locale = DiscourseAi::Translation::TopicLocaleDetector.detect_locale(topic)
|
|
||||||
rescue FinalDestination::SSRFDetector::LookupFailedError
|
|
||||||
# this job is non-critical
|
|
||||||
# the backfill job will handle failures
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
locales = SiteSetting.experimental_content_localization_supported_locales.split("|")
|
|
||||||
return if locales.blank?
|
|
||||||
|
|
||||||
locales.each do |locale|
|
|
||||||
next if locale == detected_locale
|
|
||||||
|
|
||||||
begin
|
|
||||||
DiscourseAi::Translation::TopicLocalizer.localize(topic, locale)
|
|
||||||
rescue FinalDestination::SSRFDetector::LookupFailedError
|
|
||||||
# do nothing, there are too many sporadic lookup failures
|
|
||||||
rescue => e
|
|
||||||
DiscourseAi::Translation::VerboseLogger.log(
|
|
||||||
"Failed to translate topic #{topic.id} to #{locale}: #{e.message}",
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
MessageBus.publish("/topic/#{topic.id}", type: :localized, id: 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Jobs
|
|
||||||
class LocalizeCategories < ::Jobs::Base
|
|
||||||
cluster_concurrency 1
|
|
||||||
sidekiq_options retry: false
|
|
||||||
|
|
||||||
BATCH_SIZE = 50
|
|
||||||
|
|
||||||
def execute(args)
|
|
||||||
return if !SiteSetting.discourse_ai_enabled
|
|
||||||
return if !SiteSetting.ai_translation_enabled
|
|
||||||
|
|
||||||
locales = SiteSetting.experimental_content_localization_supported_locales.split("|")
|
|
||||||
return if locales.blank?
|
|
||||||
|
|
||||||
cat_id = args[:from_category_id] || Category.order(:id).first&.id
|
|
||||||
last_id = nil
|
|
||||||
|
|
||||||
categories = Category.where("id >= ?", cat_id).order(:id).limit(BATCH_SIZE)
|
|
||||||
return if categories.empty?
|
|
||||||
|
|
||||||
categories.each do |category|
|
|
||||||
if SiteSetting.ai_translation_backfill_limit_to_public_content && category.read_restricted?
|
|
||||||
last_id = category.id
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
CategoryLocalization.transaction do
|
|
||||||
locales.each do |locale|
|
|
||||||
next if CategoryLocalization.exists?(category_id: category.id, locale: locale)
|
|
||||||
begin
|
|
||||||
DiscourseAi::Translation::CategoryLocalizer.localize(category, locale)
|
|
||||||
rescue FinalDestination::SSRFDetector::LookupFailedError
|
|
||||||
# do nothing, there are too many sporadic lookup failures
|
|
||||||
rescue => e
|
|
||||||
DiscourseAi::Translation::VerboseLogger.log(
|
|
||||||
"Failed to translate category #{category.id} to #{locale}: #{e.message}",
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
last_id = category.id
|
|
||||||
end
|
|
||||||
|
|
||||||
if categories.size == BATCH_SIZE
|
|
||||||
Jobs.enqueue_in(10.seconds, :localize_categories, from_category_id: last_id + 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Jobs
|
|
||||||
class LocalizePosts < ::Jobs::Base
|
|
||||||
cluster_concurrency 1
|
|
||||||
sidekiq_options retry: false
|
|
||||||
|
|
||||||
BATCH_SIZE = 50
|
|
||||||
|
|
||||||
def execute(args)
|
|
||||||
return if !SiteSetting.discourse_ai_enabled
|
|
||||||
return if !SiteSetting.ai_translation_enabled
|
|
||||||
|
|
||||||
locales = SiteSetting.experimental_content_localization_supported_locales.split("|")
|
|
||||||
return if locales.blank?
|
|
||||||
|
|
||||||
limit = args[:limit] || BATCH_SIZE
|
|
||||||
|
|
||||||
locales.each do |locale|
|
|
||||||
posts =
|
|
||||||
Post
|
|
||||||
.joins(
|
|
||||||
"LEFT JOIN post_localizations pl ON pl.post_id = posts.id AND pl.locale = #{ActiveRecord::Base.connection.quote(locale)}",
|
|
||||||
)
|
|
||||||
.where(deleted_at: nil)
|
|
||||||
.where("posts.user_id > 0")
|
|
||||||
.where.not(raw: [nil, ""])
|
|
||||||
.where.not(locale: nil)
|
|
||||||
.where.not(locale: locale)
|
|
||||||
.where("pl.id IS NULL")
|
|
||||||
|
|
||||||
if SiteSetting.ai_translation_backfill_limit_to_public_content
|
|
||||||
posts =
|
|
||||||
posts
|
|
||||||
.joins(:topic)
|
|
||||||
.where(topics: { category_id: Category.where(read_restricted: false).select(:id) })
|
|
||||||
.where.not(topics: { archetype: Archetype.private_message })
|
|
||||||
end
|
|
||||||
|
|
||||||
if SiteSetting.ai_translation_backfill_max_age_days > 0
|
|
||||||
posts =
|
|
||||||
posts.where(
|
|
||||||
"posts.created_at > ?",
|
|
||||||
SiteSetting.ai_translation_backfill_max_age_days.days.ago,
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
posts = posts.order(updated_at: :desc).limit(limit)
|
|
||||||
|
|
||||||
next if posts.empty?
|
|
||||||
|
|
||||||
posts.each do |post|
|
|
||||||
begin
|
|
||||||
DiscourseAi::Translation::PostLocalizer.localize(post, locale)
|
|
||||||
rescue FinalDestination::SSRFDetector::LookupFailedError
|
|
||||||
# do nothing, there are too many sporadic lookup failures
|
|
||||||
rescue => e
|
|
||||||
DiscourseAi::Translation::VerboseLogger.log(
|
|
||||||
"Failed to translate post #{post.id} to #{locale}: #{e.message}",
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
DiscourseAi::Translation::VerboseLogger.log("Translated #{posts.size} posts to #{locale}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Jobs
|
|
||||||
class LocalizeTopics < ::Jobs::Base
|
|
||||||
cluster_concurrency 1
|
|
||||||
sidekiq_options retry: false
|
|
||||||
|
|
||||||
BATCH_SIZE = 50
|
|
||||||
|
|
||||||
def execute(args)
|
|
||||||
return if !SiteSetting.discourse_ai_enabled
|
|
||||||
return if !SiteSetting.ai_translation_enabled
|
|
||||||
|
|
||||||
locales = SiteSetting.experimental_content_localization_supported_locales.split("|")
|
|
||||||
return if locales.blank?
|
|
||||||
|
|
||||||
limit = args[:limit] || BATCH_SIZE
|
|
||||||
|
|
||||||
locales.each do |locale|
|
|
||||||
topics =
|
|
||||||
Topic
|
|
||||||
.joins(
|
|
||||||
"LEFT JOIN topic_localizations tl ON tl.topic_id = topics.id AND tl.locale = #{ActiveRecord::Base.connection.quote(locale)}",
|
|
||||||
)
|
|
||||||
.where(deleted_at: nil)
|
|
||||||
.where("topics.user_id > 0")
|
|
||||||
.where.not(locale: nil)
|
|
||||||
.where.not(locale: locale)
|
|
||||||
.where("tl.id IS NULL")
|
|
||||||
|
|
||||||
if SiteSetting.ai_translation_backfill_limit_to_public_content
|
|
||||||
topics = topics.where(category_id: Category.where(read_restricted: false).select(:id))
|
|
||||||
end
|
|
||||||
|
|
||||||
if SiteSetting.ai_translation_backfill_max_age_days > 0
|
|
||||||
topics =
|
|
||||||
topics.where(
|
|
||||||
"topics.created_at > ?",
|
|
||||||
SiteSetting.ai_translation_backfill_max_age_days.days.ago,
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
topics = topics.order(updated_at: :desc).limit(limit)
|
|
||||||
|
|
||||||
next if topics.empty?
|
|
||||||
|
|
||||||
topics.each do |topic|
|
|
||||||
begin
|
|
||||||
DiscourseAi::Translation::TopicLocalizer.localize(topic, locale)
|
|
||||||
rescue FinalDestination::SSRFDetector::LookupFailedError
|
|
||||||
# do nothing, there are too many sporadic lookup failures
|
|
||||||
rescue => e
|
|
||||||
DiscourseAi::Translation::VerboseLogger.log(
|
|
||||||
"Failed to translate topic #{topic.id} to #{locale}: #{e.message}",
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
DiscourseAi::Translation::VerboseLogger.log("Translated #{topics.size} topics to #{locale}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Jobs
|
|
||||||
class StreamComposerHelper < ::Jobs::Base
|
|
||||||
sidekiq_options retry: false
|
|
||||||
|
|
||||||
def execute(args)
|
|
||||||
return unless args[:prompt]
|
|
||||||
return unless user = User.find_by(id: args[:user_id])
|
|
||||||
return unless args[:text]
|
|
||||||
return unless args[:client_id]
|
|
||||||
|
|
||||||
prompt = CompletionPrompt.enabled_by_name(args[:prompt])
|
|
||||||
|
|
||||||
if prompt.id == CompletionPrompt::CUSTOM_PROMPT
|
|
||||||
prompt.custom_instruction = args[:custom_prompt]
|
|
||||||
end
|
|
||||||
|
|
||||||
DiscourseAi::AiHelper::Assistant.new.stream_prompt(
|
|
||||||
prompt,
|
|
||||||
args[:text],
|
|
||||||
user,
|
|
||||||
"/discourse-ai/ai-helper/stream_composer_suggestion",
|
|
||||||
force_default_locale: args[:force_default_locale],
|
|
||||||
client_id: args[:client_id],
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -7,8 +7,6 @@ module Jobs
|
|||||||
def execute(args)
|
def execute(args)
|
||||||
interaction = args[:interaction]
|
interaction = args[:interaction]
|
||||||
|
|
||||||
return unless SiteSetting.ai_discord_search_enabled
|
|
||||||
|
|
||||||
if SiteSetting.ai_discord_search_mode == "persona"
|
if SiteSetting.ai_discord_search_mode == "persona"
|
||||||
DiscourseAi::Discord::Bot::PersonaReplier.new(interaction).handle_interaction!
|
DiscourseAi::Discord::Bot::PersonaReplier.new(interaction).handle_interaction!
|
||||||
else
|
else
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user