diff --git a/public/index.html b/public/index.html index 2dcddfc67..70786ed1a 100644 --- a/public/index.html +++ b/public/index.html @@ -2920,6 +2920,10 @@ Disable + 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..206390d39 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 @@ -73,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(); } @@ -99,9 +100,66 @@ async function onExtensionFloatingPositionInput(e) { saveMetadataDebounced(); } +function onExtensionFloatingCharaPromptInput() { + const tempPrompt = $(this).val(); + const avatarName = getCharaFilename(); + let tempCharaNote = { + name: avatarName, + prompt: tempPrompt + } + + debounce(() => $('#extension_floating_chara_token_counter').text(getTokenCount(tempPrompt)), 1000); + + 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)); + debounce(() => $('#extension_floating_default_token_counter').text(getTokenCount(extension_settings.note.default)), 1000); saveSettingsDebounced(); } @@ -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(/\.[^/.]+$/, "") + } +} 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; }