Export and doc most of wi functions
This commit is contained in:
parent
8cbdf6bb81
commit
3897b8c082
|
@ -18,33 +18,13 @@ import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
|
|||
import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js';
|
||||
import { StructuredCloneMap } from './util/StructuredCloneMap.js';
|
||||
|
||||
export {
|
||||
world_info,
|
||||
world_info_budget,
|
||||
world_info_depth,
|
||||
world_info_min_activations,
|
||||
world_info_min_activations_depth_max,
|
||||
world_info_include_names,
|
||||
world_info_recursive,
|
||||
world_info_overflow_alert,
|
||||
world_info_case_sensitive,
|
||||
world_info_match_whole_words,
|
||||
world_info_character_strategy,
|
||||
world_info_budget_cap,
|
||||
world_names,
|
||||
checkWorldInfo,
|
||||
deleteWorldInfo,
|
||||
setWorldInfoSettings,
|
||||
getWorldInfoPrompt,
|
||||
};
|
||||
|
||||
const world_info_insertion_strategy = {
|
||||
export const world_info_insertion_strategy = {
|
||||
evenly: 0,
|
||||
character_first: 1,
|
||||
global_first: 2,
|
||||
};
|
||||
|
||||
const world_info_logic = {
|
||||
export const world_info_logic = {
|
||||
AND_ANY: 0,
|
||||
NOT_ALL: 1,
|
||||
NOT_ANY: 2,
|
||||
|
@ -54,7 +34,7 @@ const world_info_logic = {
|
|||
/**
|
||||
* @enum {number} Possible states of the WI evaluation
|
||||
*/
|
||||
const scan_state = {
|
||||
export const scan_state = {
|
||||
/**
|
||||
* The scan will be stopped.
|
||||
*/
|
||||
|
@ -75,23 +55,23 @@ const scan_state = {
|
|||
|
||||
const WI_ENTRY_EDIT_TEMPLATE = $('#entry_edit_template .world_entry');
|
||||
|
||||
let world_info = {};
|
||||
let selected_world_info = [];
|
||||
export let world_info = {};
|
||||
export let selected_world_info = [];
|
||||
/** @type {string[]} */
|
||||
let world_names;
|
||||
let world_info_depth = 2;
|
||||
let world_info_min_activations = 0; // if > 0, will continue seeking chat until minimum world infos are activated
|
||||
let world_info_min_activations_depth_max = 0; // used when (world_info_min_activations > 0)
|
||||
export let world_names;
|
||||
export let world_info_depth = 2;
|
||||
export let world_info_min_activations = 0; // if > 0, will continue seeking chat until minimum world infos are activated
|
||||
export let world_info_min_activations_depth_max = 0; // used when (world_info_min_activations > 0)
|
||||
|
||||
let world_info_budget = 25;
|
||||
let world_info_include_names = true;
|
||||
let world_info_recursive = false;
|
||||
let world_info_overflow_alert = false;
|
||||
let world_info_case_sensitive = false;
|
||||
let world_info_match_whole_words = false;
|
||||
let world_info_use_group_scoring = false;
|
||||
let world_info_character_strategy = world_info_insertion_strategy.character_first;
|
||||
let world_info_budget_cap = 0;
|
||||
export let world_info_budget = 25;
|
||||
export let world_info_include_names = true;
|
||||
export let world_info_recursive = false;
|
||||
export let world_info_overflow_alert = false;
|
||||
export let world_info_case_sensitive = false;
|
||||
export let world_info_match_whole_words = false;
|
||||
export let world_info_use_group_scoring = false;
|
||||
export let world_info_character_strategy = world_info_insertion_strategy.character_first;
|
||||
export let world_info_budget_cap = 0;
|
||||
const saveWorldDebounced = debounce(async (name, data) => await _save(name, data), debounce_timeout.relaxed);
|
||||
const saveSettingsDebounced = debounce(() => {
|
||||
Object.assign(world_info, { globalSelect: selected_world_info });
|
||||
|
@ -101,13 +81,13 @@ const sortFn = (a, b) => b.order - a.order;
|
|||
let updateEditor = (navigation, flashOnNav = true) => { console.debug('Triggered WI navigation', navigation, flashOnNav); };
|
||||
|
||||
// Do not optimize. updateEditor is a function that is updated by the displayWorldEntries with new data.
|
||||
const worldInfoFilter = new FilterHelper(() => updateEditor());
|
||||
const SORT_ORDER_KEY = 'world_info_sort_order';
|
||||
const METADATA_KEY = 'world_info';
|
||||
export const worldInfoFilter = new FilterHelper(() => updateEditor());
|
||||
export const SORT_ORDER_KEY = 'world_info_sort_order';
|
||||
export const METADATA_KEY = 'world_info';
|
||||
|
||||
const DEFAULT_DEPTH = 4;
|
||||
const DEFAULT_WEIGHT = 100;
|
||||
const MAX_SCAN_DEPTH = 1000;
|
||||
export const DEFAULT_DEPTH = 4;
|
||||
export const DEFAULT_WEIGHT = 100;
|
||||
export const MAX_SCAN_DEPTH = 1000;
|
||||
const KNOWN_DECORATORS = ['@@activate', '@@dont_activate'];
|
||||
|
||||
// Typedef area
|
||||
|
@ -732,7 +712,7 @@ export function getWorldInfoSettings() {
|
|||
};
|
||||
}
|
||||
|
||||
const world_info_position = {
|
||||
export const world_info_position = {
|
||||
before: 0,
|
||||
after: 1,
|
||||
ANTop: 2,
|
||||
|
@ -747,8 +727,18 @@ export const wi_anchor_position = {
|
|||
after: 1,
|
||||
};
|
||||
|
||||
/** @type {StructuredCloneMap<string,object>} */
|
||||
const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOnSet: false });
|
||||
/**
|
||||
* The cache of all world info data that was loaded from the backend.
|
||||
*
|
||||
* Calling `loadWorldInfo` will fill this cache and utilize this cache, so should be the preferred way to load any world info data.
|
||||
* Only use the cache directly if you need synchronous access.
|
||||
*
|
||||
* This will return a deep clone of the data, so no way to modify the data without actually saving it.
|
||||
* Should generally be only used for readonly access.
|
||||
*
|
||||
* @type {StructuredCloneMap<string,object>}
|
||||
* */
|
||||
export const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOnSet: false });
|
||||
|
||||
/**
|
||||
* Gets the world info based on chat messages.
|
||||
|
@ -758,7 +748,7 @@ const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOnSet: fa
|
|||
* @typedef {{worldInfoString: string, worldInfoBefore: string, worldInfoAfter: string, worldInfoExamples: any[], worldInfoDepth: any[]}} WIPromptResult
|
||||
* @returns {Promise<WIPromptResult>} The world info string and depth.
|
||||
*/
|
||||
async function getWorldInfoPrompt(chat, maxContext, isDryRun) {
|
||||
export async function getWorldInfoPrompt(chat, maxContext, isDryRun) {
|
||||
let worldInfoString = '', worldInfoBefore = '', worldInfoAfter = '';
|
||||
|
||||
const activatedWorldInfo = await checkWorldInfo(chat, maxContext, isDryRun);
|
||||
|
@ -780,7 +770,7 @@ async function getWorldInfoPrompt(chat, maxContext, isDryRun) {
|
|||
};
|
||||
}
|
||||
|
||||
function setWorldInfoSettings(settings, data) {
|
||||
export function setWorldInfoSettings(settings, data) {
|
||||
if (settings.world_info_depth !== undefined)
|
||||
world_info_depth = Number(settings.world_info_depth);
|
||||
if (settings.world_info_min_activations !== undefined)
|
||||
|
@ -916,7 +906,7 @@ function registerWorldInfoSlashCommands() {
|
|||
return '';
|
||||
}
|
||||
|
||||
const data = await loadWorldInfoData(file);
|
||||
const data = await loadWorldInfo(file);
|
||||
|
||||
if (!data || !('entries' in data)) {
|
||||
toastr.warning('World Info file has an invalid format');
|
||||
|
@ -965,7 +955,7 @@ function registerWorldInfoSlashCommands() {
|
|||
return '';
|
||||
}
|
||||
|
||||
if (typeof newEntryTemplate[field] === 'boolean') {
|
||||
if (typeof newWorldInfoEntryTemplate[field] === 'boolean') {
|
||||
const isTrue = isTrueBoolean(value);
|
||||
const isFalse = isFalseBoolean(value);
|
||||
|
||||
|
@ -1016,7 +1006,7 @@ function registerWorldInfoSlashCommands() {
|
|||
return '';
|
||||
}
|
||||
|
||||
if (newEntryTemplate[field] === undefined) {
|
||||
if (newWorldInfoEntryTemplate[field] === undefined) {
|
||||
toastr.warning('Valid field name is required');
|
||||
return '';
|
||||
}
|
||||
|
@ -1038,7 +1028,7 @@ function registerWorldInfoSlashCommands() {
|
|||
const file = args.file;
|
||||
const key = args.key;
|
||||
|
||||
const data = await loadWorldInfoData(file);
|
||||
const data = await loadWorldInfo(file);
|
||||
|
||||
if (!data || !('entries' in data)) {
|
||||
toastr.warning('Valid World Info file name is required');
|
||||
|
@ -1075,7 +1065,7 @@ function registerWorldInfoSlashCommands() {
|
|||
|
||||
value = value.replace(/\\([{}|])/g, '$1');
|
||||
|
||||
const data = await loadWorldInfoData(file);
|
||||
const data = await loadWorldInfo(file);
|
||||
|
||||
if (!data || !('entries' in data)) {
|
||||
toastr.warning('Valid World Info file name is required');
|
||||
|
@ -1089,7 +1079,7 @@ function registerWorldInfoSlashCommands() {
|
|||
return '';
|
||||
}
|
||||
|
||||
if (newEntryTemplate[field] === undefined) {
|
||||
if (newWorldInfoEntryTemplate[field] === undefined) {
|
||||
toastr.warning('Valid field name is required');
|
||||
return '';
|
||||
}
|
||||
|
@ -1104,8 +1094,8 @@ function registerWorldInfoSlashCommands() {
|
|||
entry[field] = value;
|
||||
}
|
||||
|
||||
if (originalDataKeyMap[field]) {
|
||||
setOriginalDataValue(data, uid, originalDataKeyMap[field], entry[field]);
|
||||
if (originalWIDataKeyMap[field]) {
|
||||
setWIOriginalDataValue(data, uid, originalWIDataKeyMap[field], entry[field]);
|
||||
}
|
||||
|
||||
await saveWorldInfo(file, data);
|
||||
|
@ -1226,7 +1216,7 @@ function registerWorldInfoSlashCommands() {
|
|||
/** A collection of local enum providers for this context of world info */
|
||||
const localEnumProviders = {
|
||||
/** All possible fields that can be set in a WI entry */
|
||||
wiEntryFields: () => Object.entries(newEntryDefinition).map(([key, value]) =>
|
||||
wiEntryFields: () => Object.entries(newWorldInfoEntryDefinition).map(([key, value]) =>
|
||||
new SlashCommandEnumValue(key, `[${value.type}] default: ${(typeof value.default === 'string' ? `'${value.default}'` : value.default)}`,
|
||||
enumTypes.enum, enumIcons.getDataTypeIcon(value.type))),
|
||||
|
||||
|
@ -1566,18 +1556,32 @@ function registerWorldInfoSlashCommands() {
|
|||
}));
|
||||
}
|
||||
|
||||
// World Info Editor
|
||||
async function showWorldEditor(name) {
|
||||
|
||||
/**
|
||||
* Loads the given world into the World Editor.
|
||||
*
|
||||
* @param {string} name - The name of the world
|
||||
* @return {Promise<void>} A promise that resolves when the world editor is loaded
|
||||
*/
|
||||
export async function showWorldEditor(name) {
|
||||
if (!name) {
|
||||
hideWorldEditor();
|
||||
return;
|
||||
}
|
||||
|
||||
const wiData = await loadWorldInfoData(name);
|
||||
const wiData = await loadWorldInfo(name);
|
||||
displayWorldEntries(name, wiData);
|
||||
}
|
||||
|
||||
async function loadWorldInfoData(name) {
|
||||
/**
|
||||
* Loads world info from the backend.
|
||||
*
|
||||
* This function will return from `worldInfoCache` if it has already been loaded before.
|
||||
*
|
||||
* @param {string} name - The name of the world to load
|
||||
* @return {Promise<Object|null>} A promise that resolves to the loaded world information, or null if the request fails.
|
||||
*/
|
||||
export async function loadWorldInfo(name) {
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
@ -1635,10 +1639,12 @@ function getWIElement(name) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sorts the given data based on the selected sort option
|
||||
*
|
||||
* @param {any[]} data WI entries
|
||||
* @returns {any[]} Sorted data
|
||||
*/
|
||||
function sortEntries(data) {
|
||||
export function sortWorldInfoEntries(data) {
|
||||
const option = $('#world_info_sort_order').find(':selected');
|
||||
const sortField = option.data('field');
|
||||
const sortOrder = option.data('order');
|
||||
|
@ -1801,7 +1807,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
|||
|
||||
// Apply the filter and do the chosen sorting
|
||||
entriesArray = worldInfoFilter.applyFilters(entriesArray);
|
||||
entriesArray = sortEntries(entriesArray);
|
||||
entriesArray = sortWorldInfoEntries(entriesArray);
|
||||
|
||||
// Cache keys
|
||||
const keys = entriesArray.flatMap(entry => [...entry.key, ...entry.keysecondary]);
|
||||
|
@ -1919,7 +1925,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
|||
for (const entry of Object.values(data.entries)) {
|
||||
if (!entry.comment && Array.isArray(entry.key) && entry.key.length > 0) {
|
||||
entry.comment = entry.key[0];
|
||||
setOriginalDataValue(data, entry.uid, 'comment', entry.comment);
|
||||
setWIOriginalDataValue(data, entry.uid, 'comment', entry.comment);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
@ -1954,7 +1960,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
|||
|
||||
// We need to sort the entries here, as the data source isn't sorted
|
||||
const entries = Object.values(data.entries);
|
||||
sortEntries(entries);
|
||||
sortWorldInfoEntries(entries);
|
||||
|
||||
let updated = 0, current = start;
|
||||
for (const entry of entries) {
|
||||
|
@ -1962,7 +1968,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
|||
if (entry.order === newOrder) continue;
|
||||
|
||||
entry.order = newOrder;
|
||||
setOriginalDataValue(data, entry.order, 'order', entry.order);
|
||||
setWIOriginalDataValue(data, entry.order, 'order', entry.order);
|
||||
updated++;
|
||||
}
|
||||
|
||||
|
@ -2025,7 +2031,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
|||
}
|
||||
|
||||
item.displayIndex = minDisplayIndex + index;
|
||||
setOriginalDataValue(data, uid, 'extensions.display_index', item.displayIndex);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.display_index', item.displayIndex);
|
||||
});
|
||||
|
||||
console.table(Object.keys(data.entries).map(uid => data.entries[uid]).map(x => ({ uid: x.uid, key: x.key.join(','), displayIndex: x.displayIndex })));
|
||||
|
@ -2036,7 +2042,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
|||
//$("#world_popup_entries_list").disableSelection();
|
||||
}
|
||||
|
||||
const originalDataKeyMap = {
|
||||
export const originalWIDataKeyMap = {
|
||||
'displayIndex': 'extensions.display_index',
|
||||
'excludeRecursion': 'extensions.exclude_recursion',
|
||||
'preventRecursion': 'extensions.prevent_recursion',
|
||||
|
@ -2087,7 +2093,17 @@ function verifyWorldInfoSearchSortRule() {
|
|||
}
|
||||
}
|
||||
|
||||
function setOriginalDataValue(data, uid, key, value) {
|
||||
/**
|
||||
* Sets the value of a specific key in the original data entry corresponding to the given uid
|
||||
* This needs to be called whenever you update JSON data fields.
|
||||
* Use `originalWIDataKeyMap` to find the correct value to be set.
|
||||
*
|
||||
* @param {object} data - The data object containing the original data entries.
|
||||
* @param {string} uid - The unique identifier of the data entry.
|
||||
* @param {string} key - The key of the value to be set.
|
||||
* @param {any} value - The value to be set.
|
||||
*/
|
||||
export function setWIOriginalDataValue(data, uid, key, value) {
|
||||
if (data.originalData && Array.isArray(data.originalData.entries)) {
|
||||
let originalEntry = data.originalData.entries.find(x => x.uid === uid);
|
||||
|
||||
|
@ -2099,7 +2115,7 @@ function setOriginalDataValue(data, uid, key, value) {
|
|||
}
|
||||
}
|
||||
|
||||
function deleteOriginalDataValue(data, uid) {
|
||||
function deleteWIOriginalDataValue(data, uid) {
|
||||
if (data.originalData && Array.isArray(data.originalData.entries)) {
|
||||
const originalIndex = data.originalData.entries.findIndex(x => x.uid === uid);
|
||||
|
||||
|
@ -2120,7 +2136,7 @@ function deleteOriginalDataValue(data, uid) {
|
|||
* @param {string} input - One or multiple keywords or regexes, separated by commas
|
||||
* @returns {string[]} An array of keywords and regexes
|
||||
*/
|
||||
function splitKeywordsAndRegexes(input) {
|
||||
export function splitKeywordsAndRegexes(input) {
|
||||
/** @type {string[]} */
|
||||
let keywordsAndRegexes = [];
|
||||
|
||||
|
@ -2224,7 +2240,7 @@ function isValidRegex(input) {
|
|||
* @param {string} input - A delimited regex string
|
||||
* @returns {RegExp|null} The regex object, or null if not a valid regex
|
||||
*/
|
||||
function parseRegexFromString(input) {
|
||||
export function parseRegexFromString(input) {
|
||||
// Extracting the regex pattern and flags
|
||||
let match = input.match(/^\/([\w\W]+?)\/([gimsuy]*)$/);
|
||||
if (!match) {
|
||||
|
@ -2310,7 +2326,7 @@ function getWorldEntry(name, data, entry) {
|
|||
!skipReset && resetScrollHeight(this);
|
||||
if (!noSave) {
|
||||
data.entries[uid][entryPropName] = keys;
|
||||
setOriginalDataValue(data, uid, originalDataValueName, data.entries[uid][entryPropName]);
|
||||
setWIOriginalDataValue(data, uid, originalDataValueName, data.entries[uid][entryPropName]);
|
||||
await saveWorldInfo(name, data);
|
||||
}
|
||||
});
|
||||
|
@ -2348,7 +2364,7 @@ function getWorldEntry(name, data, entry) {
|
|||
!skipReset && resetScrollHeight(this);
|
||||
if (!noSave) {
|
||||
data.entries[uid][entryPropName] = splitKeywordsAndRegexes(value);
|
||||
setOriginalDataValue(data, uid, originalDataValueName, data.entries[uid][entryPropName]);
|
||||
setWIOriginalDataValue(data, uid, originalDataValueName, data.entries[uid][entryPropName]);
|
||||
await saveWorldInfo(name, data);
|
||||
}
|
||||
});
|
||||
|
@ -2392,7 +2408,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const uid = $(this).data('uid');
|
||||
const value = Number($(this).val());
|
||||
data.entries[uid].selectiveLogic = !isNaN(value) ? value : world_info_logic.AND_ANY;
|
||||
setOriginalDataValue(data, uid, 'selectiveLogic', data.entries[uid].selectiveLogic);
|
||||
setWIOriginalDataValue(data, uid, 'selectiveLogic', data.entries[uid].selectiveLogic);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
|
||||
|
@ -2441,7 +2457,7 @@ function getWorldEntry(name, data, entry) {
|
|||
}
|
||||
}
|
||||
|
||||
setOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter);
|
||||
setWIOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
characterExclusionInput.prop('checked', entry.characterFilter?.isExclude ?? false).trigger('input');
|
||||
|
@ -2503,7 +2519,7 @@ function getWorldEntry(name, data, entry) {
|
|||
},
|
||||
);
|
||||
}
|
||||
setOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter);
|
||||
setWIOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
|
||||
|
@ -2517,7 +2533,7 @@ function getWorldEntry(name, data, entry) {
|
|||
!skipReset && resetScrollHeight(this);
|
||||
data.entries[uid].comment = value;
|
||||
|
||||
setOriginalDataValue(data, uid, 'comment', data.entries[uid].comment);
|
||||
setWIOriginalDataValue(data, uid, 'comment', data.entries[uid].comment);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
commentToggle.data('uid', entry.uid);
|
||||
|
@ -2552,7 +2568,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const value = $(this).val();
|
||||
data.entries[uid].content = value;
|
||||
|
||||
setOriginalDataValue(data, uid, 'content', data.entries[uid].content);
|
||||
setWIOriginalDataValue(data, uid, 'content', data.entries[uid].content);
|
||||
await saveWorldInfo(name, data);
|
||||
|
||||
if (skipCount) {
|
||||
|
@ -2582,7 +2598,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const value = $(this).prop('checked');
|
||||
data.entries[uid].selective = value;
|
||||
|
||||
setOriginalDataValue(data, uid, 'selective', data.entries[uid].selective);
|
||||
setWIOriginalDataValue(data, uid, 'selective', data.entries[uid].selective);
|
||||
await saveWorldInfo(name, data);
|
||||
|
||||
const keysecondary = $(this)
|
||||
|
@ -2631,7 +2647,7 @@ function getWorldEntry(name, data, entry) {
|
|||
|
||||
data.entries[uid].order = !isNaN(value) ? value : 0;
|
||||
updatePosOrdDisplay(uid);
|
||||
setOriginalDataValue(data, uid, 'insertion_order', data.entries[uid].order);
|
||||
setWIOriginalDataValue(data, uid, 'insertion_order', data.entries[uid].order);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
orderInput.val(entry.order).trigger('input');
|
||||
|
@ -2645,7 +2661,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const value = String($(this).val()).trim();
|
||||
|
||||
data.entries[uid].group = value;
|
||||
setOriginalDataValue(data, uid, 'extensions.group', data.entries[uid].group);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.group', data.entries[uid].group);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
groupInput.val(entry.group ?? '').trigger('input');
|
||||
|
@ -2658,7 +2674,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const uid = $(this).data('uid');
|
||||
const value = $(this).prop('checked');
|
||||
data.entries[uid].groupOverride = value;
|
||||
setOriginalDataValue(data, uid, 'extensions.group_override', data.entries[uid].groupOverride);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.group_override', data.entries[uid].groupOverride);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
groupOverrideInput.prop('checked', entry.groupOverride).trigger('input');
|
||||
|
@ -2682,7 +2698,7 @@ function getWorldEntry(name, data, entry) {
|
|||
}
|
||||
|
||||
data.entries[uid].groupWeight = !isNaN(value) ? Math.abs(value) : 1;
|
||||
setOriginalDataValue(data, uid, 'extensions.group_weight', data.entries[uid].groupWeight);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.group_weight', data.entries[uid].groupWeight);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
groupWeightInput.val(entry.groupWeight ?? DEFAULT_WEIGHT).trigger('input');
|
||||
|
@ -2695,7 +2711,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const value = Number($(this).val());
|
||||
data.entries[uid].sticky = !isNaN(value) ? value : null;
|
||||
|
||||
setOriginalDataValue(data, uid, 'extensions.sticky', data.entries[uid].sticky);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.sticky', data.entries[uid].sticky);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
sticky.val(entry.sticky > 0 ? entry.sticky : '').trigger('input');
|
||||
|
@ -2708,7 +2724,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const value = Number($(this).val());
|
||||
data.entries[uid].cooldown = !isNaN(value) ? value : null;
|
||||
|
||||
setOriginalDataValue(data, uid, 'extensions.cooldown', data.entries[uid].cooldown);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.cooldown', data.entries[uid].cooldown);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
cooldown.val(entry.cooldown > 0 ? entry.cooldown : '').trigger('input');
|
||||
|
@ -2721,7 +2737,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const value = Number($(this).val());
|
||||
data.entries[uid].delay = !isNaN(value) ? value : null;
|
||||
|
||||
setOriginalDataValue(data, uid, 'extensions.delay', data.entries[uid].delay);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.delay', data.entries[uid].delay);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
delay.val(entry.delay > 0 ? entry.delay : '').trigger('input');
|
||||
|
@ -2741,7 +2757,7 @@ function getWorldEntry(name, data, entry) {
|
|||
|
||||
data.entries[uid].depth = !isNaN(value) ? value : 0;
|
||||
updatePosOrdDisplay(uid);
|
||||
setOriginalDataValue(data, uid, 'extensions.depth', data.entries[uid].depth);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.depth', data.entries[uid].depth);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
depthInput.val(entry.depth ?? DEFAULT_DEPTH).trigger('input');
|
||||
|
@ -2769,7 +2785,7 @@ function getWorldEntry(name, data, entry) {
|
|||
}
|
||||
}
|
||||
|
||||
setOriginalDataValue(data, uid, 'extensions.probability', data.entries[uid].probability);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.probability', data.entries[uid].probability);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
probabilityInput.val(entry.probability).trigger('input');
|
||||
|
@ -2836,10 +2852,10 @@ function getWorldEntry(name, data, entry) {
|
|||
}
|
||||
updatePosOrdDisplay(uid);
|
||||
// Spec v2 only supports before_char and after_char
|
||||
setOriginalDataValue(data, uid, 'position', data.entries[uid].position == 0 ? 'before_char' : 'after_char');
|
||||
setWIOriginalDataValue(data, uid, 'position', data.entries[uid].position == 0 ? 'before_char' : 'after_char');
|
||||
// Write the original value as extensions field
|
||||
setOriginalDataValue(data, uid, 'extensions.position', data.entries[uid].position);
|
||||
setOriginalDataValue(data, uid, 'extensions.role', data.entries[uid].role);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.position', data.entries[uid].position);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.role', data.entries[uid].role);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
|
||||
|
@ -2881,36 +2897,36 @@ function getWorldEntry(name, data, entry) {
|
|||
data.entries[uid].constant = true;
|
||||
data.entries[uid].disable = false;
|
||||
data.entries[uid].vectorized = false;
|
||||
setOriginalDataValue(data, uid, 'enabled', true);
|
||||
setOriginalDataValue(data, uid, 'constant', true);
|
||||
setOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
||||
setWIOriginalDataValue(data, uid, 'enabled', true);
|
||||
setWIOriginalDataValue(data, uid, 'constant', true);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
||||
template.removeClass('disabledWIEntry');
|
||||
break;
|
||||
case 'normal':
|
||||
data.entries[uid].constant = false;
|
||||
data.entries[uid].disable = false;
|
||||
data.entries[uid].vectorized = false;
|
||||
setOriginalDataValue(data, uid, 'enabled', true);
|
||||
setOriginalDataValue(data, uid, 'constant', false);
|
||||
setOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
||||
setWIOriginalDataValue(data, uid, 'enabled', true);
|
||||
setWIOriginalDataValue(data, uid, 'constant', false);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
||||
template.removeClass('disabledWIEntry');
|
||||
break;
|
||||
case 'vectorized':
|
||||
data.entries[uid].constant = false;
|
||||
data.entries[uid].disable = false;
|
||||
data.entries[uid].vectorized = true;
|
||||
setOriginalDataValue(data, uid, 'enabled', true);
|
||||
setOriginalDataValue(data, uid, 'constant', false);
|
||||
setOriginalDataValue(data, uid, 'extensions.vectorized', true);
|
||||
setWIOriginalDataValue(data, uid, 'enabled', true);
|
||||
setWIOriginalDataValue(data, uid, 'constant', false);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.vectorized', true);
|
||||
template.removeClass('disabledWIEntry');
|
||||
break;
|
||||
case 'disabled':
|
||||
data.entries[uid].constant = false;
|
||||
data.entries[uid].disable = true;
|
||||
data.entries[uid].vectorized = false;
|
||||
setOriginalDataValue(data, uid, 'enabled', false);
|
||||
setOriginalDataValue(data, uid, 'constant', false);
|
||||
setOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
||||
setWIOriginalDataValue(data, uid, 'enabled', false);
|
||||
setWIOriginalDataValue(data, uid, 'constant', false);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
||||
template.addClass('disabledWIEntry');
|
||||
break;
|
||||
}
|
||||
|
@ -2941,7 +2957,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const uid = $(this).data('uid');
|
||||
const value = $(this).prop('checked');
|
||||
data.entries[uid].excludeRecursion = value;
|
||||
setOriginalDataValue(data, uid, 'extensions.exclude_recursion', data.entries[uid].excludeRecursion);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.exclude_recursion', data.entries[uid].excludeRecursion);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
excludeRecursionInput.prop('checked', entry.excludeRecursion).trigger('input');
|
||||
|
@ -2953,7 +2969,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const uid = $(this).data('uid');
|
||||
const value = $(this).prop('checked');
|
||||
data.entries[uid].preventRecursion = value;
|
||||
setOriginalDataValue(data, uid, 'extensions.prevent_recursion', data.entries[uid].preventRecursion);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.prevent_recursion', data.entries[uid].preventRecursion);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
preventRecursionInput.prop('checked', entry.preventRecursion).trigger('input');
|
||||
|
@ -2965,7 +2981,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const uid = $(this).data('uid');
|
||||
const value = $(this).prop('checked');
|
||||
data.entries[uid].delayUntilRecursion = value;
|
||||
setOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.delay_until_recursion', data.entries[uid].delayUntilRecursion);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
delayUntilRecursionInput.prop('checked', entry.delayUntilRecursion).trigger('input');
|
||||
|
@ -2988,7 +3004,7 @@ function getWorldEntry(name, data, entry) {
|
|||
deleteButton.on('click', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
deleteWorldInfoEntry(data, uid);
|
||||
deleteOriginalDataValue(data, uid);
|
||||
deleteWIOriginalDataValue(data, uid);
|
||||
await saveWorldInfo(name, data);
|
||||
updateEditor(navigation_option.previous);
|
||||
});
|
||||
|
@ -3015,7 +3031,7 @@ function getWorldEntry(name, data, entry) {
|
|||
}
|
||||
|
||||
data.entries[uid].scanDepth = !isEmpty && !isNaN(value) && value >= 0 && value <= MAX_SCAN_DEPTH ? Math.floor(value) : null;
|
||||
setOriginalDataValue(data, uid, 'extensions.scan_depth', data.entries[uid].scanDepth);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.scan_depth', data.entries[uid].scanDepth);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
scanDepthInput.val(entry.scanDepth ?? null).trigger('input');
|
||||
|
@ -3028,7 +3044,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const value = $(this).val();
|
||||
|
||||
data.entries[uid].caseSensitive = value === 'null' ? null : value === 'true';
|
||||
setOriginalDataValue(data, uid, 'extensions.case_sensitive', data.entries[uid].caseSensitive);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.case_sensitive', data.entries[uid].caseSensitive);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
caseSensitiveSelect.val((entry.caseSensitive === null || entry.caseSensitive === undefined) ? 'null' : entry.caseSensitive ? 'true' : 'false').trigger('input');
|
||||
|
@ -3041,7 +3057,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const value = $(this).val();
|
||||
|
||||
data.entries[uid].matchWholeWords = value === 'null' ? null : value === 'true';
|
||||
setOriginalDataValue(data, uid, 'extensions.match_whole_words', data.entries[uid].matchWholeWords);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.match_whole_words', data.entries[uid].matchWholeWords);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
matchWholeWordsSelect.val((entry.matchWholeWords === null || entry.matchWholeWords === undefined) ? 'null' : entry.matchWholeWords ? 'true' : 'false').trigger('input');
|
||||
|
@ -3054,7 +3070,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const value = $(this).val();
|
||||
|
||||
data.entries[uid].useGroupScoring = value === 'null' ? null : value === 'true';
|
||||
setOriginalDataValue(data, uid, 'extensions.use_group_scoring', data.entries[uid].useGroupScoring);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.use_group_scoring', data.entries[uid].useGroupScoring);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
useGroupScoringSelect.val((entry.useGroupScoring === null || entry.useGroupScoring === undefined) ? 'null' : entry.useGroupScoring ? 'true' : 'false').trigger('input');
|
||||
|
@ -3067,7 +3083,7 @@ function getWorldEntry(name, data, entry) {
|
|||
const value = $(this).val();
|
||||
|
||||
data.entries[uid].automationId = value;
|
||||
setOriginalDataValue(data, uid, 'extensions.automation_id', data.entries[uid].automationId);
|
||||
setWIOriginalDataValue(data, uid, 'extensions.automation_id', data.entries[uid].automationId);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
automationIdInput.val(entry.automationId ?? '').trigger('input');
|
||||
|
@ -3200,12 +3216,12 @@ function createEntryInputAutocomplete(input, callback, { allowMultiple = false }
|
|||
|
||||
|
||||
/**
|
||||
* Duplicated a WI entry by copying all of its properties and assigning a new uid
|
||||
* Duplicate a WI entry by copying all of its properties and assigning a new uid
|
||||
* @param {*} data - The data of the book
|
||||
* @param {number} uid - The uid of the entry to copy in this book
|
||||
* @returns {*} The new WI duplicated entry
|
||||
*/
|
||||
function duplicateWorldInfoEntry(data, uid) {
|
||||
export function duplicateWorldInfoEntry(data, uid) {
|
||||
if (!data || !('entries' in data) || !data.entries[uid]) {
|
||||
return;
|
||||
}
|
||||
|
@ -3226,7 +3242,7 @@ function duplicateWorldInfoEntry(data, uid) {
|
|||
* @param {*[]} data - The data of the book
|
||||
* @param {number} uid - The uid of the entry to copy in this book
|
||||
*/
|
||||
function deleteWorldInfoEntry(data, uid) {
|
||||
export function deleteWorldInfoEntry(data, uid) {
|
||||
if (!data || !('entries' in data)) {
|
||||
return;
|
||||
}
|
||||
|
@ -3245,7 +3261,7 @@ function deleteWorldInfoEntry(data, uid) {
|
|||
*
|
||||
* @type {{[key: string]: { default: any, type: string }}}
|
||||
*/
|
||||
const newEntryDefinition = {
|
||||
export const newWorldInfoEntryDefinition = {
|
||||
key: { default: [], type: 'array' },
|
||||
keysecondary: { default: [], type: 'array' },
|
||||
comment: { default: '', type: 'string' },
|
||||
|
@ -3278,8 +3294,8 @@ const newEntryDefinition = {
|
|||
delay: { default: null, type: 'number?' },
|
||||
};
|
||||
|
||||
const newEntryTemplate = Object.fromEntries(
|
||||
Object.entries(newEntryDefinition).map(([key, value]) => [key, value.default]),
|
||||
export const newWorldInfoEntryTemplate = Object.fromEntries(
|
||||
Object.entries(newWorldInfoEntryDefinition).map(([key, value]) => [key, value.default]),
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -3288,7 +3304,7 @@ const newEntryTemplate = Object.fromEntries(
|
|||
* @param {any} data WI data
|
||||
* @returns {object | undefined} New entry object or undefined if failed
|
||||
*/
|
||||
function createWorldInfoEntry(_name, data) {
|
||||
export function createWorldInfoEntry(_name, data) {
|
||||
const newUid = getFreeWorldEntryUid(data);
|
||||
|
||||
if (!Number.isInteger(newUid)) {
|
||||
|
@ -3296,7 +3312,7 @@ function createWorldInfoEntry(_name, data) {
|
|||
return;
|
||||
}
|
||||
|
||||
const newEntry = { uid: newUid, ...structuredClone(newEntryTemplate) };
|
||||
const newEntry = { uid: newUid, ...structuredClone(newWorldInfoEntryTemplate) };
|
||||
data.entries[newUid] = newEntry;
|
||||
|
||||
return newEntry;
|
||||
|
@ -3314,7 +3330,21 @@ async function _save(name, data) {
|
|||
eventSource.emit(event_types.WORLDINFO_UPDATED, name, data);
|
||||
}
|
||||
|
||||
async function saveWorldInfo(name, data, immediately = false) {
|
||||
|
||||
/**
|
||||
* Saves the world info
|
||||
*
|
||||
* This will also refresh the `worldInfoCache`.
|
||||
* Note, for performance reasons the saved cache will not make a deep clone of the data.
|
||||
* It is your responsibility to not modify the saved data object after calling this function, or there will be data inconsistencies.
|
||||
* Call `loadWorldInfoData` or query directly from cache if you need the object again.
|
||||
*
|
||||
* @param {string} name - The name of the world info
|
||||
* @param {any} data - The data to be saved
|
||||
* @param {boolean} [immediately=false] - Whether to save immediately or use debouncing
|
||||
* @return {Promise<void>} A promise that resolves when the world info is saved
|
||||
*/
|
||||
export async function saveWorldInfo(name, data, immediately = false) {
|
||||
if (!name || !data) {
|
||||
return;
|
||||
}
|
||||
|
@ -3371,7 +3401,7 @@ async function renameWorldInfo(name, data) {
|
|||
* @param {string} worldInfoName - The name of the world info to delete
|
||||
* @returns {Promise<boolean>} A promise that resolves to true if the world info was successfully deleted, false otherwise
|
||||
*/
|
||||
async function deleteWorldInfo(worldInfoName) {
|
||||
export async function deleteWorldInfo(worldInfoName) {
|
||||
if (!world_names.includes(worldInfoName)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3406,7 +3436,7 @@ async function deleteWorldInfo(worldInfoName) {
|
|||
return true;
|
||||
}
|
||||
|
||||
function getFreeWorldEntryUid(data) {
|
||||
export function getFreeWorldEntryUid(data) {
|
||||
if (!data || !('entries' in data)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -3422,7 +3452,7 @@ function getFreeWorldEntryUid(data) {
|
|||
return null;
|
||||
}
|
||||
|
||||
function getFreeWorldName() {
|
||||
export function getFreeWorldName() {
|
||||
const MAX_FREE_NAME = 100_000;
|
||||
for (let index = 1; index < MAX_FREE_NAME; index++) {
|
||||
const newName = `New World (${index})`;
|
||||
|
@ -3444,7 +3474,7 @@ function getFreeWorldName() {
|
|||
* @param {boolean} [options.interactive=false] - Whether to show a confirmation dialog when overwriting an existing world
|
||||
* @returns {Promise<boolean>} - True if the world info was successfully created, false otherwise
|
||||
*/
|
||||
async function createNewWorldInfo(worldName, { interactive = false } = {}) {
|
||||
export async function createNewWorldInfo(worldName, { interactive = false } = {}) {
|
||||
const worldInfoTemplate = { entries: {} };
|
||||
|
||||
if (!worldName) {
|
||||
|
@ -3505,7 +3535,7 @@ async function getCharacterLore() {
|
|||
continue;
|
||||
}
|
||||
|
||||
const data = await loadWorldInfoData(worldName);
|
||||
const data = await loadWorldInfo(worldName);
|
||||
const newEntries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: worldName, ...rest })) : [];
|
||||
entries = entries.concat(newEntries);
|
||||
|
||||
|
@ -3525,7 +3555,7 @@ async function getGlobalLore() {
|
|||
|
||||
let entries = [];
|
||||
for (const worldName of selected_world_info) {
|
||||
const data = await loadWorldInfoData(worldName);
|
||||
const data = await loadWorldInfo(worldName);
|
||||
const newEntries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: worldName, ...rest })) : [];
|
||||
entries = entries.concat(newEntries);
|
||||
}
|
||||
|
@ -3547,7 +3577,7 @@ async function getChatLore() {
|
|||
return [];
|
||||
}
|
||||
|
||||
const data = await loadWorldInfoData(chatWorld);
|
||||
const data = await loadWorldInfo(chatWorld);
|
||||
const entries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: chatWorld, ...rest })) : [];
|
||||
|
||||
console.debug(`[WI] Chat lore has ${entries.length} entries`, [chatWorld]);
|
||||
|
@ -3663,7 +3693,7 @@ function parseDecorators(content) {
|
|||
* @typedef {{ worldInfoBefore: string, worldInfoAfter: string, EMEntries: any[], WIDepthEntries: any[], allActivatedEntries: Set<any> }} WIActivated
|
||||
* @returns {Promise<WIActivated>} The world info activated.
|
||||
*/
|
||||
async function checkWorldInfo(chat, maxContext, isDryRun) {
|
||||
export async function checkWorldInfo(chat, maxContext, isDryRun) {
|
||||
const context = getContext();
|
||||
const buffer = new WorldInfoBuffer(chat);
|
||||
|
||||
|
@ -4233,7 +4263,7 @@ function convertAgnaiMemoryBook(inputObj) {
|
|||
|
||||
inputObj.entries.forEach((entry, index) => {
|
||||
outputObj.entries[index] = {
|
||||
...newEntryTemplate,
|
||||
...newWorldInfoEntryTemplate,
|
||||
uid: index,
|
||||
key: entry.keywords,
|
||||
keysecondary: [],
|
||||
|
@ -4275,7 +4305,7 @@ function convertRisuLorebook(inputObj) {
|
|||
|
||||
inputObj.data.forEach((entry, index) => {
|
||||
outputObj.entries[index] = {
|
||||
...newEntryTemplate,
|
||||
...newWorldInfoEntryTemplate,
|
||||
uid: index,
|
||||
key: entry.key.split(',').map(x => x.trim()),
|
||||
keysecondary: entry.secondkey ? entry.secondkey.split(',').map(x => x.trim()) : [],
|
||||
|
@ -4322,7 +4352,7 @@ function convertNovelLorebook(inputObj) {
|
|||
const addMemo = displayName !== undefined && displayName.trim() !== '';
|
||||
|
||||
outputObj.entries[index] = {
|
||||
...newEntryTemplate,
|
||||
...newWorldInfoEntryTemplate,
|
||||
uid: index,
|
||||
key: entry.keys,
|
||||
keysecondary: [],
|
||||
|
@ -4369,7 +4399,7 @@ function convertCharacterBook(characterBook) {
|
|||
}
|
||||
|
||||
result.entries[entry.id] = {
|
||||
...newEntryTemplate,
|
||||
...newWorldInfoEntryTemplate,
|
||||
uid: entry.id,
|
||||
key: entry.keys,
|
||||
keysecondary: entry.secondary_keys || [],
|
||||
|
@ -4499,7 +4529,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) {
|
|||
setWorldInfoButtonClass(chid, true);
|
||||
}
|
||||
|
||||
function onWorldInfoChange(args, text) {
|
||||
export function onWorldInfoChange(args, text) {
|
||||
if (args !== '__notSlashCommand__') { // if it's a slash command
|
||||
const silent = isTrueBoolean(args.silent);
|
||||
if (text.trim() !== '') { // and args are provided
|
||||
|
@ -4650,7 +4680,7 @@ export async function importWorldInfo(file) {
|
|||
});
|
||||
}
|
||||
|
||||
function assignLorebookToChat() {
|
||||
export function assignLorebookToChat() {
|
||||
const selectedName = chat_metadata[METADATA_KEY];
|
||||
const template = $('#chat_world_template .chat_world').clone();
|
||||
|
||||
|
|
Loading…
Reference in New Issue