diff --git a/public/scripts/extensions/hypebot/index.js b/public/scripts/extensions/hypebot/index.js
index 69b08ac5a..11430226b 100644
--- a/public/scripts/extensions/hypebot/index.js
+++ b/public/scripts/extensions/hypebot/index.js
@@ -6,6 +6,7 @@ import { bufferToBase64, debounce } from "../../utils.js";
import { decodeTextTokens, getTextTokens, tokenizers } from "../../tokenizers.js";
const MODULE_NAME = 'hypebot';
+const WAITING_VERBS = ['thinking', 'typing', 'brainstorming', 'cooking', 'conjuring'];
const MAX_PROMPT = 1024;
const MAX_LENGTH = 50;
const MAX_STRING_LENGTH = MAX_PROMPT * 4;
@@ -20,8 +21,7 @@ const settings = {
* @returns {string} Random waiting verb
*/
function getWaitingVerb() {
- const waitingVerbs = ['thinking', 'typing', 'brainstorming', 'cooking', 'conjuring'];
- return waitingVerbs[Math.floor(Math.random() * waitingVerbs.length)];
+ return WAITING_VERBS[Math.floor(Math.random() * WAITING_VERBS.length)];
}
/**
@@ -49,8 +49,7 @@ function getVerb(text) {
* @returns {string} Formatted HTML text
*/
function formatReply(text) {
- const verb = getVerb(text);
- return DOMPurify.sanitize(`${settings.name} ${verb}: ${text}`);
+ return `${settings.name} ${getVerb(text)}: ${text}`;
}
let hypeBotBar;
@@ -58,13 +57,25 @@ let abortController;
const generateDebounced = debounce(() => generateHypeBot(), 500);
+/**
+ * Sets the HypeBot text. Preserves scroll position of the chat.
+ * @param {string} text Text to set
+ */
+function setHypeBotText(text) {
+ const blockA = $('#chat');
+ var originalScrollBottom = blockA[0].scrollHeight - (blockA.scrollTop() + blockA.outerHeight());
+ hypeBotBar.html(DOMPurify.sanitize(text));
+ var newScrollTop = blockA[0].scrollHeight - (blockA.outerHeight() + originalScrollBottom);
+ blockA.scrollTop(newScrollTop);
+}
+
/**
* Called when a chat event occurs to generate a HypeBot reply.
* @param {boolean} clear Clear the hypebot bar.
*/
function onChatEvent(clear) {
if (clear) {
- hypeBotBar.text('');
+ setHypeBotText('');
}
abortController?.abort();
@@ -80,12 +91,12 @@ async function generateHypeBot() {
}
if (!secret_state[SECRET_KEYS.NOVEL]) {
- hypeBotBar.html('No API key found. Please enter your API key in the NovelAI API Settings');
+ setHypeBotText('No API key found. Please enter your API key in the NovelAI API Settings');
return;
}
console.debug('Generating HypeBot reply');
- hypeBotBar.html(DOMPurify.sanitize(`${settings.name} is ${getWaitingVerb()}...`));
+ setHypeBotText(`${settings.name} is ${getWaitingVerb()}...`);
const context = getContext();
const chat = context.chat.slice();
@@ -160,7 +171,7 @@ async function generateHypeBot() {
const ids = Array.from(new Uint16Array(Uint8Array.from(atob(data.output), c => c.charCodeAt(0)).buffer));
const output = decodeTextTokens(tokenizers.GPT2, ids).replace(/�/g, '').trim();
- hypeBotBar.html(formatReply(output));
+ setHypeBotText(formatReply(output));
}
}