Implement WI matching on global data
| @@ -4143,7 +4143,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4143 | // Make quiet prompt available for WIAN | 4143 | // Make quiet prompt available for WIAN |
| 4144 | setExtensionPrompt('QUIET_PROMPT', quiet_prompt || '', extension_prompt_types.IN_PROMPT, 0, true); | 4144 | setExtensionPrompt('QUIET_PROMPT', quiet_prompt || '', extension_prompt_types.IN_PROMPT, 0, true); |
| 4145 | const chatForWI = coreChat.map(x => world_info_include_names ? `${x.name}: ${x.mes}` : x.mes).reverse(); | 4145 | const chatForWI = coreChat.map(x => world_info_include_names ? `${x.name}: ${x.mes}` : x.mes).reverse(); |
| 4146 | const { worldInfoString, worldInfoBefore, worldInfoAfter, worldInfoExamples, worldInfoDepth } = await getWorldInfoPrompt(chatForWI, this_max_context, dryRun); | 4146 | // TODO: Build globalScanData |
| 4147 | const { worldInfoString, worldInfoBefore, worldInfoAfter, worldInfoExamples, worldInfoDepth } = await getWorldInfoPrompt(null, chatForWI, this_max_context, dryRun); | ||
| 4147 | setExtensionPrompt('QUIET_PROMPT', '', extension_prompt_types.IN_PROMPT, 0, true); | 4148 | setExtensionPrompt('QUIET_PROMPT', '', extension_prompt_types.IN_PROMPT, 0, true); |
| 4148 | 4149 | ||
| 4149 | // Add message example WI | 4150 | // Add message example WI |
| @@ -156,6 +156,11 @@ class WorldInfoBuffer { | |||
| 156 | static externalActivations = new Map(); | 156 | static externalActivations = new Map(); |
| 157 | 157 | ||
| 158 | /** | 158 | /** |
| 159 | * @type {WIGlobalScanData} Chat independent data to be scanned, such as persona and character descriptions | ||
| 160 | */ | ||
| 161 | #globalScanDataBuffer = null; | ||
| 162 | |||
| 163 | /** | ||
| 159 | * @type {string[]} Array of messages sorted by ascending depth | 164 | * @type {string[]} Array of messages sorted by ascending depth |
| 160 | */ | 165 | */ |
| 161 | #depthBuffer = []; | 166 | #depthBuffer = []; |
| @@ -182,10 +187,12 @@ class WorldInfoBuffer { | |||
| 182 | 187 | ||
| 183 | /** | 188 | /** |
| 184 | * Initialize the buffer with the given messages. | 189 | * Initialize the buffer with the given messages. |
| 190 | * @param {WIGlobalScanData} globalScanData Chat independent context to be scanned | ||
| 185 | * @param {string[]} messages Array of messages to add to the buffer | 191 | * @param {string[]} messages Array of messages to add to the buffer |
| 186 | */ | 192 | */ |
| 187 | constructor(messages) { | 193 | constructor(globalScanData, messages) { |
| 188 | this.#initDepthBuffer(messages); | 194 | this.#initDepthBuffer(messages); |
| 195 | this.#globalScanDataBuffer = globalScanData; | ||
| 189 | } | 196 | } |
| 190 | 197 | ||
| 191 | /** | 198 | /** |
| @@ -242,6 +249,25 @@ class WorldInfoBuffer { | |||
| 242 | const JOINER = '\n' + MATCHER; | 249 | const JOINER = '\n' + MATCHER; |
| 243 | let result = MATCHER + this.#depthBuffer.slice(this.#startDepth, depth).join(JOINER); | 250 | let result = MATCHER + this.#depthBuffer.slice(this.#startDepth, depth).join(JOINER); |
| 244 | 251 | ||
| 252 | if (entry.matchPersonaDescription) { | ||
| 253 | result += JOINER + this.#globalScanDataBuffer.personaDescription; | ||
| 254 | } | ||
| 255 | if (entry.matchCharacterDescription) { | ||
| 256 | result += JOINER + this.#globalScanDataBuffer.characterDescription; | ||
| 257 | } | ||
| 258 | if (entry.matchCharacterPersonality) { | ||
| 259 | result += JOINER + this.#globalScanDataBuffer.characterPersonality; | ||
| 260 | } | ||
| 261 | if (entry.matchCharacterNote) { | ||
| 262 | result += JOINER + this.#globalScanDataBuffer.characterNote; | ||
| 263 | } | ||
| 264 | if (entry.matchScenario) { | ||
| 265 | result += JOINER + this.#globalScanDataBuffer.scenario; | ||
| 266 | } | ||
| 267 | if (entry.matchCreatorNotes) { | ||
| 268 | result += JOINER + this.#globalScanDataBuffer.creatorNotes; | ||
| 269 | } | ||
| 270 | |||
| 245 | if (this.#injectBuffer.length > 0) { | 271 | if (this.#injectBuffer.length > 0) { |
| 246 | result += JOINER + this.#injectBuffer.join(JOINER); | 272 | result += JOINER + this.#injectBuffer.join(JOINER); |
| 247 | } | 273 | } |
| @@ -770,6 +796,7 @@ export const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOn | |||
| 770 | 796 | ||
| 771 | /** | 797 | /** |
| 772 | * Gets the world info based on chat messages. | 798 | * Gets the world info based on chat messages. |
| 799 | * @param {WIGlobalScanData} globalScanData Chat independent context to be scanned | ||
| 773 | * @param {string[]} chat - The chat messages to scan, in reverse order. | 800 | * @param {string[]} chat - The chat messages to scan, in reverse order. |
| 774 | * @param {number} maxContext - The maximum context size of the generation. | 801 | * @param {number} maxContext - The maximum context size of the generation. |
| 775 | * @param {boolean} isDryRun - If true, the function will not emit any events. | 802 | * @param {boolean} isDryRun - If true, the function will not emit any events. |
| @@ -783,10 +810,10 @@ export const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOn | |||
| 783 | * @property {Array} anAfter - Array of entries after Author's Note | 810 | * @property {Array} anAfter - Array of entries after Author's Note |
| 784 | * @returns {Promise<WIPromptResult>} The world info string and depth. | 811 | * @returns {Promise<WIPromptResult>} The world info string and depth. |
| 785 | */ | 812 | */ |
| 786 | export async function getWorldInfoPrompt(chat, maxContext, isDryRun) { | 813 | export async function getWorldInfoPrompt(globalScanData, chat, maxContext, isDryRun) { |
| 787 | let worldInfoString = '', worldInfoBefore = '', worldInfoAfter = ''; | 814 | let worldInfoString = '', worldInfoBefore = '', worldInfoAfter = ''; |
| 788 | 815 | ||
| 789 | const activatedWorldInfo = await checkWorldInfo(chat, maxContext, isDryRun); | 816 | const activatedWorldInfo = await checkWorldInfo(globalScanData, chat, maxContext, isDryRun); |
| 790 | worldInfoBefore = activatedWorldInfo.worldInfoBefore; | 817 | worldInfoBefore = activatedWorldInfo.worldInfoBefore; |
| 791 | worldInfoAfter = activatedWorldInfo.worldInfoAfter; | 818 | worldInfoAfter = activatedWorldInfo.worldInfoAfter; |
| 792 | worldInfoString = worldInfoBefore + worldInfoAfter; | 819 | worldInfoString = worldInfoBefore + worldInfoAfter; |
| @@ -3333,17 +3360,17 @@ export async function getWorldEntry(name, data, entry) { | |||
| 3333 | 3360 | ||
| 3334 | function handleOptionalSelect(name) { | 3361 | function handleOptionalSelect(name) { |
| 3335 | const key = originalWIDataKeyMap[name]; | 3362 | const key = originalWIDataKeyMap[name]; |
| 3336 | const selectElem = template.find(`select[name="${name}"]`); | 3363 | const checkBoxElem = template.find(`input[type="checkbox"][name="${name}"]`); |
| 3337 | selectElem.data('uid', entry.uid); | 3364 | checkBoxElem.data('uid', entry.uid); |
| 3338 | selectElem.on('input', async function () { | 3365 | checkBoxElem.on('change', async function () { |
| 3339 | const uid = $(this).data('uid'); | 3366 | const uid = $(this).data('uid'); |
| 3340 | const value = $(this).val(); | 3367 | const isChecked = $(this).is(':checked'); |
| 3341 | 3368 | ||
| 3342 | data.entries[uid][name] = value === 'null' ? null : value === 'true'; | 3369 | data.entries[uid][name] = isChecked; |
| 3343 | setWIOriginalDataValue(data, uid, key, data.entries[uid][name]); | 3370 | setWIOriginalDataValue(data, uid, key, data.entries[uid][name]); |
| 3344 | await saveWorldInfo(name, data); | 3371 | await saveWorldInfo(name, data); |
| 3345 | }); | 3372 | }); |
| 3346 | selectElem.val((entry[name] === null || entry[name] === undefined) ? 'null' : entry[name] ? 'true' : 'false').trigger('input'); | 3373 | checkBoxElem.prop('checked', !!entry[name]).trigger('change'); |
| 3347 | } | 3374 | } |
| 3348 | 3375 | ||
| 3349 | handleOptionalSelect("matchPersonaDescription"); | 3376 | handleOptionalSelect("matchPersonaDescription"); |
| @@ -4020,7 +4047,7 @@ function parseDecorators(content) { | |||
| 4020 | 4047 | ||
| 4021 | /** | 4048 | /** |
| 4022 | * Performs a scan on the chat and returns the world info activated. | 4049 | * Performs a scan on the chat and returns the world info activated. |
| 4023 | * @param {string[]} chat The chat messages to scan, in reverse order. | 4050 | * @param {WIGlobalScanData} globalScanData Chat independent context to be scanned |
| 4024 | * @param {number} maxContext The maximum context size of the generation. | 4051 | * @param {number} maxContext The maximum context size of the generation. |
| 4025 | * @param {boolean} isDryRun Whether to perform a dry run. | 4052 | * @param {boolean} isDryRun Whether to perform a dry run. |
| 4026 | * @typedef {object} WIActivated | 4053 | * @typedef {object} WIActivated |
| @@ -4033,9 +4060,9 @@ function parseDecorators(content) { | |||
| 4033 | * @property {Set<any>} allActivatedEntries All entries. | 4060 | * @property {Set<any>} allActivatedEntries All entries. |
| 4034 | * @returns {Promise<WIActivated>} The world info activated. | 4061 | * @returns {Promise<WIActivated>} The world info activated. |
| 4035 | */ | 4062 | */ |
| 4036 | export async function checkWorldInfo(chat, maxContext, isDryRun) { | 4063 | export async function checkWorldInfo(globalScanData, chat, maxContext, isDryRun) { |
| 4037 | const context = getContext(); | 4064 | const context = getContext(); |
| 4038 | const buffer = new WorldInfoBuffer(chat); | 4065 | const buffer = new WorldInfoBuffer(globalScanData, chat); |
| 4039 | 4066 | ||
| 4040 | console.debug(`[WI] --- START WI SCAN (on ${chat.length} messages)${isDryRun ? ' (DRY RUN)' : ''} ---`); | 4067 | console.debug(`[WI] --- START WI SCAN (on ${chat.length} messages)${isDryRun ? ' (DRY RUN)' : ''} ---`); |
| 4041 | 4068 | ||