Merge pull request #2601 from SillyTavern/wi-blackbox-be-gone
WI blackbox begone (Export, document and refactor a bit of the WI API)
This commit is contained in:
commit
d5576cd7b7
|
@ -18,33 +18,13 @@ import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
|
||||||
import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js';
|
import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js';
|
||||||
import { StructuredCloneMap } from './util/StructuredCloneMap.js';
|
import { StructuredCloneMap } from './util/StructuredCloneMap.js';
|
||||||
|
|
||||||
export {
|
export const world_info_insertion_strategy = {
|
||||||
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 = {
|
|
||||||
evenly: 0,
|
evenly: 0,
|
||||||
character_first: 1,
|
character_first: 1,
|
||||||
global_first: 2,
|
global_first: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const world_info_logic = {
|
export const world_info_logic = {
|
||||||
AND_ANY: 0,
|
AND_ANY: 0,
|
||||||
NOT_ALL: 1,
|
NOT_ALL: 1,
|
||||||
NOT_ANY: 2,
|
NOT_ANY: 2,
|
||||||
|
@ -54,7 +34,7 @@ const world_info_logic = {
|
||||||
/**
|
/**
|
||||||
* @enum {number} Possible states of the WI evaluation
|
* @enum {number} Possible states of the WI evaluation
|
||||||
*/
|
*/
|
||||||
const scan_state = {
|
export const scan_state = {
|
||||||
/**
|
/**
|
||||||
* The scan will be stopped.
|
* The scan will be stopped.
|
||||||
*/
|
*/
|
||||||
|
@ -75,23 +55,23 @@ const scan_state = {
|
||||||
|
|
||||||
const WI_ENTRY_EDIT_TEMPLATE = $('#entry_edit_template .world_entry');
|
const WI_ENTRY_EDIT_TEMPLATE = $('#entry_edit_template .world_entry');
|
||||||
|
|
||||||
let world_info = {};
|
export let world_info = {};
|
||||||
let selected_world_info = [];
|
export let selected_world_info = [];
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
let world_names;
|
export let world_names;
|
||||||
let world_info_depth = 2;
|
export let world_info_depth = 2;
|
||||||
let world_info_min_activations = 0; // if > 0, will continue seeking chat until minimum world infos are activated
|
export 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_info_min_activations_depth_max = 0; // used when (world_info_min_activations > 0)
|
||||||
|
|
||||||
let world_info_budget = 25;
|
export let world_info_budget = 25;
|
||||||
let world_info_include_names = true;
|
export let world_info_include_names = true;
|
||||||
let world_info_recursive = false;
|
export let world_info_recursive = false;
|
||||||
let world_info_overflow_alert = false;
|
export let world_info_overflow_alert = false;
|
||||||
let world_info_case_sensitive = false;
|
export let world_info_case_sensitive = false;
|
||||||
let world_info_match_whole_words = false;
|
export let world_info_match_whole_words = false;
|
||||||
let world_info_use_group_scoring = false;
|
export let world_info_use_group_scoring = false;
|
||||||
let world_info_character_strategy = world_info_insertion_strategy.character_first;
|
export let world_info_character_strategy = world_info_insertion_strategy.character_first;
|
||||||
let world_info_budget_cap = 0;
|
export let world_info_budget_cap = 0;
|
||||||
const saveWorldDebounced = debounce(async (name, data) => await _save(name, data), debounce_timeout.relaxed);
|
const saveWorldDebounced = debounce(async (name, data) => await _save(name, data), debounce_timeout.relaxed);
|
||||||
const saveSettingsDebounced = debounce(() => {
|
const saveSettingsDebounced = debounce(() => {
|
||||||
Object.assign(world_info, { globalSelect: selected_world_info });
|
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); };
|
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.
|
// Do not optimize. updateEditor is a function that is updated by the displayWorldEntries with new data.
|
||||||
const worldInfoFilter = new FilterHelper(() => updateEditor());
|
export const worldInfoFilter = new FilterHelper(() => updateEditor());
|
||||||
const SORT_ORDER_KEY = 'world_info_sort_order';
|
export const SORT_ORDER_KEY = 'world_info_sort_order';
|
||||||
const METADATA_KEY = 'world_info';
|
export const METADATA_KEY = 'world_info';
|
||||||
|
|
||||||
const DEFAULT_DEPTH = 4;
|
export const DEFAULT_DEPTH = 4;
|
||||||
const DEFAULT_WEIGHT = 100;
|
export const DEFAULT_WEIGHT = 100;
|
||||||
const MAX_SCAN_DEPTH = 1000;
|
export const MAX_SCAN_DEPTH = 1000;
|
||||||
const KNOWN_DECORATORS = ['@@activate', '@@dont_activate'];
|
const KNOWN_DECORATORS = ['@@activate', '@@dont_activate'];
|
||||||
|
|
||||||
// Typedef area
|
// Typedef area
|
||||||
|
@ -732,7 +712,7 @@ export function getWorldInfoSettings() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const world_info_position = {
|
export const world_info_position = {
|
||||||
before: 0,
|
before: 0,
|
||||||
after: 1,
|
after: 1,
|
||||||
ANTop: 2,
|
ANTop: 2,
|
||||||
|
@ -747,8 +727,18 @@ export const wi_anchor_position = {
|
||||||
after: 1,
|
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.
|
* 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
|
* @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) {
|
export async function getWorldInfoPrompt(chat, maxContext, isDryRun) {
|
||||||
let worldInfoString = '', worldInfoBefore = '', worldInfoAfter = '';
|
let worldInfoString = '', worldInfoBefore = '', worldInfoAfter = '';
|
||||||
|
|
||||||
const activatedWorldInfo = await checkWorldInfo(chat, maxContext, isDryRun);
|
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)
|
if (settings.world_info_depth !== undefined)
|
||||||
world_info_depth = Number(settings.world_info_depth);
|
world_info_depth = Number(settings.world_info_depth);
|
||||||
if (settings.world_info_min_activations !== undefined)
|
if (settings.world_info_min_activations !== undefined)
|
||||||
|
@ -916,7 +906,7 @@ function registerWorldInfoSlashCommands() {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await loadWorldInfoData(file);
|
const data = await loadWorldInfo(file);
|
||||||
|
|
||||||
if (!data || !('entries' in data)) {
|
if (!data || !('entries' in data)) {
|
||||||
toastr.warning('World Info file has an invalid format');
|
toastr.warning('World Info file has an invalid format');
|
||||||
|
@ -965,7 +955,7 @@ function registerWorldInfoSlashCommands() {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof newEntryTemplate[field] === 'boolean') {
|
if (typeof newWorldInfoEntryTemplate[field] === 'boolean') {
|
||||||
const isTrue = isTrueBoolean(value);
|
const isTrue = isTrueBoolean(value);
|
||||||
const isFalse = isFalseBoolean(value);
|
const isFalse = isFalseBoolean(value);
|
||||||
|
|
||||||
|
@ -1016,7 +1006,7 @@ function registerWorldInfoSlashCommands() {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newEntryTemplate[field] === undefined) {
|
if (newWorldInfoEntryTemplate[field] === undefined) {
|
||||||
toastr.warning('Valid field name is required');
|
toastr.warning('Valid field name is required');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -1038,7 +1028,7 @@ function registerWorldInfoSlashCommands() {
|
||||||
const file = args.file;
|
const file = args.file;
|
||||||
const key = args.key;
|
const key = args.key;
|
||||||
|
|
||||||
const data = await loadWorldInfoData(file);
|
const data = await loadWorldInfo(file);
|
||||||
|
|
||||||
if (!data || !('entries' in data)) {
|
if (!data || !('entries' in data)) {
|
||||||
toastr.warning('Valid World Info file name is required');
|
toastr.warning('Valid World Info file name is required');
|
||||||
|
@ -1075,7 +1065,7 @@ function registerWorldInfoSlashCommands() {
|
||||||
|
|
||||||
value = value.replace(/\\([{}|])/g, '$1');
|
value = value.replace(/\\([{}|])/g, '$1');
|
||||||
|
|
||||||
const data = await loadWorldInfoData(file);
|
const data = await loadWorldInfo(file);
|
||||||
|
|
||||||
if (!data || !('entries' in data)) {
|
if (!data || !('entries' in data)) {
|
||||||
toastr.warning('Valid World Info file name is required');
|
toastr.warning('Valid World Info file name is required');
|
||||||
|
@ -1089,7 +1079,7 @@ function registerWorldInfoSlashCommands() {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newEntryTemplate[field] === undefined) {
|
if (newWorldInfoEntryTemplate[field] === undefined) {
|
||||||
toastr.warning('Valid field name is required');
|
toastr.warning('Valid field name is required');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -1104,8 +1094,8 @@ function registerWorldInfoSlashCommands() {
|
||||||
entry[field] = value;
|
entry[field] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (originalDataKeyMap[field]) {
|
if (originalWIDataKeyMap[field]) {
|
||||||
setOriginalDataValue(data, uid, originalDataKeyMap[field], entry[field]);
|
setWIOriginalDataValue(data, uid, originalWIDataKeyMap[field], entry[field]);
|
||||||
}
|
}
|
||||||
|
|
||||||
await saveWorldInfo(file, data);
|
await saveWorldInfo(file, data);
|
||||||
|
@ -1226,7 +1216,7 @@ function registerWorldInfoSlashCommands() {
|
||||||
/** A collection of local enum providers for this context of world info */
|
/** A collection of local enum providers for this context of world info */
|
||||||
const localEnumProviders = {
|
const localEnumProviders = {
|
||||||
/** All possible fields that can be set in a WI entry */
|
/** 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)}`,
|
new SlashCommandEnumValue(key, `[${value.type}] default: ${(typeof value.default === 'string' ? `'${value.default}'` : value.default)}`,
|
||||||
enumTypes.enum, enumIcons.getDataTypeIcon(value.type))),
|
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) {
|
if (!name) {
|
||||||
hideWorldEditor();
|
hideWorldEditor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wiData = await loadWorldInfoData(name);
|
const wiData = await loadWorldInfo(name);
|
||||||
displayWorldEntries(name, wiData);
|
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) {
|
if (!name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1635,14 +1639,18 @@ function getWIElement(name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Sorts the given data based on the selected sort option
|
||||||
|
*
|
||||||
* @param {any[]} data WI entries
|
* @param {any[]} data WI entries
|
||||||
|
* @param {object} [options={}] - Optional arguments
|
||||||
|
* @param {{sortField?: string, sortOrder?: string, sortRule?: string}} [options.customSort={}] - Custom sort options, instead of the chosen UI sort
|
||||||
* @returns {any[]} Sorted data
|
* @returns {any[]} Sorted data
|
||||||
*/
|
*/
|
||||||
function sortEntries(data) {
|
export function sortWorldInfoEntries(data, { customSort = null } = {}) {
|
||||||
const option = $('#world_info_sort_order').find(':selected');
|
const option = $('#world_info_sort_order').find(':selected');
|
||||||
const sortField = option.data('field');
|
const sortField = customSort?.sortField ?? option.data('field');
|
||||||
const sortOrder = option.data('order');
|
const sortOrder = customSort?.sortOrder ?? option.data('order');
|
||||||
const sortRule = option.data('rule');
|
const sortRule = customSort?.sortRule ?? option.data('rule');
|
||||||
const orderSign = sortOrder === 'asc' ? 1 : -1;
|
const orderSign = sortOrder === 'asc' ? 1 : -1;
|
||||||
|
|
||||||
if (!data.length) return data;
|
if (!data.length) return data;
|
||||||
|
@ -1801,7 +1809,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
||||||
|
|
||||||
// Apply the filter and do the chosen sorting
|
// Apply the filter and do the chosen sorting
|
||||||
entriesArray = worldInfoFilter.applyFilters(entriesArray);
|
entriesArray = worldInfoFilter.applyFilters(entriesArray);
|
||||||
entriesArray = sortEntries(entriesArray);
|
entriesArray = sortWorldInfoEntries(entriesArray);
|
||||||
|
|
||||||
// Cache keys
|
// Cache keys
|
||||||
const keys = entriesArray.flatMap(entry => [...entry.key, ...entry.keysecondary]);
|
const keys = entriesArray.flatMap(entry => [...entry.key, ...entry.keysecondary]);
|
||||||
|
@ -1919,7 +1927,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
||||||
for (const entry of Object.values(data.entries)) {
|
for (const entry of Object.values(data.entries)) {
|
||||||
if (!entry.comment && Array.isArray(entry.key) && entry.key.length > 0) {
|
if (!entry.comment && Array.isArray(entry.key) && entry.key.length > 0) {
|
||||||
entry.comment = entry.key[0];
|
entry.comment = entry.key[0];
|
||||||
setOriginalDataValue(data, entry.uid, 'comment', entry.comment);
|
setWIOriginalDataValue(data, entry.uid, 'comment', entry.comment);
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1954,7 +1962,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
||||||
|
|
||||||
// We need to sort the entries here, as the data source isn't sorted
|
// We need to sort the entries here, as the data source isn't sorted
|
||||||
const entries = Object.values(data.entries);
|
const entries = Object.values(data.entries);
|
||||||
sortEntries(entries);
|
sortWorldInfoEntries(entries);
|
||||||
|
|
||||||
let updated = 0, current = start;
|
let updated = 0, current = start;
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
|
@ -1962,7 +1970,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
||||||
if (entry.order === newOrder) continue;
|
if (entry.order === newOrder) continue;
|
||||||
|
|
||||||
entry.order = newOrder;
|
entry.order = newOrder;
|
||||||
setOriginalDataValue(data, entry.order, 'order', entry.order);
|
setWIOriginalDataValue(data, entry.order, 'order', entry.order);
|
||||||
updated++;
|
updated++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2025,7 +2033,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
||||||
}
|
}
|
||||||
|
|
||||||
item.displayIndex = minDisplayIndex + index;
|
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 })));
|
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 +2044,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
||||||
//$("#world_popup_entries_list").disableSelection();
|
//$("#world_popup_entries_list").disableSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
const originalDataKeyMap = {
|
export const originalWIDataKeyMap = {
|
||||||
'displayIndex': 'extensions.display_index',
|
'displayIndex': 'extensions.display_index',
|
||||||
'excludeRecursion': 'extensions.exclude_recursion',
|
'excludeRecursion': 'extensions.exclude_recursion',
|
||||||
'preventRecursion': 'extensions.prevent_recursion',
|
'preventRecursion': 'extensions.prevent_recursion',
|
||||||
|
@ -2087,7 +2095,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)) {
|
if (data.originalData && Array.isArray(data.originalData.entries)) {
|
||||||
let originalEntry = data.originalData.entries.find(x => x.uid === uid);
|
let originalEntry = data.originalData.entries.find(x => x.uid === uid);
|
||||||
|
|
||||||
|
@ -2099,7 +2117,13 @@ function setOriginalDataValue(data, uid, key, value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteOriginalDataValue(data, uid) {
|
/**
|
||||||
|
* Deletes the original data entry corresponding to the given uid from the provided data object
|
||||||
|
*
|
||||||
|
* @param {object} data - The data object containing the original data entries
|
||||||
|
* @param {string} uid - The unique identifier of the data entry to be deleted
|
||||||
|
*/
|
||||||
|
export function deleteWIOriginalDataValue(data, uid) {
|
||||||
if (data.originalData && Array.isArray(data.originalData.entries)) {
|
if (data.originalData && Array.isArray(data.originalData.entries)) {
|
||||||
const originalIndex = data.originalData.entries.findIndex(x => x.uid === uid);
|
const originalIndex = data.originalData.entries.findIndex(x => x.uid === uid);
|
||||||
|
|
||||||
|
@ -2120,7 +2144,7 @@ function deleteOriginalDataValue(data, uid) {
|
||||||
* @param {string} input - One or multiple keywords or regexes, separated by commas
|
* @param {string} input - One or multiple keywords or regexes, separated by commas
|
||||||
* @returns {string[]} An array of keywords and regexes
|
* @returns {string[]} An array of keywords and regexes
|
||||||
*/
|
*/
|
||||||
function splitKeywordsAndRegexes(input) {
|
export function splitKeywordsAndRegexes(input) {
|
||||||
/** @type {string[]} */
|
/** @type {string[]} */
|
||||||
let keywordsAndRegexes = [];
|
let keywordsAndRegexes = [];
|
||||||
|
|
||||||
|
@ -2224,7 +2248,7 @@ function isValidRegex(input) {
|
||||||
* @param {string} input - A delimited regex string
|
* @param {string} input - A delimited regex string
|
||||||
* @returns {RegExp|null} The regex object, or null if not a valid regex
|
* @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
|
// Extracting the regex pattern and flags
|
||||||
let match = input.match(/^\/([\w\W]+?)\/([gimsuy]*)$/);
|
let match = input.match(/^\/([\w\W]+?)\/([gimsuy]*)$/);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
|
@ -2310,7 +2334,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
!skipReset && resetScrollHeight(this);
|
!skipReset && resetScrollHeight(this);
|
||||||
if (!noSave) {
|
if (!noSave) {
|
||||||
data.entries[uid][entryPropName] = keys;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2348,7 +2372,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
!skipReset && resetScrollHeight(this);
|
!skipReset && resetScrollHeight(this);
|
||||||
if (!noSave) {
|
if (!noSave) {
|
||||||
data.entries[uid][entryPropName] = splitKeywordsAndRegexes(value);
|
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);
|
await saveWorldInfo(name, data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2392,7 +2416,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const uid = $(this).data('uid');
|
const uid = $(this).data('uid');
|
||||||
const value = Number($(this).val());
|
const value = Number($(this).val());
|
||||||
data.entries[uid].selectiveLogic = !isNaN(value) ? value : world_info_logic.AND_ANY;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2441,7 +2465,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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
characterExclusionInput.prop('checked', entry.characterFilter?.isExclude ?? false).trigger('input');
|
characterExclusionInput.prop('checked', entry.characterFilter?.isExclude ?? false).trigger('input');
|
||||||
|
@ -2503,7 +2527,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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2517,7 +2541,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
!skipReset && resetScrollHeight(this);
|
!skipReset && resetScrollHeight(this);
|
||||||
data.entries[uid].comment = value;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
commentToggle.data('uid', entry.uid);
|
commentToggle.data('uid', entry.uid);
|
||||||
|
@ -2552,7 +2576,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const value = $(this).val();
|
const value = $(this).val();
|
||||||
data.entries[uid].content = value;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
|
|
||||||
if (skipCount) {
|
if (skipCount) {
|
||||||
|
@ -2582,7 +2606,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const value = $(this).prop('checked');
|
const value = $(this).prop('checked');
|
||||||
data.entries[uid].selective = value;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
|
|
||||||
const keysecondary = $(this)
|
const keysecondary = $(this)
|
||||||
|
@ -2631,7 +2655,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
|
|
||||||
data.entries[uid].order = !isNaN(value) ? value : 0;
|
data.entries[uid].order = !isNaN(value) ? value : 0;
|
||||||
updatePosOrdDisplay(uid);
|
updatePosOrdDisplay(uid);
|
||||||
setOriginalDataValue(data, uid, 'insertion_order', data.entries[uid].order);
|
setWIOriginalDataValue(data, uid, 'insertion_order', data.entries[uid].order);
|
||||||
await saveWorldInfo(name, data);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
orderInput.val(entry.order).trigger('input');
|
orderInput.val(entry.order).trigger('input');
|
||||||
|
@ -2645,7 +2669,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const value = String($(this).val()).trim();
|
const value = String($(this).val()).trim();
|
||||||
|
|
||||||
data.entries[uid].group = value;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
groupInput.val(entry.group ?? '').trigger('input');
|
groupInput.val(entry.group ?? '').trigger('input');
|
||||||
|
@ -2658,7 +2682,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const uid = $(this).data('uid');
|
const uid = $(this).data('uid');
|
||||||
const value = $(this).prop('checked');
|
const value = $(this).prop('checked');
|
||||||
data.entries[uid].groupOverride = value;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
groupOverrideInput.prop('checked', entry.groupOverride).trigger('input');
|
groupOverrideInput.prop('checked', entry.groupOverride).trigger('input');
|
||||||
|
@ -2682,7 +2706,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
data.entries[uid].groupWeight = !isNaN(value) ? Math.abs(value) : 1;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
groupWeightInput.val(entry.groupWeight ?? DEFAULT_WEIGHT).trigger('input');
|
groupWeightInput.val(entry.groupWeight ?? DEFAULT_WEIGHT).trigger('input');
|
||||||
|
@ -2695,7 +2719,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const value = Number($(this).val());
|
const value = Number($(this).val());
|
||||||
data.entries[uid].sticky = !isNaN(value) ? value : null;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
sticky.val(entry.sticky > 0 ? entry.sticky : '').trigger('input');
|
sticky.val(entry.sticky > 0 ? entry.sticky : '').trigger('input');
|
||||||
|
@ -2708,7 +2732,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const value = Number($(this).val());
|
const value = Number($(this).val());
|
||||||
data.entries[uid].cooldown = !isNaN(value) ? value : null;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
cooldown.val(entry.cooldown > 0 ? entry.cooldown : '').trigger('input');
|
cooldown.val(entry.cooldown > 0 ? entry.cooldown : '').trigger('input');
|
||||||
|
@ -2721,7 +2745,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const value = Number($(this).val());
|
const value = Number($(this).val());
|
||||||
data.entries[uid].delay = !isNaN(value) ? value : null;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
delay.val(entry.delay > 0 ? entry.delay : '').trigger('input');
|
delay.val(entry.delay > 0 ? entry.delay : '').trigger('input');
|
||||||
|
@ -2741,7 +2765,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
|
|
||||||
data.entries[uid].depth = !isNaN(value) ? value : 0;
|
data.entries[uid].depth = !isNaN(value) ? value : 0;
|
||||||
updatePosOrdDisplay(uid);
|
updatePosOrdDisplay(uid);
|
||||||
setOriginalDataValue(data, uid, 'extensions.depth', data.entries[uid].depth);
|
setWIOriginalDataValue(data, uid, 'extensions.depth', data.entries[uid].depth);
|
||||||
await saveWorldInfo(name, data);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
depthInput.val(entry.depth ?? DEFAULT_DEPTH).trigger('input');
|
depthInput.val(entry.depth ?? DEFAULT_DEPTH).trigger('input');
|
||||||
|
@ -2769,7 +2793,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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
probabilityInput.val(entry.probability).trigger('input');
|
probabilityInput.val(entry.probability).trigger('input');
|
||||||
|
@ -2836,10 +2860,10 @@ function getWorldEntry(name, data, entry) {
|
||||||
}
|
}
|
||||||
updatePosOrdDisplay(uid);
|
updatePosOrdDisplay(uid);
|
||||||
// Spec v2 only supports before_char and after_char
|
// 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
|
// Write the original value as extensions field
|
||||||
setOriginalDataValue(data, uid, 'extensions.position', data.entries[uid].position);
|
setWIOriginalDataValue(data, uid, 'extensions.position', data.entries[uid].position);
|
||||||
setOriginalDataValue(data, uid, 'extensions.role', data.entries[uid].role);
|
setWIOriginalDataValue(data, uid, 'extensions.role', data.entries[uid].role);
|
||||||
await saveWorldInfo(name, data);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2881,36 +2905,36 @@ function getWorldEntry(name, data, entry) {
|
||||||
data.entries[uid].constant = true;
|
data.entries[uid].constant = true;
|
||||||
data.entries[uid].disable = false;
|
data.entries[uid].disable = false;
|
||||||
data.entries[uid].vectorized = false;
|
data.entries[uid].vectorized = false;
|
||||||
setOriginalDataValue(data, uid, 'enabled', true);
|
setWIOriginalDataValue(data, uid, 'enabled', true);
|
||||||
setOriginalDataValue(data, uid, 'constant', true);
|
setWIOriginalDataValue(data, uid, 'constant', true);
|
||||||
setOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
setWIOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
||||||
template.removeClass('disabledWIEntry');
|
template.removeClass('disabledWIEntry');
|
||||||
break;
|
break;
|
||||||
case 'normal':
|
case 'normal':
|
||||||
data.entries[uid].constant = false;
|
data.entries[uid].constant = false;
|
||||||
data.entries[uid].disable = false;
|
data.entries[uid].disable = false;
|
||||||
data.entries[uid].vectorized = false;
|
data.entries[uid].vectorized = false;
|
||||||
setOriginalDataValue(data, uid, 'enabled', true);
|
setWIOriginalDataValue(data, uid, 'enabled', true);
|
||||||
setOriginalDataValue(data, uid, 'constant', false);
|
setWIOriginalDataValue(data, uid, 'constant', false);
|
||||||
setOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
setWIOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
||||||
template.removeClass('disabledWIEntry');
|
template.removeClass('disabledWIEntry');
|
||||||
break;
|
break;
|
||||||
case 'vectorized':
|
case 'vectorized':
|
||||||
data.entries[uid].constant = false;
|
data.entries[uid].constant = false;
|
||||||
data.entries[uid].disable = false;
|
data.entries[uid].disable = false;
|
||||||
data.entries[uid].vectorized = true;
|
data.entries[uid].vectorized = true;
|
||||||
setOriginalDataValue(data, uid, 'enabled', true);
|
setWIOriginalDataValue(data, uid, 'enabled', true);
|
||||||
setOriginalDataValue(data, uid, 'constant', false);
|
setWIOriginalDataValue(data, uid, 'constant', false);
|
||||||
setOriginalDataValue(data, uid, 'extensions.vectorized', true);
|
setWIOriginalDataValue(data, uid, 'extensions.vectorized', true);
|
||||||
template.removeClass('disabledWIEntry');
|
template.removeClass('disabledWIEntry');
|
||||||
break;
|
break;
|
||||||
case 'disabled':
|
case 'disabled':
|
||||||
data.entries[uid].constant = false;
|
data.entries[uid].constant = false;
|
||||||
data.entries[uid].disable = true;
|
data.entries[uid].disable = true;
|
||||||
data.entries[uid].vectorized = false;
|
data.entries[uid].vectorized = false;
|
||||||
setOriginalDataValue(data, uid, 'enabled', false);
|
setWIOriginalDataValue(data, uid, 'enabled', false);
|
||||||
setOriginalDataValue(data, uid, 'constant', false);
|
setWIOriginalDataValue(data, uid, 'constant', false);
|
||||||
setOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
setWIOriginalDataValue(data, uid, 'extensions.vectorized', false);
|
||||||
template.addClass('disabledWIEntry');
|
template.addClass('disabledWIEntry');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2941,7 +2965,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const uid = $(this).data('uid');
|
const uid = $(this).data('uid');
|
||||||
const value = $(this).prop('checked');
|
const value = $(this).prop('checked');
|
||||||
data.entries[uid].excludeRecursion = value;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
excludeRecursionInput.prop('checked', entry.excludeRecursion).trigger('input');
|
excludeRecursionInput.prop('checked', entry.excludeRecursion).trigger('input');
|
||||||
|
@ -2953,7 +2977,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const uid = $(this).data('uid');
|
const uid = $(this).data('uid');
|
||||||
const value = $(this).prop('checked');
|
const value = $(this).prop('checked');
|
||||||
data.entries[uid].preventRecursion = value;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
preventRecursionInput.prop('checked', entry.preventRecursion).trigger('input');
|
preventRecursionInput.prop('checked', entry.preventRecursion).trigger('input');
|
||||||
|
@ -2965,7 +2989,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const uid = $(this).data('uid');
|
const uid = $(this).data('uid');
|
||||||
const value = $(this).prop('checked');
|
const value = $(this).prop('checked');
|
||||||
data.entries[uid].delayUntilRecursion = value;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
delayUntilRecursionInput.prop('checked', entry.delayUntilRecursion).trigger('input');
|
delayUntilRecursionInput.prop('checked', entry.delayUntilRecursion).trigger('input');
|
||||||
|
@ -2985,10 +3009,12 @@ function getWorldEntry(name, data, entry) {
|
||||||
// delete button
|
// delete button
|
||||||
const deleteButton = template.find('.delete_entry_button');
|
const deleteButton = template.find('.delete_entry_button');
|
||||||
deleteButton.data('uid', entry.uid);
|
deleteButton.data('uid', entry.uid);
|
||||||
deleteButton.on('click', async function () {
|
deleteButton.on('click', async function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
const uid = $(this).data('uid');
|
const uid = $(this).data('uid');
|
||||||
deleteWorldInfoEntry(data, uid);
|
const deleted = await deleteWorldInfoEntry(data, uid);
|
||||||
deleteOriginalDataValue(data, uid);
|
if (!deleted) return;
|
||||||
|
deleteWIOriginalDataValue(data, uid);
|
||||||
await saveWorldInfo(name, data);
|
await saveWorldInfo(name, data);
|
||||||
updateEditor(navigation_option.previous);
|
updateEditor(navigation_option.previous);
|
||||||
});
|
});
|
||||||
|
@ -3015,7 +3041,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
data.entries[uid].scanDepth = !isEmpty && !isNaN(value) && value >= 0 && value <= MAX_SCAN_DEPTH ? Math.floor(value) : null;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
scanDepthInput.val(entry.scanDepth ?? null).trigger('input');
|
scanDepthInput.val(entry.scanDepth ?? null).trigger('input');
|
||||||
|
@ -3028,7 +3054,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const value = $(this).val();
|
const value = $(this).val();
|
||||||
|
|
||||||
data.entries[uid].caseSensitive = value === 'null' ? null : value === 'true';
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
caseSensitiveSelect.val((entry.caseSensitive === null || entry.caseSensitive === undefined) ? 'null' : entry.caseSensitive ? 'true' : 'false').trigger('input');
|
caseSensitiveSelect.val((entry.caseSensitive === null || entry.caseSensitive === undefined) ? 'null' : entry.caseSensitive ? 'true' : 'false').trigger('input');
|
||||||
|
@ -3041,7 +3067,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const value = $(this).val();
|
const value = $(this).val();
|
||||||
|
|
||||||
data.entries[uid].matchWholeWords = value === 'null' ? null : value === 'true';
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
matchWholeWordsSelect.val((entry.matchWholeWords === null || entry.matchWholeWords === undefined) ? 'null' : entry.matchWholeWords ? 'true' : 'false').trigger('input');
|
matchWholeWordsSelect.val((entry.matchWholeWords === null || entry.matchWholeWords === undefined) ? 'null' : entry.matchWholeWords ? 'true' : 'false').trigger('input');
|
||||||
|
@ -3054,7 +3080,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const value = $(this).val();
|
const value = $(this).val();
|
||||||
|
|
||||||
data.entries[uid].useGroupScoring = value === 'null' ? null : value === 'true';
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
useGroupScoringSelect.val((entry.useGroupScoring === null || entry.useGroupScoring === undefined) ? 'null' : entry.useGroupScoring ? 'true' : 'false').trigger('input');
|
useGroupScoringSelect.val((entry.useGroupScoring === null || entry.useGroupScoring === undefined) ? 'null' : entry.useGroupScoring ? 'true' : 'false').trigger('input');
|
||||||
|
@ -3067,7 +3093,7 @@ function getWorldEntry(name, data, entry) {
|
||||||
const value = $(this).val();
|
const value = $(this).val();
|
||||||
|
|
||||||
data.entries[uid].automationId = value;
|
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);
|
await saveWorldInfo(name, data);
|
||||||
});
|
});
|
||||||
automationIdInput.val(entry.automationId ?? '').trigger('input');
|
automationIdInput.val(entry.automationId ?? '').trigger('input');
|
||||||
|
@ -3200,12 +3226,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 {*} data - The data of the book
|
||||||
* @param {number} uid - The uid of the entry to copy in this book
|
* @param {number} uid - The uid of the entry to copy in this book
|
||||||
* @returns {*} The new WI duplicated entry
|
* @returns {*} The new WI duplicated entry
|
||||||
*/
|
*/
|
||||||
function duplicateWorldInfoEntry(data, uid) {
|
export function duplicateWorldInfoEntry(data, uid) {
|
||||||
if (!data || !('entries' in data) || !data.entries[uid]) {
|
if (!data || !('entries' in data) || !data.entries[uid]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3225,17 +3251,22 @@ function duplicateWorldInfoEntry(data, uid) {
|
||||||
* Deletes a WI entry, with a user confirmation dialog
|
* Deletes a WI entry, with a user confirmation dialog
|
||||||
* @param {*[]} data - The data of the book
|
* @param {*[]} data - The data of the book
|
||||||
* @param {number} uid - The uid of the entry to copy in this book
|
* @param {number} uid - The uid of the entry to copy in this book
|
||||||
|
* @param {object} [options={}] - Optional arguments
|
||||||
|
* @param {boolean} [options.silent=false] - Whether to prompt the user for deletion or just do it
|
||||||
|
* @returns {Promise<boolean>} Whether the entry deletion was successful
|
||||||
*/
|
*/
|
||||||
function deleteWorldInfoEntry(data, uid) {
|
export async function deleteWorldInfoEntry(data, uid, { silent = false } = {}) {
|
||||||
if (!data || !('entries' in data)) {
|
if (!data || !('entries' in data)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!confirm(`Delete the entry with UID: ${uid}? This action is irreversible!`)) {
|
const confirmation = silent || await Popup.show.confirm(`Delete the entry with UID: ${uid}?`, 'This action is irreversible!');
|
||||||
throw new Error('User cancelled deletion');
|
if (!confirmation) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete data.entries[uid];
|
delete data.entries[uid];
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3245,7 +3276,7 @@ function deleteWorldInfoEntry(data, uid) {
|
||||||
*
|
*
|
||||||
* @type {{[key: string]: { default: any, type: string }}}
|
* @type {{[key: string]: { default: any, type: string }}}
|
||||||
*/
|
*/
|
||||||
const newEntryDefinition = {
|
export const newWorldInfoEntryDefinition = {
|
||||||
key: { default: [], type: 'array' },
|
key: { default: [], type: 'array' },
|
||||||
keysecondary: { default: [], type: 'array' },
|
keysecondary: { default: [], type: 'array' },
|
||||||
comment: { default: '', type: 'string' },
|
comment: { default: '', type: 'string' },
|
||||||
|
@ -3278,8 +3309,8 @@ const newEntryDefinition = {
|
||||||
delay: { default: null, type: 'number?' },
|
delay: { default: null, type: 'number?' },
|
||||||
};
|
};
|
||||||
|
|
||||||
const newEntryTemplate = Object.fromEntries(
|
export const newWorldInfoEntryTemplate = Object.fromEntries(
|
||||||
Object.entries(newEntryDefinition).map(([key, value]) => [key, value.default]),
|
Object.entries(newWorldInfoEntryDefinition).map(([key, value]) => [key, value.default]),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3288,7 +3319,7 @@ const newEntryTemplate = Object.fromEntries(
|
||||||
* @param {any} data WI data
|
* @param {any} data WI data
|
||||||
* @returns {object | undefined} New entry object or undefined if failed
|
* @returns {object | undefined} New entry object or undefined if failed
|
||||||
*/
|
*/
|
||||||
function createWorldInfoEntry(_name, data) {
|
export function createWorldInfoEntry(_name, data) {
|
||||||
const newUid = getFreeWorldEntryUid(data);
|
const newUid = getFreeWorldEntryUid(data);
|
||||||
|
|
||||||
if (!Number.isInteger(newUid)) {
|
if (!Number.isInteger(newUid)) {
|
||||||
|
@ -3296,7 +3327,7 @@ function createWorldInfoEntry(_name, data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newEntry = { uid: newUid, ...structuredClone(newEntryTemplate) };
|
const newEntry = { uid: newUid, ...structuredClone(newWorldInfoEntryTemplate) };
|
||||||
data.entries[newUid] = newEntry;
|
data.entries[newUid] = newEntry;
|
||||||
|
|
||||||
return newEntry;
|
return newEntry;
|
||||||
|
@ -3314,7 +3345,21 @@ async function _save(name, data) {
|
||||||
eventSource.emit(event_types.WORLDINFO_UPDATED, 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) {
|
if (!name || !data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3371,7 +3416,7 @@ async function renameWorldInfo(name, data) {
|
||||||
* @param {string} worldInfoName - The name of the world info to delete
|
* @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
|
* @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)) {
|
if (!world_names.includes(worldInfoName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3406,7 +3451,7 @@ async function deleteWorldInfo(worldInfoName) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFreeWorldEntryUid(data) {
|
export function getFreeWorldEntryUid(data) {
|
||||||
if (!data || !('entries' in data)) {
|
if (!data || !('entries' in data)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -3422,7 +3467,7 @@ function getFreeWorldEntryUid(data) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFreeWorldName() {
|
export function getFreeWorldName() {
|
||||||
const MAX_FREE_NAME = 100_000;
|
const MAX_FREE_NAME = 100_000;
|
||||||
for (let index = 1; index < MAX_FREE_NAME; index++) {
|
for (let index = 1; index < MAX_FREE_NAME; index++) {
|
||||||
const newName = `New World (${index})`;
|
const newName = `New World (${index})`;
|
||||||
|
@ -3444,7 +3489,7 @@ function getFreeWorldName() {
|
||||||
* @param {boolean} [options.interactive=false] - Whether to show a confirmation dialog when overwriting an existing world
|
* @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
|
* @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: {} };
|
const worldInfoTemplate = { entries: {} };
|
||||||
|
|
||||||
if (!worldName) {
|
if (!worldName) {
|
||||||
|
@ -3505,7 +3550,7 @@ async function getCharacterLore() {
|
||||||
continue;
|
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 })) : [];
|
const newEntries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: worldName, ...rest })) : [];
|
||||||
entries = entries.concat(newEntries);
|
entries = entries.concat(newEntries);
|
||||||
|
|
||||||
|
@ -3525,7 +3570,7 @@ async function getGlobalLore() {
|
||||||
|
|
||||||
let entries = [];
|
let entries = [];
|
||||||
for (const worldName of selected_world_info) {
|
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 })) : [];
|
const newEntries = data ? Object.keys(data.entries).map((x) => data.entries[x]).map(({ uid, ...rest }) => ({ uid, world: worldName, ...rest })) : [];
|
||||||
entries = entries.concat(newEntries);
|
entries = entries.concat(newEntries);
|
||||||
}
|
}
|
||||||
|
@ -3547,7 +3592,7 @@ async function getChatLore() {
|
||||||
return [];
|
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 })) : [];
|
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]);
|
console.debug(`[WI] Chat lore has ${entries.length} entries`, [chatWorld]);
|
||||||
|
@ -3663,7 +3708,7 @@ function parseDecorators(content) {
|
||||||
* @typedef {{ worldInfoBefore: string, worldInfoAfter: string, EMEntries: any[], 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, isDryRun) {
|
export async function checkWorldInfo(chat, maxContext, isDryRun) {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
const buffer = new WorldInfoBuffer(chat);
|
const buffer = new WorldInfoBuffer(chat);
|
||||||
|
|
||||||
|
@ -4233,7 +4278,7 @@ function convertAgnaiMemoryBook(inputObj) {
|
||||||
|
|
||||||
inputObj.entries.forEach((entry, index) => {
|
inputObj.entries.forEach((entry, index) => {
|
||||||
outputObj.entries[index] = {
|
outputObj.entries[index] = {
|
||||||
...newEntryTemplate,
|
...newWorldInfoEntryTemplate,
|
||||||
uid: index,
|
uid: index,
|
||||||
key: entry.keywords,
|
key: entry.keywords,
|
||||||
keysecondary: [],
|
keysecondary: [],
|
||||||
|
@ -4275,7 +4320,7 @@ function convertRisuLorebook(inputObj) {
|
||||||
|
|
||||||
inputObj.data.forEach((entry, index) => {
|
inputObj.data.forEach((entry, index) => {
|
||||||
outputObj.entries[index] = {
|
outputObj.entries[index] = {
|
||||||
...newEntryTemplate,
|
...newWorldInfoEntryTemplate,
|
||||||
uid: index,
|
uid: index,
|
||||||
key: entry.key.split(',').map(x => x.trim()),
|
key: entry.key.split(',').map(x => x.trim()),
|
||||||
keysecondary: entry.secondkey ? entry.secondkey.split(',').map(x => x.trim()) : [],
|
keysecondary: entry.secondkey ? entry.secondkey.split(',').map(x => x.trim()) : [],
|
||||||
|
@ -4322,7 +4367,7 @@ function convertNovelLorebook(inputObj) {
|
||||||
const addMemo = displayName !== undefined && displayName.trim() !== '';
|
const addMemo = displayName !== undefined && displayName.trim() !== '';
|
||||||
|
|
||||||
outputObj.entries[index] = {
|
outputObj.entries[index] = {
|
||||||
...newEntryTemplate,
|
...newWorldInfoEntryTemplate,
|
||||||
uid: index,
|
uid: index,
|
||||||
key: entry.keys,
|
key: entry.keys,
|
||||||
keysecondary: [],
|
keysecondary: [],
|
||||||
|
@ -4369,7 +4414,7 @@ function convertCharacterBook(characterBook) {
|
||||||
}
|
}
|
||||||
|
|
||||||
result.entries[entry.id] = {
|
result.entries[entry.id] = {
|
||||||
...newEntryTemplate,
|
...newWorldInfoEntryTemplate,
|
||||||
uid: entry.id,
|
uid: entry.id,
|
||||||
key: entry.keys,
|
key: entry.keys,
|
||||||
keysecondary: entry.secondary_keys || [],
|
keysecondary: entry.secondary_keys || [],
|
||||||
|
@ -4499,7 +4544,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) {
|
||||||
setWorldInfoButtonClass(chid, true);
|
setWorldInfoButtonClass(chid, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWorldInfoChange(args, text) {
|
export function onWorldInfoChange(args, text) {
|
||||||
if (args !== '__notSlashCommand__') { // if it's a slash command
|
if (args !== '__notSlashCommand__') { // if it's a slash command
|
||||||
const silent = isTrueBoolean(args.silent);
|
const silent = isTrueBoolean(args.silent);
|
||||||
if (text.trim() !== '') { // and args are provided
|
if (text.trim() !== '') { // and args are provided
|
||||||
|
@ -4650,7 +4695,7 @@ export async function importWorldInfo(file) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function assignLorebookToChat() {
|
export function assignLorebookToChat() {
|
||||||
const selectedName = chat_metadata[METADATA_KEY];
|
const selectedName = chat_metadata[METADATA_KEY];
|
||||||
const template = $('#chat_world_template .chat_world').clone();
|
const template = $('#chat_world_template .chat_world').clone();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue