mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-03-09 02:40:50 +00:00
Previously we were not using using HeaderPanel for drop down, which caused it not to properly act like a header panel. - Not styled right - Not hidden when other buttons clicked Etc... Header is sadly full of legacy so this is somewhat hacky weaving widgets.
167 lines
4.8 KiB
JavaScript
167 lines
4.8 KiB
JavaScript
import { withPluginApi } from "discourse/lib/plugin-api";
|
|
import { cookAsync } from "discourse/lib/text";
|
|
import { ajax } from "discourse/lib/ajax";
|
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
|
import loadScript from "discourse/lib/load-script";
|
|
import { composeAiBotMessage } from "discourse/plugins/discourse-ai/discourse/lib/ai-bot-helper";
|
|
|
|
function isGPTBot(user) {
|
|
return user && [-110, -111, -112].includes(user.id);
|
|
}
|
|
|
|
function attachHeaderIcon(api) {
|
|
const settings = api.container.lookup("service:site-settings");
|
|
|
|
const enabledBots = settings.ai_helper_add_ai_pm_to_header
|
|
? settings.ai_bot_enabled_chat_bots.split("|").filter(Boolean)
|
|
: [];
|
|
if (enabledBots.length > 0) {
|
|
api.attachWidgetAction("header", "showAiBotPanel", function () {
|
|
this.state.botSelectorVisible = true;
|
|
});
|
|
|
|
api.attachWidgetAction("header", "hideAiBotPanel", function () {
|
|
this.state.botSelectorVisible = false;
|
|
});
|
|
|
|
api.attachWidgetAction("header", "toggleAiBotPanel", function () {
|
|
this.state.botSelectorVisible = !this.state.botSelectorVisible;
|
|
});
|
|
|
|
api.decorateWidget("header-icons:before", (helper) => {
|
|
return helper.attach("header-dropdown", {
|
|
title: "blog.start_gpt_chat",
|
|
icon: "robot",
|
|
action: "clickStartAiBotChat",
|
|
active: false,
|
|
classNames: ["ai-bot-button"],
|
|
});
|
|
});
|
|
|
|
if (enabledBots.length === 1) {
|
|
api.attachWidgetAction("header", "clickStartAiBotChat", function () {
|
|
composeAiBotMessage(
|
|
enabledBots[0],
|
|
api.container.lookup("service:composer")
|
|
);
|
|
});
|
|
} else {
|
|
api.attachWidgetAction("header", "clickStartAiBotChat", function () {
|
|
this.sendWidgetAction("showAiBotPanel");
|
|
});
|
|
}
|
|
|
|
api.addHeaderPanel(
|
|
"ai-bot-header-panel-wrapper",
|
|
"botSelectorVisible",
|
|
function () {
|
|
return {};
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
function initializeAIBotReplies(api) {
|
|
api.addPostMenuButton("cancel-gpt", (post) => {
|
|
if (isGPTBot(post.user)) {
|
|
return {
|
|
icon: "pause",
|
|
action: "cancelStreaming",
|
|
title: "discourse_ai.ai_bot.cancel_streaming",
|
|
className: "btn btn-default cancel-streaming",
|
|
position: "first",
|
|
};
|
|
}
|
|
});
|
|
|
|
api.attachWidgetAction("post", "cancelStreaming", function () {
|
|
ajax(`/discourse-ai/ai-bot/post/${this.model.id}/stop-streaming`, {
|
|
type: "POST",
|
|
})
|
|
.then(() => {
|
|
document
|
|
.querySelector(`#post_${this.model.post_number}`)
|
|
.classList.remove("streaming");
|
|
})
|
|
.catch(popupAjaxError);
|
|
});
|
|
|
|
api.modifyClass("controller:topic", {
|
|
pluginId: "discourse-ai",
|
|
|
|
onAIBotStreamedReply: function (data) {
|
|
const post = this.model.postStream.findLoadedPost(data.post_id);
|
|
|
|
if (post) {
|
|
if (data.raw) {
|
|
cookAsync(data.raw).then((cooked) => {
|
|
post.set("raw", data.raw);
|
|
post.set("cooked", cooked);
|
|
|
|
document
|
|
.querySelector(`#post_${data.post_number}`)
|
|
.classList.add("streaming");
|
|
|
|
const cookedElement = document.createElement("div");
|
|
cookedElement.innerHTML = cooked;
|
|
|
|
let element = document.querySelector(
|
|
`#post_${data.post_number} .cooked`
|
|
);
|
|
|
|
loadScript("/javascripts/diffhtml.min.js").then(() => {
|
|
window.diff.innerHTML(element, cookedElement.innerHTML);
|
|
});
|
|
});
|
|
}
|
|
if (data.done) {
|
|
document
|
|
.querySelector(`#post_${data.post_number}`)
|
|
.classList.remove("streaming");
|
|
}
|
|
}
|
|
},
|
|
subscribe: function () {
|
|
this._super();
|
|
|
|
if (
|
|
this.model.isPrivateMessage &&
|
|
this.model.details.allowed_users &&
|
|
this.model.details.allowed_users.filter(isGPTBot).length >= 1
|
|
) {
|
|
this.messageBus.subscribe(
|
|
`discourse-ai/ai-bot/topic/${this.model.id}`,
|
|
this.onAIBotStreamedReply.bind(this)
|
|
);
|
|
}
|
|
},
|
|
unsubscribe: function () {
|
|
this.messageBus.unsubscribe("discourse-ai/ai-bot/topic/*");
|
|
this._super();
|
|
},
|
|
});
|
|
}
|
|
|
|
export default {
|
|
name: "discourse-ai-bot-replies",
|
|
|
|
initialize(container) {
|
|
const settings = container.lookup("service:site-settings");
|
|
const user = container.lookup("service:current-user");
|
|
const aiBotEnaled =
|
|
settings.discourse_ai_enabled && settings.ai_bot_enabled;
|
|
|
|
const aiBotsAllowedGroups = settings.ai_bot_allowed_groups
|
|
.split("|")
|
|
.map(parseInt);
|
|
const canInteractWithAIBots = user?.groups.some((g) =>
|
|
aiBotsAllowedGroups.includes(g.id)
|
|
);
|
|
|
|
if (aiBotEnaled && canInteractWithAIBots) {
|
|
withPluginApi("1.6.0", attachHeaderIcon);
|
|
withPluginApi("1.6.0", initializeAIBotReplies);
|
|
}
|
|
},
|
|
};
|