mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-12 10:00:36 +01:00
Merge pull request #2191 from bdashore3/example-wi
mesExamples anchor for World Info
This commit is contained in:
commit
10fda0b220
@ -5057,13 +5057,19 @@
|
|||||||
<div class="WIEnteryHeaderControls flex-container">
|
<div class="WIEnteryHeaderControls flex-container">
|
||||||
<div name="PositionBlock" class="world_entry_form_control world_entry_form_radios wi-enter-footer-text">
|
<div name="PositionBlock" class="world_entry_form_control world_entry_form_radios wi-enter-footer-text">
|
||||||
<label for="position" class="WIEntryHeaderTitleMobile" data-i18n="Position:">Position:</label>
|
<label for="position" class="WIEntryHeaderTitleMobile" data-i18n="Position:">Position:</label>
|
||||||
<select name="position" class="text_pole widthNatural margin0" data-i18n="[title]T_Position" title="↑Char: Before Character Definitions ↓Char: After Character Definitions ↑AN: Before Author's Note ↓AN: After Author's Note @D ⚙️: at Depth (System) @D 👤: at Depth (User) @D 🤖: at Depth (Assistant)">
|
<select name="position" class="text_pole widthNatural margin0" data-i18n="[title]T_Position" title="↑Char: Before Character Definitions ↓Char: After Character Definitions ↑EM: Before Example Messages ↓EM: After Example Messages ↑AN: Before Author's Note ↓AN: After Author's Note @D ⚙️: at Depth (System) @D 👤: at Depth (User) @D 🤖: at Depth (Assistant)">
|
||||||
<option value="0" data-role="" data-i18n="Before Char Defs">
|
<option value="0" data-role="" data-i18n="Before Char Defs">
|
||||||
↑Char
|
↑Char
|
||||||
</option>
|
</option>
|
||||||
<option value="1" data-role="" data-i18n="After Char Defs">
|
<option value="1" data-role="" data-i18n="After Char Defs">
|
||||||
↓Char
|
↓Char
|
||||||
</option>
|
</option>
|
||||||
|
<option value="5" data-role="" data-i18n="Before EM">
|
||||||
|
↑EM
|
||||||
|
</option>
|
||||||
|
<option value="6" data-role="" data-i18n="After EM">
|
||||||
|
↓EM
|
||||||
|
</option>
|
||||||
<option value="2" data-role="" data-i18n="Before AN">
|
<option value="2" data-role="" data-i18n="Before AN">
|
||||||
↑AN
|
↑AN
|
||||||
</option>
|
</option>
|
||||||
|
@ -34,6 +34,7 @@ import {
|
|||||||
checkEmbeddedWorld,
|
checkEmbeddedWorld,
|
||||||
setWorldInfoButtonClass,
|
setWorldInfoButtonClass,
|
||||||
importWorldInfo,
|
importWorldInfo,
|
||||||
|
wi_anchor_position,
|
||||||
} from './scripts/world-info.js';
|
} from './scripts/world-info.js';
|
||||||
|
|
||||||
import {
|
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);
|
setExtensionPrompt('DEPTH_PROMPT', depthPromptText, extension_prompt_types.IN_CHAT, depthPromptDepth, extension_settings.note.allowWIScan, depthPromptRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse example messages
|
|
||||||
if (!mesExamples.startsWith('<START>')) {
|
|
||||||
mesExamples = '<START>\n' + mesExamples.trim();
|
|
||||||
}
|
|
||||||
if (mesExamples.replace(/<START>/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' ? '<START>\n' : (exampleSeparator || (isInstruct ? '<START>\n' : ''));
|
|
||||||
return examplesStr.split(/<START>/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
|
// First message in fresh 1-on-1 chat reacts to user/character settings changes
|
||||||
if (chat.length) {
|
if (chat.length) {
|
||||||
chat[0].mes = substituteParams(chat[0].mes);
|
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;
|
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('<START>')) {
|
||||||
|
examplesStr = '<START>\n' + examplesStr.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
const exampleSeparator = power_user.context.example_separator ? `${substituteParams(power_user.context.example_separator)}\n` : '';
|
||||||
|
const blockHeading = main_api === 'openai' ? '<START>\n' : (exampleSeparator || (isInstruct ? '<START>\n' : ''));
|
||||||
|
const splitExamples = examplesStr.split(/<START>/gi).slice(1).map(block => `${blockHeading}${block.trim()}\n`);
|
||||||
|
|
||||||
|
return splitExamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mesExamplesArray = parseMesExamples(mesExamples);
|
||||||
|
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
// Extension added strings
|
// Extension added strings
|
||||||
// Set non-WI AN
|
// 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
|
// Make quiet prompt available for WIAN
|
||||||
setExtensionPrompt('QUIET_PROMPT', quiet_prompt || '', extension_prompt_types.IN_PROMPT, 0, true);
|
setExtensionPrompt('QUIET_PROMPT', quiet_prompt || '', extension_prompt_types.IN_PROMPT, 0, true);
|
||||||
const chatForWI = coreChat.map(x => `${x.name}: ${x.mes}`).reverse();
|
const chatForWI = coreChat.map(x => `${x.name}: ${x.mes}`).reverse();
|
||||||
let { worldInfoString, worldInfoBefore, worldInfoAfter, worldInfoDepth } = await getWorldInfoPrompt(chatForWI, this_max_context, dryRun);
|
const { worldInfoString, worldInfoBefore, worldInfoAfter, worldInfoExamples, worldInfoDepth } = await getWorldInfoPrompt(chatForWI, this_max_context, dryRun);
|
||||||
setExtensionPrompt('QUIET_PROMPT', '', extension_prompt_types.IN_PROMPT, 0, true);
|
setExtensionPrompt('QUIET_PROMPT', '', extension_prompt_types.IN_PROMPT, 0, true);
|
||||||
|
|
||||||
|
// Add message example WI
|
||||||
|
for (const example of worldInfoExamples) {
|
||||||
|
const exampleMessage = example.content;
|
||||||
|
|
||||||
|
if (exampleMessage.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const 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) {
|
if (skipWIAN !== true) {
|
||||||
console.log('skipWIAN not active, adding WIAN');
|
console.log('skipWIAN not active, adding WIAN');
|
||||||
// Add all depth WI entries to prompt
|
// Add all depth WI entries to prompt
|
||||||
|
@ -333,6 +333,13 @@ const world_info_position = {
|
|||||||
ANTop: 2,
|
ANTop: 2,
|
||||||
ANBottom: 3,
|
ANBottom: 3,
|
||||||
atDepth: 4,
|
atDepth: 4,
|
||||||
|
EMTop: 5,
|
||||||
|
EMBottom: 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const wi_anchor_position = {
|
||||||
|
before: 0,
|
||||||
|
after: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const worldInfoCache = {};
|
const worldInfoCache = {};
|
||||||
@ -342,7 +349,7 @@ const worldInfoCache = {};
|
|||||||
* @param {string[]} chat The chat messages to scan.
|
* @param {string[]} chat The chat messages to scan.
|
||||||
* @param {number} maxContext The maximum context size of the generation.
|
* @param {number} maxContext The maximum context size of the generation.
|
||||||
* @param {boolean} isDryRun If true, the function will not emit any events.
|
* @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<WIPromptResult>} The world info string and depth.
|
* @returns {Promise<WIPromptResult>} The world info string and depth.
|
||||||
*/
|
*/
|
||||||
async function getWorldInfoPrompt(chat, maxContext, isDryRun) {
|
async function getWorldInfoPrompt(chat, maxContext, isDryRun) {
|
||||||
@ -362,7 +369,8 @@ async function getWorldInfoPrompt(chat, maxContext, isDryRun) {
|
|||||||
worldInfoString,
|
worldInfoString,
|
||||||
worldInfoBefore,
|
worldInfoBefore,
|
||||||
worldInfoAfter,
|
worldInfoAfter,
|
||||||
worldInfoDepth: activatedWorldInfo.WIDepthEntries,
|
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.
|
* Performs a scan on the chat and returns the world info activated.
|
||||||
* @param {string[]} chat The chat messages to scan.
|
* @param {string[]} chat The chat messages to scan.
|
||||||
* @param {number} maxContext The maximum context size of the generation.
|
* @param {number} maxContext The maximum context size of the generation.
|
||||||
* @typedef {{ worldInfoBefore: string, worldInfoAfter: string, WIDepthEntries: any[], allActivatedEntries: Set<any> }} WIActivated
|
* @typedef {{ worldInfoBefore: string, worldInfoAfter: string, EMEntries: any[], WIDepthEntries: any[], allActivatedEntries: Set<any> }} WIActivated
|
||||||
* @returns {Promise<WIActivated>} The world info activated.
|
* @returns {Promise<WIActivated>} The world info activated.
|
||||||
*/
|
*/
|
||||||
async function checkWorldInfo(chat, maxContext) {
|
async function checkWorldInfo(chat, maxContext) {
|
||||||
@ -2315,7 +2323,7 @@ async function checkWorldInfo(chat, maxContext) {
|
|||||||
const sortedEntries = await getSortedEntries();
|
const sortedEntries = await getSortedEntries();
|
||||||
|
|
||||||
if (sortedEntries.length === 0) {
|
if (sortedEntries.length === 0) {
|
||||||
return { worldInfoBefore: '', worldInfoAfter: '', WIDepthEntries: [], allActivatedEntries: new Set() };
|
return { worldInfoBefore: '', worldInfoAfter: '', WIDepthEntries: [], EMEntries: [], allActivatedEntries: new Set() };
|
||||||
}
|
}
|
||||||
|
|
||||||
while (needsToScan) {
|
while (needsToScan) {
|
||||||
@ -2514,11 +2522,13 @@ async function checkWorldInfo(chat, maxContext) {
|
|||||||
// Forward-sorted list of entries for joining
|
// Forward-sorted list of entries for joining
|
||||||
const WIBeforeEntries = [];
|
const WIBeforeEntries = [];
|
||||||
const WIAfterEntries = [];
|
const WIAfterEntries = [];
|
||||||
|
const EMEntries = [];
|
||||||
const ANTopEntries = [];
|
const ANTopEntries = [];
|
||||||
const ANBottomEntries = [];
|
const ANBottomEntries = [];
|
||||||
const WIDepthEntries = [];
|
const WIDepthEntries = [];
|
||||||
|
|
||||||
// Appends from insertion order 999 to 1. Use unshift for this purpose
|
// 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) => {
|
[...allActivatedEntries].sort(sortFn).forEach((entry) => {
|
||||||
switch (entry.position) {
|
switch (entry.position) {
|
||||||
case world_info_position.before:
|
case world_info_position.before:
|
||||||
@ -2527,6 +2537,16 @@ async function checkWorldInfo(chat, maxContext) {
|
|||||||
case world_info_position.after:
|
case world_info_position.after:
|
||||||
WIAfterEntries.unshift(substituteParams(entry.content));
|
WIAfterEntries.unshift(substituteParams(entry.content));
|
||||||
break;
|
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:
|
case world_info_position.ANTop:
|
||||||
ANTopEntries.unshift(entry.content);
|
ANTopEntries.unshift(entry.content);
|
||||||
break;
|
break;
|
||||||
@ -2562,7 +2582,7 @@ async function checkWorldInfo(chat, maxContext) {
|
|||||||
|
|
||||||
buffer.cleanExternalActivations();
|
buffer.cleanExternalActivations();
|
||||||
|
|
||||||
return { worldInfoBefore, worldInfoAfter, WIDepthEntries, allActivatedEntries };
|
return { worldInfoBefore, worldInfoAfter, EMEntries, WIDepthEntries, allActivatedEntries };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3135,6 +3155,10 @@ jQuery(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('#world_import_file').on('change', async function (e) {
|
$('#world_import_file').on('change', async function (e) {
|
||||||
|
if (!(e.target instanceof HTMLInputElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
|
|
||||||
await importWorldInfo(file);
|
await importWorldInfo(file);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user