From 01aacb9280753503418587d1589ad6c0ca94a446 Mon Sep 17 00:00:00 2001 From: kingbri Date: Tue, 7 May 2024 21:55:26 -0400 Subject: [PATCH] World Info: Add example messages insertion point Allow insertion above and below mesExamples (also known as the "examples of dialogue") box. Signed-off-by: kingbri --- public/index.html | 6 +++ public/script.js | 79 ++++++++++++++++++++++++------------ public/scripts/world-info.js | 26 ++++++++++-- 3 files changed, 81 insertions(+), 30 deletions(-) diff --git a/public/index.html b/public/index.html index 562b2cd9a..b9ece2ade 100644 --- a/public/index.html +++ b/public/index.html @@ -5064,6 +5064,12 @@ + + diff --git a/public/script.js b/public/script.js index 2279889d9..8d253a475 100644 --- a/public/script.js +++ b/public/script.js @@ -34,6 +34,7 @@ import { checkEmbeddedWorld, setWorldInfoButtonClass, importWorldInfo, + wi_anchor_position, } from './scripts/world-info.js'; import { @@ -3223,32 +3224,6 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro setExtensionPrompt('DEPTH_PROMPT', depthPromptText, extension_prompt_types.IN_CHAT, depthPromptDepth, extension_settings.note.allowWIScan, depthPromptRole); } - // Parse example messages - if (!mesExamples.startsWith('')) { - mesExamples = '\n' + mesExamples.trim(); - } - if (mesExamples.replace(//gi, '').trim().length === 0) { - mesExamples = ''; - } - const mesExamplesRaw = mesExamples; - /** - * Adds a block heading to the examples string. - * @param {string} examplesStr - * @returns {string[]} Examples array with block heading - */ - function addBlockHeading(examplesStr) { - const exampleSeparator = power_user.context.example_separator ? `${substituteParams(power_user.context.example_separator)}\n` : ''; - const blockHeading = main_api === 'openai' ? '\n' : (exampleSeparator || (isInstruct ? '\n' : '')); - return examplesStr.split(//gi).slice(1).map(block => `${blockHeading}${block.trim()}\n`); - } - - let mesExamplesArray = addBlockHeading(mesExamples); - let mesExamplesRawArray = addBlockHeading(mesExamplesRaw); - - if (mesExamplesArray && isInstruct) { - mesExamplesArray = formatInstructModeExamples(mesExamplesArray, name1, name2); - } - // First message in fresh 1-on-1 chat reacts to user/character settings changes if (chat.length) { chat[0].mes = substituteParams(chat[0].mes); @@ -3317,6 +3292,30 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro force_name2 = false; } + // TODO (kingbri): Migrate to a utility function + /** + * Parses an examples string. + * @param {string} examplesStr + * @returns {string[]} Examples array with block heading + */ + function parseMesExamples(examplesStr) { + if (examplesStr.length === 0) { + return []; + } + + if (!examplesStr.startsWith('')) { + examplesStr = '\n' + examplesStr.trim(); + } + + const exampleSeparator = power_user.context.example_separator ? `${substituteParams(power_user.context.example_separator)}\n` : ''; + const blockHeading = main_api === 'openai' ? '\n' : (exampleSeparator || (isInstruct ? '\n' : '')); + const splitExamples = examplesStr.split(//gi).slice(1).map(block => `${blockHeading}${block.trim()}\n`); + + return splitExamples; + } + + let mesExamplesArray = parseMesExamples(mesExamples); + ////////////////////////////////// // Extension added strings // Set non-WI AN @@ -3326,9 +3325,35 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro // Make quiet prompt available for WIAN setExtensionPrompt('QUIET_PROMPT', quiet_prompt || '', extension_prompt_types.IN_PROMPT, 0, true); const chatForWI = coreChat.map(x => `${x.name}: ${x.mes}`).reverse(); - let { worldInfoString, worldInfoBefore, worldInfoAfter, worldInfoDepth } = await getWorldInfoPrompt(chatForWI, this_max_context, dryRun); + let { worldInfoString, worldInfoBefore, worldInfoAfter, worldInfoExamples, worldInfoDepth } = await getWorldInfoPrompt(chatForWI, this_max_context, dryRun); setExtensionPrompt('QUIET_PROMPT', '', extension_prompt_types.IN_PROMPT, 0, true); + // Add message example WI + for (const example of worldInfoExamples) { + let exampleMessage = example.content; + + if (exampleMessage.length === 0) { + continue; + } + + let formattedExample = baseChatReplace(exampleMessage, name1, name2) + const cleanedExample = parseMesExamples(formattedExample); + + // Insert depending on before or after position + if (example.position === wi_anchor_position.before) { + mesExamplesArray.unshift(...cleanedExample); + } else { + mesExamplesArray.push(...cleanedExample); + } + } + + // At this point, the raw message examples can be created + const mesExamplesRawArray = [...mesExamplesArray] + + if (mesExamplesArray && isInstruct) { + mesExamplesArray = formatInstructModeExamples(mesExamplesArray, name1, name2); + } + if (skipWIAN !== true) { console.log('skipWIAN not active, adding WIAN'); // Add all depth WI entries to prompt diff --git a/public/scripts/world-info.js b/public/scripts/world-info.js index 18702235d..b301de2fa 100644 --- a/public/scripts/world-info.js +++ b/public/scripts/world-info.js @@ -333,8 +333,15 @@ const world_info_position = { ANTop: 2, ANBottom: 3, atDepth: 4, + EMTop: 5, + EMBottom: 6, }; +export const wi_anchor_position = { + before: 0, + after: 1, +} + const worldInfoCache = {}; /** @@ -342,7 +349,7 @@ const worldInfoCache = {}; * @param {string[]} chat The chat messages to scan. * @param {number} maxContext The maximum context size of the generation. * @param {boolean} isDryRun If true, the function will not emit any events. - * @typedef {{worldInfoString: string, worldInfoBefore: string, worldInfoAfter: string, worldInfoDepth: any[]}} WIPromptResult + * @typedef {{worldInfoString: string, worldInfoBefore: string, worldInfoAfter: string, worldInfoExamples: any[], worldInfoDepth: any[]}} WIPromptResult * @returns {Promise} The world info string and depth. */ async function getWorldInfoPrompt(chat, maxContext, isDryRun) { @@ -362,6 +369,7 @@ async function getWorldInfoPrompt(chat, maxContext, isDryRun) { worldInfoString, worldInfoBefore, worldInfoAfter, + worldInfoExamples: activatedWorldInfo.EMEntries, worldInfoDepth: activatedWorldInfo.WIDepthEntries, }; } @@ -2277,7 +2285,7 @@ export async function getSortedEntries() { * Performs a scan on the chat and returns the world info activated. * @param {string[]} chat The chat messages to scan. * @param {number} maxContext The maximum context size of the generation. - * @typedef {{ worldInfoBefore: string, worldInfoAfter: string, WIDepthEntries: any[], allActivatedEntries: Set }} WIActivated + * @typedef {{ worldInfoBefore: string, worldInfoAfter: string, EMEntries: any[], WIDepthEntries: any[], allActivatedEntries: Set }} WIActivated * @returns {Promise} The world info activated. */ async function checkWorldInfo(chat, maxContext) { @@ -2514,11 +2522,13 @@ async function checkWorldInfo(chat, maxContext) { // Forward-sorted list of entries for joining const WIBeforeEntries = []; const WIAfterEntries = []; + const EMEntries = []; const ANTopEntries = []; const ANBottomEntries = []; const WIDepthEntries = []; // Appends from insertion order 999 to 1. Use unshift for this purpose + // TODO (kingbri): Change to use WI Anchor positioning instead of separate top/bottom arrays [...allActivatedEntries].sort(sortFn).forEach((entry) => { switch (entry.position) { case world_info_position.before: @@ -2527,6 +2537,16 @@ async function checkWorldInfo(chat, maxContext) { case world_info_position.after: WIAfterEntries.unshift(substituteParams(entry.content)); break; + case world_info_position.EMTop: + EMEntries.unshift( + {position: wi_anchor_position.before, content: entry.content} + ); + break; + case world_info_position.EMBottom: + EMEntries.unshift( + {position: wi_anchor_position.after, content: entry.content} + ); + break; case world_info_position.ANTop: ANTopEntries.unshift(entry.content); break; @@ -2562,7 +2582,7 @@ async function checkWorldInfo(chat, maxContext) { buffer.cleanExternalActivations(); - return { worldInfoBefore, worldInfoAfter, WIDepthEntries, allActivatedEntries }; + return { worldInfoBefore, worldInfoAfter, EMEntries, WIDepthEntries, allActivatedEntries }; } /**