From 346d5cfb3a4f681ef854db3542727fc87c19d56a Mon Sep 17 00:00:00 2001 From: kingbri Date: Wed, 14 Jun 2023 01:22:16 -0400 Subject: [PATCH 1/3] Author's Notes: Add per-character author's note Adds the option to override the chat's author's note with one set for each character. This saves the pain of having to copy and paste author's notes for every chat. Signed-off-by: kingbri --- public/scripts/extensions.js | 1 + .../scripts/extensions/expressions/index.js | 4 +- .../extensions/floating-prompt/index.js | 117 +++++++++++++++++- public/scripts/utils.js | 11 ++ 4 files changed, 128 insertions(+), 5 deletions(-) diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js index 290391ce6..bf8be73a6 100644 --- a/public/scripts/extensions.js +++ b/public/scripts/extensions.js @@ -50,6 +50,7 @@ const extension_settings = { memory: {}, note: { default: '', + chara: [], }, caption: {}, expressions: {}, diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index 0dabd431a..c7edfe266 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -2,7 +2,7 @@ import { callPopup, eventSource, event_types, getRequestHeaders, saveSettingsDeb import { dragElement, isMobile } from "../../RossAscends-mods.js"; import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch } from "../../extensions.js"; import { power_user } from "../../power-user.js"; -import { onlyUnique, debounce } from "../../utils.js"; +import { onlyUnique, debounce, getCharaFilename } from "../../utils.js"; export { MODULE_NAME }; const MODULE_NAME = 'expressions'; @@ -437,7 +437,7 @@ function getSpriteFolderName(message) { avatarPath = message.original_avatar || context.characters.find(x => message.force_avatar && message.force_avatar.includes(encodeURIComponent(x.avatar)))?.avatar; } else if (context.characterId) { - avatarPath = context.characters[context.characterId].avatar; + avatarPath = getCharaFilename(); } if (!avatarPath) { diff --git a/public/scripts/extensions/floating-prompt/index.js b/public/scripts/extensions/floating-prompt/index.js index 57b3d3cdb..8f11c0bd5 100644 --- a/public/scripts/extensions/floating-prompt/index.js +++ b/public/scripts/extensions/floating-prompt/index.js @@ -9,6 +9,7 @@ import { import { selected_group } from "../../group-chats.js"; import { ModuleWorkerWrapper, extension_settings, getContext, saveMetadataDebounced } from "../../extensions.js"; import { registerSlashCommand } from "../../slash-commands.js"; +import { getCharaFilename } from "../../utils.js"; export { MODULE_NAME }; const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory @@ -99,6 +100,63 @@ async function onExtensionFloatingPositionInput(e) { saveMetadataDebounced(); } +function onExtensionFloatingCharaPromptInput() { + const tempPrompt = $(this).val(); + const avatarName = getCharaFilename(); + let tempCharaNote = { + name: avatarName, + prompt: tempPrompt + } + + $('#extension_floating_chara_token_counter').text(getTokenCount(tempPrompt)); + + let existingCharaNoteIndex; + let existingCharaNote; + + if (extension_settings.note.chara) { + existingCharaNoteIndex = extension_settings.note.chara.findIndex((e) => e.name === avatarName); + existingCharaNote = extension_settings.note.chara[existingCharaNoteIndex] + } + + if (tempPrompt.length === 0 && + extension_settings.note.chara && + existingCharaNote && + !existingCharaNote.useChara + ) { + extension_settings.note.chara.splice(existingCharaNoteIndex, 1); + } + else if (extension_settings.note.chara && existingCharaNote) { + Object.assign(existingCharaNote, tempCharaNote); + } + else if (avatarName && tempPrompt.length > 0) { + if (!extension_settings.note.chara) { + extension_settings.note.chara = [] + } + Object.assign(tempCharaNote, { useChara: false }) + + extension_settings.note.chara.push(tempCharaNote); + } else { + console.log("Character author's note error: No avatar name key could be found."); + toastr.error("Something went wrong. Could not save character's author's note."); + + // Don't save settings if something went wrong + return; + } + + saveSettingsDebounced(); +} + +function onExtensionFloatingCharaCheckboxChanged() { + const value = !!$(this).prop('checked'); + const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename()); + + if (charaNote) { + charaNote.useChara = value; + + saveSettingsDebounced(); + } +} + function onExtensionFloatingDefaultInput() { extension_settings.note.default = $(this).val(); $('#extension_floating_default_token_counter').text(getTokenCount(extension_settings.note.default)); @@ -114,6 +172,14 @@ function loadSettings() { $('#extension_floating_interval').val(chat_metadata[metadata_keys.interval]); $('#extension_floating_depth').val(chat_metadata[metadata_keys.depth]); $(`input[name="extension_floating_position"][value="${chat_metadata[metadata_keys.position]}"]`).prop('checked', true); + + if (extension_settings.note.chara) { + const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename()); + + $('#extension_floating_chara').val(charaNote ? charaNote.prompt : ''); + $('#extension_use_floating_chara').prop('checked', charaNote ? charaNote.useChara : false); + } + $('#extension_floating_default').val(extension_settings.note.default); } @@ -144,7 +210,17 @@ async function moduleWorker() { ? (lastMessageNumber % chat_metadata[metadata_keys.interval]) : (chat_metadata[metadata_keys.interval] - lastMessageNumber); const shouldAddPrompt = messagesTillInsertion == 0; - const prompt = shouldAddPrompt ? $('#extension_floating_prompt').val() : ''; + + let prompt = shouldAddPrompt ? $('#extension_floating_prompt').val() : ''; + if (shouldAddPrompt && extension_settings.note.chara) { + const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename()); + + // Only replace with the chara note if the user checked the box + if (charaNote && charaNote.useChara) { + prompt = charaNote.prompt; + } + } + context.setExtensionPrompt(MODULE_NAME, prompt, chat_metadata[metadata_keys.position], chat_metadata[metadata_keys.depth]); $('#extension_floating_counter').text(shouldAddPrompt ? '0' : messagesTillInsertion); } @@ -184,9 +260,23 @@ function onANMenuItemClick() { function onChatChanged() { const tokenCounter1 = chat_metadata[metadata_keys.prompt] ? getTokenCount(chat_metadata[metadata_keys.prompt]) : 0; - const tokenCounter2 = extension_settings.note.default ? getTokenCount(extension_settings.note.default) : 0; $('#extension_floating_prompt_token_counter').text(tokenCounter1); - $('#extension_floating_default_token_counter').text(tokenCounter2); + + let tokenCounter2; + if (extension_settings.note.chara) { + const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename()); + + if (charaNote) { + tokenCounter2 = getTokenCount(charaNote.prompt); + } + } + + if (tokenCounter2) { + $('#extension_floating_chara_token_counter').text(tokenCounter2); + } + + const tokenCounter3 = extension_settings.note.default ? getTokenCount(extension_settings.note.default) : 0; + $('#extension_floating_default_token_counter').text(tokenCounter3); } (function () { @@ -235,6 +325,25 @@ function onChatChanged() {
+
+
+ Character Author's Note +
+
+
+ Will be automatically added as the author's note for this character. + + +
Tokens: 0
+ + +
+
+
Default Author's Note @@ -263,6 +372,8 @@ function onChatChanged() { $('#extension_floating_prompt').on('input', onExtensionFloatingPromptInput); $('#extension_floating_interval').on('input', onExtensionFloatingIntervalInput); $('#extension_floating_depth').on('input', onExtensionFloatingDepthInput); + $('#extension_floating_chara').on('input', onExtensionFloatingCharaPromptInput); + $('#extension_use_floating_chara').on('input', onExtensionFloatingCharaCheckboxChanged); $('#extension_floating_default').on('input', onExtensionFloatingDefaultInput); $('input[name="extension_floating_position"]').on('change', onExtensionFloatingPositionInput); $('#ANClose').on('click', function () { diff --git a/public/scripts/utils.js b/public/scripts/utils.js index 9e30a4fec..606ed119e 100644 --- a/public/scripts/utils.js +++ b/public/scripts/utils.js @@ -1,3 +1,5 @@ +import { getContext } from "./extensions.js"; + export function onlyUnique(value, index, array) { return array.indexOf(value) === index; } @@ -420,3 +422,12 @@ export function isDataURL(str) { const regex = /^data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)*;?)?(base64)?,([a-z0-9!$&',()*+;=\-_%.~:@\/?#]+)?$/i; return regex.test(str); } + +export function getCharaFilename() { + const context = getContext(); + const fileName = context.characters[context.characterId].avatar; + + if (fileName) { + return fileName.replace(/\.[^/.]+$/, "") + } +} From 8b8bf645eb5222ca65e7bc6569f3e4069699fd9c Mon Sep 17 00:00:00 2001 From: kingbri Date: Wed, 14 Jun 2023 12:26:02 -0400 Subject: [PATCH 2/3] World Info: Allow disabling recursion on entries Recursive scanning is a very great tool used to create a tree hierarchy of entries. However, some entries should not be included in recursion due to possible conflicts and resulting leakage in chats. Add an individual opt-out toggle to exclude the entry from recursive scanning if the main option is enabled. Signed-off-by: kingbri --- public/index.html | 4 ++++ public/scripts/world-info.js | 20 +++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/public/index.html b/public/index.html index 25695ae41..fa21b42d0 100644 --- a/public/index.html +++ b/public/index.html @@ -2920,6 +2920,10 @@ Disable +
diff --git a/public/scripts/world-info.js b/public/scripts/world-info.js index 2dc0abcbc..b322d14c1 100644 --- a/public/scripts/world-info.js +++ b/public/scripts/world-info.js @@ -332,6 +332,19 @@ function appendWorldEntry(entry) { $(this).siblings("input").click(); }); + const excludeRecursionInput = template.find('input[name="exclude_recursion"]'); + excludeRecursionInput.data("uid", entry.uid); + excludeRecursionInput.on("input", function () { + const uid = $(this).data("uid"); + const value = $(this).prop("checked"); + world_info_data.entries[uid].excludeRecursion = value; + saveWorldInfo(); + }); + excludeRecursionInput.prop("checked", entry.excludeRecursion).trigger("input"); + excludeRecursionInput.siblings(".checkbox_fancy").click(function () { + $(this).siblings("input").click(); + }); + // delete button const deleteButton = template.find("input.delete_entry_button"); deleteButton.data("uid", entry.uid); @@ -366,6 +379,7 @@ function createWorldInfoEntry() { order: 100, position: 0, disable: false, + excludeRecursion: false }; const newUid = getFreeWorldEntryUid(); @@ -505,6 +519,7 @@ function checkWorldInfo(chat) { let worldInfoBefore = ""; let worldInfoAfter = ""; let needsToScan = true; + let count = 0; let allActivatedEntries = new Set(); const sortedEntries = Object.keys(world_info_data.entries) @@ -512,10 +527,13 @@ function checkWorldInfo(chat) { .sort((a, b) => b.order - a.order); while (needsToScan) { + // Track how many times the loop has run + count++; + let activatedNow = new Set(); for (let entry of sortedEntries) { - if (allActivatedEntries.has(entry.uid) || entry.disable == true) { + if (allActivatedEntries.has(entry.uid) || entry.disable == true || (count > 1 && world_info_recursive && entry.excludeRecursion)) { continue; } From 63939fe6601d32241da52b375f4389fe617e0e8b Mon Sep 17 00:00:00 2001 From: kingbri Date: Wed, 14 Jun 2023 23:30:48 -0400 Subject: [PATCH 3/3] Author's Notes: Add debouncing for token updates Whenever a character is typed, add a debounce to not ovewhelm online tokenizers such as OpenAI's. Signed-off-by: kingbri --- public/scripts/extensions/floating-prompt/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/scripts/extensions/floating-prompt/index.js b/public/scripts/extensions/floating-prompt/index.js index 8f11c0bd5..206390d39 100644 --- a/public/scripts/extensions/floating-prompt/index.js +++ b/public/scripts/extensions/floating-prompt/index.js @@ -74,7 +74,7 @@ function setNotePositionCommand(_, text) { async function onExtensionFloatingPromptInput() { chat_metadata[metadata_keys.prompt] = $(this).val(); - $('#extension_floating_prompt_token_counter').text(getTokenCount(chat_metadata[metadata_keys.prompt])); + debounce(() => $('#extension_floating_prompt_token_counter').text(getTokenCount(chat_metadata[metadata_keys.prompt])), 1000); saveMetadataDebounced(); } @@ -108,7 +108,7 @@ function onExtensionFloatingCharaPromptInput() { prompt: tempPrompt } - $('#extension_floating_chara_token_counter').text(getTokenCount(tempPrompt)); + debounce(() => $('#extension_floating_chara_token_counter').text(getTokenCount(tempPrompt)), 1000); let existingCharaNoteIndex; let existingCharaNote; @@ -159,7 +159,7 @@ function onExtensionFloatingCharaCheckboxChanged() { function onExtensionFloatingDefaultInput() { extension_settings.note.default = $(this).val(); - $('#extension_floating_default_token_counter').text(getTokenCount(extension_settings.note.default)); + debounce(() => $('#extension_floating_default_token_counter').text(getTokenCount(extension_settings.note.default)), 1000); saveSettingsDebounced(); }