Merge branch 'staging' into parser-followup-2
This commit is contained in:
commit
8cb31d2f7b
|
@ -5,6 +5,10 @@
|
|||
width: unset;
|
||||
}
|
||||
|
||||
#sheldWidthToggleBlock {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bg_button {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
|
|
@ -2862,6 +2862,11 @@
|
|||
</div>
|
||||
<h4 data-i18n="Groq Model">Groq Model</h4>
|
||||
<select id="model_groq_select">
|
||||
<option value="llama-3.1-405b-reasoning">llama-3.1-405b-reasoning</option>
|
||||
<option value="llama-3.1-70b-versatile">llama-3.1-70b-versatile</option>
|
||||
<option value="llama-3.1-8b-instant">llama-3.1-8b-instant</option>
|
||||
<option value="llama3-groq-70b-8192-tool-use-preview">llama3-groq-70b-8192-tool-use-preview</option>
|
||||
<option value="llama3-groq-8b-8192-tool-use-preview">llama3-groq-8b-8192-tool-use-preview</option>
|
||||
<option value="llama3-8b-8192">llama3-8b-8192</option>
|
||||
<option value="llama3-70b-8192">llama3-70b-8192</option>
|
||||
<option value="mixtral-8x7b-32768">mixtral-8x7b-32768</option>
|
||||
|
|
|
@ -1640,5 +1640,26 @@
|
|||
"Ask": "Спрашивать",
|
||||
"tag_import_all": "Все",
|
||||
"Existing": "Только существующие",
|
||||
"tag_import_none": "Не импортировать"
|
||||
"tag_import_none": "Не импортировать",
|
||||
"Using a proxy that you're not running yourself is a risk to your data privacy.": "Помните, что используя чужую прокси, вы подвергаете риску конфиденциальность своих данных.",
|
||||
"ANY support requests will be REFUSED if you are using a proxy.": "НЕ РАССЧИТЫВАЙТЕ на нашу поддержку, если используете прокси.",
|
||||
"Do not proceed if you do not agree to this!": "Не продолжайте, если не согласны с этими условиями!",
|
||||
"Injection position. Relative (to other prompts in prompt manager) or In-chat @ Depth.": "Как рассчитывать позицию, на которую вставляется данный промпт. Относительно других промтов в менеджере, либо на опред. глубину в чате.",
|
||||
"prompt_manager_in_chat": "На глубине в чате",
|
||||
"01.AI API Key": "Ключ от API 01.AI",
|
||||
"01.AI Model": "Модель 01.AI",
|
||||
"Load a custom asset list or select": "Загрузите набор внешних ресурсов или выберите",
|
||||
"Install Extension": "Установить расширение",
|
||||
"to install 3rd party extensions.": ", чтобы установить стороннее расширение.",
|
||||
"Load an asset list": "Загрузить набор ресурсов",
|
||||
"load_asset_list_desc": "Загрузить набор ресурсов и/или расширений из определённого списка.\n\nДефолтный URL содержит описание набора стандартных ресурсов, идущих в комплекте.\nЕсли хотите скачать ресурсы из стороннего набора, вставьте в это поле свой URL.\n\nЧтобы установить одиночное расширение от стороннего разработчика, воспользуйтесь кнопкой \"Установить расширение\" в левом верхнем углу.",
|
||||
"Show group chat queue": "Показывать очерёдность в групповых чатах",
|
||||
"In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "Подсвечивать персонажей, которые скоро будут генерировать ответ в групповом чате, а также порядок, в котором они будут это делать",
|
||||
"Sequence Breakers": "Брейкеры для строк",
|
||||
"DRY_Sequence_Breakers_desc": "Токены, которые прерывают сопоставление/поиск строк. Вводятся через запятую, каждый брейкер в отдельных кавычках.",
|
||||
"ext_regex_user_input_desc": "Сообщения, отправленные пользователем",
|
||||
"ext_regex_ai_output_desc": "Сообщения, полученные от API",
|
||||
"ext_regex_sts_desc": "Сообщения, отправленные с помощью команд STscript",
|
||||
"ext_regex_wi_desc": "Содержимое лорбуков и миров. Для работы требует включения флажка \"Только промпт\"!",
|
||||
"ext_regex_only_format_display_desc": "История чата не изменится, замена будет осуществляться только в отображаемом сообщении (в UI)"
|
||||
}
|
|
@ -8961,14 +8961,6 @@ API Settings: ${JSON.stringify(getSettingsContents[getSettingsContents.main_api
|
|||
}
|
||||
|
||||
jQuery(async function () {
|
||||
|
||||
if (isMobile()) {
|
||||
console.debug('hiding movingUI and sheldWidth toggles for mobile');
|
||||
$('#sheldWidthToggleBlock').hide();
|
||||
$('#movingUIModeCheckBlock').hide();
|
||||
|
||||
}
|
||||
|
||||
async function doForceSave() {
|
||||
await saveSettings();
|
||||
await saveChatConditional();
|
||||
|
@ -9261,12 +9253,26 @@ jQuery(async function () {
|
|||
}
|
||||
});
|
||||
const chatElementScroll = document.getElementById('chat');
|
||||
chatElementScroll.addEventListener('wheel', function () {
|
||||
scrollLock = true;
|
||||
}, { passive: true });
|
||||
chatElementScroll.addEventListener('touchstart', function () {
|
||||
scrollLock = true;
|
||||
}, { passive: true });
|
||||
const chatScrollHandler = function () {
|
||||
if (power_user.waifuMode) {
|
||||
scrollLock = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const scrollIsAtBottom = Math.abs(chatElementScroll.scrollHeight - chatElementScroll.clientHeight - chatElementScroll.scrollTop) < 1;
|
||||
|
||||
// Resume autoscroll if the user scrolls to the bottom
|
||||
if (scrollLock && scrollIsAtBottom) {
|
||||
scrollLock = false;
|
||||
}
|
||||
|
||||
// Cancel autoscroll if the user scrolls up
|
||||
if (!scrollLock && !scrollIsAtBottom) {
|
||||
scrollLock = true;
|
||||
}
|
||||
};
|
||||
chatElementScroll.addEventListener('wheel', chatScrollHandler, { passive: true });
|
||||
chatElementScroll.addEventListener('touchmove', chatScrollHandler, { passive: true });
|
||||
chatElementScroll.addEventListener('scroll', function () {
|
||||
if (is_use_scroll_holder) {
|
||||
this.scrollTop = scroll_holder;
|
||||
|
|
|
@ -9,20 +9,20 @@
|
|||
<span data-i18n="Load a custom asset list or select">
|
||||
Load a custom asset list or select
|
||||
</span>
|
||||
<a class="assets-install-hint-link" data-i18n="Install Extension">Install Extension</a>
|
||||
<a class="assets-install-hint-link" data-i18n="Install extension">Install Extension</a>
|
||||
<span data-i18n="to install 3rd party extensions.">
|
||||
to install 3rd party extensions.
|
||||
</span>
|
||||
</small>
|
||||
<div class="assets-url-block m-b-1 m-t-1">
|
||||
<label for="assets-json-url-field" data-i18n="Assets URL">Assets URL</label>
|
||||
<small title="Load a list of extensions & assets based on an asset list file.
|
||||
<small data-i18n="[title]load_asset_list_desc" title="Load a list of extensions & assets based on an asset list file.
|
||||
|
||||
The default Asset URL in this field points to the list of offical first party extensions and assets.
|
||||
If you have a custom asset list, you can insert it here.
|
||||
|
||||
To install a single 3rd party extension, use the "Install Extensions" button on the top right.">
|
||||
<span>Load an asset list</span>
|
||||
<span data-i18n="Load an asset list">Load an asset list</span>
|
||||
<div class="fa-solid fa-circle-info opacity50p"></div>
|
||||
</small>
|
||||
<div class="assets-connect-div">
|
||||
|
|
|
@ -97,9 +97,9 @@ class SystemTtsProvider {
|
|||
|
||||
return `<p>Uses the voices provided by your operating system</p>
|
||||
<label for="system_tts_rate">Rate: <span id="system_tts_rate_output"></span></label>
|
||||
<input id="system_tts_rate" type="range" value="${this.defaultSettings.rate}" min="0.5" max="2" step="0.1" />
|
||||
<input id="system_tts_rate" type="range" value="${this.defaultSettings.rate}" min="0.1" max="2" step="0.01" />
|
||||
<label for="system_tts_pitch">Pitch: <span id="system_tts_pitch_output"></span></label>
|
||||
<input id="system_tts_pitch" type="range" value="${this.defaultSettings.pitch}" min="0" max="2" step="0.1" />`;
|
||||
<input id="system_tts_pitch" type="range" value="${this.defaultSettings.pitch}" min="0" max="2" step="0.01" />`;
|
||||
}
|
||||
|
||||
onSettingsChange() {
|
||||
|
@ -147,7 +147,7 @@ class SystemTtsProvider {
|
|||
|
||||
// Trigger updates
|
||||
$('#system_tts_rate').on('input', () => { this.onSettingsChange(); });
|
||||
$('#system_tts_rate').on('input', () => { this.onSettingsChange(); });
|
||||
$('#system_tts_pitch').on('input', () => { this.onSettingsChange(); });
|
||||
|
||||
$('#system_tts_pitch_output').text(this.settings.pitch);
|
||||
$('#system_tts_rate_output').text(this.settings.rate);
|
||||
|
@ -198,8 +198,8 @@ class SystemTtsProvider {
|
|||
const text = getPreviewString(voice.lang);
|
||||
const utterance = new SpeechSynthesisUtterance(text);
|
||||
utterance.voice = voice;
|
||||
utterance.rate = 1;
|
||||
utterance.pitch = 1;
|
||||
utterance.rate = this.settings.rate || 1;
|
||||
utterance.pitch = this.settings.pitch || 1;
|
||||
speechSynthesis.speak(utterance);
|
||||
}
|
||||
|
||||
|
|
|
@ -4220,6 +4220,12 @@ async function onModelChange() {
|
|||
if (oai_settings.max_context_unlocked) {
|
||||
$('#openai_max_context').attr('max', unlocked_max);
|
||||
}
|
||||
else if (oai_settings.groq_model.includes('llama-3.1')) {
|
||||
$('#openai_max_context').attr('max', max_128k);
|
||||
}
|
||||
else if (oai_settings.groq_model.includes('llama3-groq')) {
|
||||
$('#openai_max_context').attr('max', max_8k);
|
||||
}
|
||||
else if (['llama3-8b-8192', 'llama3-70b-8192', 'gemma-7b-it', 'gemma2-9b-it'].includes(oai_settings.groq_model)) {
|
||||
$('#openai_max_context').attr('max', max_8k);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* A specialized Map class that provides consistent data storage by performing deep cloning of values.
|
||||
*
|
||||
* @template K, V
|
||||
* @extends Map<K, V>
|
||||
*/
|
||||
export class StructuredCloneMap extends Map {
|
||||
/**
|
||||
* Constructs a new StructuredCloneMap.
|
||||
* @param {object} options - Options for the map
|
||||
* @param {boolean} options.cloneOnGet - Whether to clone the value when getting it from the map
|
||||
* @param {boolean} options.cloneOnSet - Whether to clone the value when setting it in the map
|
||||
*/
|
||||
constructor({ cloneOnGet, cloneOnSet } = { cloneOnGet: true, cloneOnSet: true }) {
|
||||
super();
|
||||
this.cloneOnGet = cloneOnGet;
|
||||
this.cloneOnSet = cloneOnSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new element with a specified key and value to the Map. If an element with the same key already exists, the element will be updated.
|
||||
*
|
||||
* The set value will always be a deep clone of the provided value to provide consistent data storage.
|
||||
*
|
||||
* @param {K} key - The key to set
|
||||
* @param {V} value - The value to set
|
||||
* @returns {this} The updated map
|
||||
*/
|
||||
set(key, value) {
|
||||
if (!this.cloneOnSet) {
|
||||
return super.set(key, value);
|
||||
}
|
||||
|
||||
const clonedValue = structuredClone(value);
|
||||
super.set(key, clonedValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specified element from the Map object.
|
||||
* If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.
|
||||
*
|
||||
* The returned value will always be a deep clone of the cached value.
|
||||
*
|
||||
* @param {K} key - The key to get the value for
|
||||
* @returns {V | undefined} Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.
|
||||
*/
|
||||
get(key) {
|
||||
if (!this.cloneOnGet) {
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
const value = super.get(key);
|
||||
return structuredClone(value);
|
||||
}
|
||||
}
|
|
@ -270,6 +270,13 @@ export function getStringHash(str, seed = 0) {
|
|||
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of debounced functions to their timers.
|
||||
* Weak map is used to avoid memory leaks.
|
||||
* @type {WeakMap<function, any>}
|
||||
*/
|
||||
const debounceMap = new WeakMap();
|
||||
|
||||
/**
|
||||
* Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked.
|
||||
* @param {function} func The function to debounce.
|
||||
|
@ -278,10 +285,26 @@ export function getStringHash(str, seed = 0) {
|
|||
*/
|
||||
export function debounce(func, timeout = debounce_timeout.standard) {
|
||||
let timer;
|
||||
return (...args) => {
|
||||
let fn = (...args) => {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(() => { func.apply(this, args); }, timeout);
|
||||
debounceMap.set(func, timer);
|
||||
debounceMap.set(fn, timer);
|
||||
};
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a scheduled debounced function.
|
||||
* Does nothing if the function is not debounced or not scheduled.
|
||||
* @param {function} func The function to cancel. Either the original or the debounced function.
|
||||
*/
|
||||
export function cancelDebounce(func) {
|
||||
if (debounceMap.has(func)) {
|
||||
clearTimeout(debounceMap.get(func));
|
||||
debounceMap.delete(func);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { saveSettings, callPopup, substituteParams, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types, getExtensionPromptByName, saveMetadata, getCurrentChatId, extension_prompt_roles } from '../script.js';
|
||||
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight, select2ModifyOptions, getSelect2OptionId, dynamicSelect2DataViaAjax, highlightRegex, select2ChoiceClickSubscribe, isFalseBoolean, getSanitizedFilename, checkOverwriteExistingData, getStringHash, parseStringArray } from './utils.js';
|
||||
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight, select2ModifyOptions, getSelect2OptionId, dynamicSelect2DataViaAjax, highlightRegex, select2ChoiceClickSubscribe, isFalseBoolean, getSanitizedFilename, checkOverwriteExistingData, getStringHash, parseStringArray, cancelDebounce } from './utils.js';
|
||||
import { extension_settings, getContext } from './extensions.js';
|
||||
import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from './authors-note.js';
|
||||
import { isMobile } from './RossAscends-mods.js';
|
||||
|
@ -16,6 +16,7 @@ import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandE
|
|||
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
|
||||
import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js';
|
||||
import { StructuredCloneMap } from './util/StructuredCloneMap.js';
|
||||
|
||||
export {
|
||||
world_info,
|
||||
|
@ -746,7 +747,8 @@ export const wi_anchor_position = {
|
|||
after: 1,
|
||||
};
|
||||
|
||||
const worldInfoCache = new Map();
|
||||
/** @type {StructuredCloneMap<string,object>} */
|
||||
const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOnSet: false });
|
||||
|
||||
/**
|
||||
* Gets the world info based on chat messages.
|
||||
|
@ -885,9 +887,15 @@ function setWorldInfoSettings(settings, data) {
|
|||
}
|
||||
|
||||
function registerWorldInfoSlashCommands() {
|
||||
function reloadEditor(file) {
|
||||
/**
|
||||
* Reloads the editor with the specified world info file
|
||||
* @param {string} file - The file to load in the editor
|
||||
* @param {boolean} [loadIfNotSelected=false] - Indicates whether to load the file even if it's not currently selected
|
||||
*/
|
||||
function reloadEditor(file, loadIfNotSelected = false) {
|
||||
const currentIndex = $('#world_editor_select').val();
|
||||
const selectedIndex = world_names.indexOf(file);
|
||||
if (selectedIndex !== -1) {
|
||||
if (selectedIndex !== -1 && (loadIfNotSelected || currentIndex === selectedIndex)) {
|
||||
$('#world_editor_select').val(selectedIndex).trigger('change');
|
||||
}
|
||||
}
|
||||
|
@ -1049,7 +1057,7 @@ function registerWorldInfoSlashCommands() {
|
|||
entry.content = content;
|
||||
}
|
||||
|
||||
await saveWorldInfo(file, data, true);
|
||||
await saveWorldInfo(file, data);
|
||||
reloadEditor(file);
|
||||
|
||||
return String(entry.uid);
|
||||
|
@ -1100,7 +1108,7 @@ function registerWorldInfoSlashCommands() {
|
|||
setOriginalDataValue(data, uid, originalDataKeyMap[field], entry[field]);
|
||||
}
|
||||
|
||||
await saveWorldInfo(file, data, true);
|
||||
await saveWorldInfo(file, data);
|
||||
reloadEditor(file);
|
||||
return '';
|
||||
}
|
||||
|
@ -1840,7 +1848,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
|||
nextText: '>',
|
||||
formatNavigator: PAGINATION_TEMPLATE,
|
||||
showNavigator: true,
|
||||
callback: function (/** @type {object[]} */ page) {
|
||||
callback: async function (/** @type {object[]} */ page) {
|
||||
// We save costly performance by removing all events before emptying. Because we know there are no relevant event handlers reacting on removing elements
|
||||
// This prevents jQuery from actually going through all registered events on the controls for each entry when removing it
|
||||
worldEntriesList.find('*').off();
|
||||
|
@ -1926,7 +1934,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
|||
|
||||
if (counter > 0) {
|
||||
toastr.info(`Backfilled ${counter} titles`);
|
||||
await saveWorldInfo(name, data, true);
|
||||
await saveWorldInfo(name, data);
|
||||
updateEditor(navigation_option.previous);
|
||||
}
|
||||
});
|
||||
|
@ -2026,7 +2034,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none, fl
|
|||
|
||||
console.table(Object.keys(data.entries).map(uid => data.entries[uid]).map(x => ({ uid: x.uid, key: x.key.join(','), displayIndex: x.displayIndex })));
|
||||
|
||||
await saveWorldInfo(name, data, true);
|
||||
await saveWorldInfo(name, data);
|
||||
},
|
||||
});
|
||||
//$("#world_popup_entries_list").disableSelection();
|
||||
|
@ -2298,7 +2306,7 @@ function getWorldEntry(name, data, entry) {
|
|||
templateResult: item => templateStyling(item, { searchStyle: true }),
|
||||
templateSelection: item => templateStyling(item),
|
||||
});
|
||||
input.on('change', function (_, { skipReset, noSave } = {}) {
|
||||
input.on('change', async function (_, { skipReset, noSave } = {}) {
|
||||
const uid = $(this).data('uid');
|
||||
/** @type {string[]} */
|
||||
const keys = ($(this).select2('data')).map(x => x.text);
|
||||
|
@ -2307,7 +2315,7 @@ function getWorldEntry(name, data, entry) {
|
|||
if (!noSave) {
|
||||
data.entries[uid][entryPropName] = keys;
|
||||
setOriginalDataValue(data, uid, originalDataValueName, data.entries[uid][entryPropName]);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
}
|
||||
});
|
||||
input.on('select2:select', /** @type {function(*):void} */ event => updateWorldEntryKeyOptionsCache([event.params.data]));
|
||||
|
@ -2338,14 +2346,14 @@ function getWorldEntry(name, data, entry) {
|
|||
template.find(`select[name="${entryPropName}"]`).hide();
|
||||
input.show();
|
||||
|
||||
input.on('input', function (_, { skipReset, noSave } = {}) {
|
||||
input.on('input', async function (_, { skipReset, noSave } = {}) {
|
||||
const uid = $(this).data('uid');
|
||||
const value = String($(this).val());
|
||||
!skipReset && resetScrollHeight(this);
|
||||
if (!noSave) {
|
||||
data.entries[uid][entryPropName] = splitKeywordsAndRegexes(value);
|
||||
setOriginalDataValue(data, uid, originalDataValueName, data.entries[uid][entryPropName]);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
}
|
||||
});
|
||||
input.val(entry[entryPropName].join(', ')).trigger('input', { skipReset: true });
|
||||
|
@ -2384,12 +2392,12 @@ function getWorldEntry(name, data, entry) {
|
|||
event.stopPropagation();
|
||||
});
|
||||
|
||||
selectiveLogicDropdown.on('input', function () {
|
||||
selectiveLogicDropdown.on('input', async function () {
|
||||
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);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
|
||||
template
|
||||
|
@ -2404,7 +2412,7 @@ function getWorldEntry(name, data, entry) {
|
|||
// exclude characters checkbox
|
||||
const characterExclusionInput = template.find('input[name="character_exclusion"]');
|
||||
characterExclusionInput.data('uid', entry.uid);
|
||||
characterExclusionInput.on('input', function () {
|
||||
characterExclusionInput.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).prop('checked');
|
||||
characterFilterLabel.text(value ? 'Exclude Character(s)' : 'Filter to Character(s)');
|
||||
|
@ -2438,7 +2446,7 @@ function getWorldEntry(name, data, entry) {
|
|||
}
|
||||
|
||||
setOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
characterExclusionInput.prop('checked', entry.characterFilter?.isExclude ?? false).trigger('input');
|
||||
|
||||
|
@ -2500,24 +2508,24 @@ function getWorldEntry(name, data, entry) {
|
|||
);
|
||||
}
|
||||
setOriginalDataValue(data, uid, 'character_filter', data.entries[uid].characterFilter);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
|
||||
// comment
|
||||
const commentInput = template.find('textarea[name="comment"]');
|
||||
const commentToggle = template.find('input[name="addMemo"]');
|
||||
commentInput.data('uid', entry.uid);
|
||||
commentInput.on('input', function (_, { skipReset } = {}) {
|
||||
commentInput.on('input', async function (_, { skipReset } = {}) {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).val();
|
||||
!skipReset && resetScrollHeight(this);
|
||||
data.entries[uid].comment = value;
|
||||
|
||||
setOriginalDataValue(data, uid, 'comment', data.entries[uid].comment);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
commentToggle.data('uid', entry.uid);
|
||||
commentToggle.on('input', function () {
|
||||
commentToggle.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).prop('checked');
|
||||
//console.log(value)
|
||||
|
@ -2525,7 +2533,7 @@ function getWorldEntry(name, data, entry) {
|
|||
.closest('.world_entry')
|
||||
.find('.commentContainer');
|
||||
data.entries[uid].addMemo = value;
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
value ? commentContainer.show() : commentContainer.hide();
|
||||
});
|
||||
|
||||
|
@ -2543,13 +2551,13 @@ function getWorldEntry(name, data, entry) {
|
|||
|
||||
const contentInput = template.find('textarea[name="content"]');
|
||||
contentInput.data('uid', entry.uid);
|
||||
contentInput.on('input', function (_, { skipCount } = {}) {
|
||||
contentInput.on('input', async function (_, { skipCount } = {}) {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).val();
|
||||
data.entries[uid].content = value;
|
||||
|
||||
setOriginalDataValue(data, uid, 'content', data.entries[uid].content);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
|
||||
if (skipCount) {
|
||||
return;
|
||||
|
@ -2573,13 +2581,13 @@ function getWorldEntry(name, data, entry) {
|
|||
// selective
|
||||
const selectiveInput = template.find('input[name="selective"]');
|
||||
selectiveInput.data('uid', entry.uid);
|
||||
selectiveInput.on('input', function () {
|
||||
selectiveInput.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).prop('checked');
|
||||
data.entries[uid].selective = value;
|
||||
|
||||
setOriginalDataValue(data, uid, 'selective', data.entries[uid].selective);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
|
||||
const keysecondary = $(this)
|
||||
.closest('.world_entry')
|
||||
|
@ -2608,12 +2616,12 @@ function getWorldEntry(name, data, entry) {
|
|||
/*
|
||||
const constantInput = template.find('input[name="constant"]');
|
||||
constantInput.data("uid", entry.uid);
|
||||
constantInput.on("input", function () {
|
||||
constantInput.on("input", async function () {
|
||||
const uid = $(this).data("uid");
|
||||
const value = $(this).prop("checked");
|
||||
data.entries[uid].constant = value;
|
||||
setOriginalDataValue(data, uid, "constant", data.entries[uid].constant);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
constantInput.prop("checked", entry.constant).trigger("input");
|
||||
*/
|
||||
|
@ -2621,14 +2629,14 @@ function getWorldEntry(name, data, entry) {
|
|||
// order
|
||||
const orderInput = template.find('input[name="order"]');
|
||||
orderInput.data('uid', entry.uid);
|
||||
orderInput.on('input', function () {
|
||||
orderInput.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = Number($(this).val());
|
||||
|
||||
data.entries[uid].order = !isNaN(value) ? value : 0;
|
||||
updatePosOrdDisplay(uid);
|
||||
setOriginalDataValue(data, uid, 'insertion_order', data.entries[uid].order);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
orderInput.val(entry.order).trigger('input');
|
||||
orderInput.css('width', 'calc(3em + 15px)');
|
||||
|
@ -2636,13 +2644,13 @@ function getWorldEntry(name, data, entry) {
|
|||
// group
|
||||
const groupInput = template.find('input[name="group"]');
|
||||
groupInput.data('uid', entry.uid);
|
||||
groupInput.on('input', function () {
|
||||
groupInput.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = String($(this).val()).trim();
|
||||
|
||||
data.entries[uid].group = value;
|
||||
setOriginalDataValue(data, uid, 'extensions.group', data.entries[uid].group);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
groupInput.val(entry.group ?? '').trigger('input');
|
||||
setTimeout(() => createEntryInputAutocomplete(groupInput, getInclusionGroupCallback(data), { allowMultiple: true }), 1);
|
||||
|
@ -2650,19 +2658,19 @@ function getWorldEntry(name, data, entry) {
|
|||
// inclusion priority
|
||||
const groupOverrideInput = template.find('input[name="groupOverride"]');
|
||||
groupOverrideInput.data('uid', entry.uid);
|
||||
groupOverrideInput.on('input', function () {
|
||||
groupOverrideInput.on('input', async function () {
|
||||
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);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
groupOverrideInput.prop('checked', entry.groupOverride).trigger('input');
|
||||
|
||||
// group weight
|
||||
const groupWeightInput = template.find('input[name="groupWeight"]');
|
||||
groupWeightInput.data('uid', entry.uid);
|
||||
groupWeightInput.on('input', function () {
|
||||
groupWeightInput.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
let value = Number($(this).val());
|
||||
const min = Number($(this).attr('min'));
|
||||
|
@ -2679,46 +2687,46 @@ 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);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
groupWeightInput.val(entry.groupWeight ?? DEFAULT_WEIGHT).trigger('input');
|
||||
|
||||
// sticky
|
||||
const sticky = template.find('input[name="sticky"]');
|
||||
sticky.data('uid', entry.uid);
|
||||
sticky.on('input', function () {
|
||||
sticky.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = Number($(this).val());
|
||||
data.entries[uid].sticky = !isNaN(value) ? value : null;
|
||||
|
||||
setOriginalDataValue(data, uid, 'extensions.sticky', data.entries[uid].sticky);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
sticky.val(entry.sticky > 0 ? entry.sticky : '').trigger('input');
|
||||
|
||||
// cooldown
|
||||
const cooldown = template.find('input[name="cooldown"]');
|
||||
cooldown.data('uid', entry.uid);
|
||||
cooldown.on('input', function () {
|
||||
cooldown.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = Number($(this).val());
|
||||
data.entries[uid].cooldown = !isNaN(value) ? value : null;
|
||||
|
||||
setOriginalDataValue(data, uid, 'extensions.cooldown', data.entries[uid].cooldown);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
cooldown.val(entry.cooldown > 0 ? entry.cooldown : '').trigger('input');
|
||||
|
||||
// delay
|
||||
const delay = template.find('input[name="delay"]');
|
||||
delay.data('uid', entry.uid);
|
||||
delay.on('input', function () {
|
||||
delay.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = Number($(this).val());
|
||||
data.entries[uid].delay = !isNaN(value) ? value : null;
|
||||
|
||||
setOriginalDataValue(data, uid, 'extensions.delay', data.entries[uid].delay);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
delay.val(entry.delay > 0 ? entry.delay : '').trigger('input');
|
||||
|
||||
|
@ -2731,14 +2739,14 @@ function getWorldEntry(name, data, entry) {
|
|||
const depthInput = template.find('input[name="depth"]');
|
||||
depthInput.data('uid', entry.uid);
|
||||
|
||||
depthInput.on('input', function () {
|
||||
depthInput.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = Number($(this).val());
|
||||
|
||||
data.entries[uid].depth = !isNaN(value) ? value : 0;
|
||||
updatePosOrdDisplay(uid);
|
||||
setOriginalDataValue(data, uid, 'extensions.depth', data.entries[uid].depth);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
depthInput.val(entry.depth ?? DEFAULT_DEPTH).trigger('input');
|
||||
depthInput.css('width', 'calc(3em + 15px)');
|
||||
|
@ -2750,7 +2758,7 @@ function getWorldEntry(name, data, entry) {
|
|||
|
||||
const probabilityInput = template.find('input[name="probability"]');
|
||||
probabilityInput.data('uid', entry.uid);
|
||||
probabilityInput.on('input', function () {
|
||||
probabilityInput.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = Number($(this).val());
|
||||
|
||||
|
@ -2766,7 +2774,7 @@ function getWorldEntry(name, data, entry) {
|
|||
}
|
||||
|
||||
setOriginalDataValue(data, uid, 'extensions.probability', data.entries[uid].probability);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
probabilityInput.val(entry.probability).trigger('input');
|
||||
probabilityInput.css('width', 'calc(3em + 15px)');
|
||||
|
@ -2778,14 +2786,14 @@ function getWorldEntry(name, data, entry) {
|
|||
|
||||
const probabilityToggle = template.find('input[name="useProbability"]');
|
||||
probabilityToggle.data('uid', entry.uid);
|
||||
probabilityToggle.on('input', function () {
|
||||
probabilityToggle.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).prop('checked');
|
||||
data.entries[uid].useProbability = value;
|
||||
const probabilityContainer = $(this)
|
||||
.closest('.world_entry')
|
||||
.find('.probabilityContainer');
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
value ? probabilityContainer.show() : probabilityContainer.hide();
|
||||
|
||||
if (value && data.entries[uid].probability === null) {
|
||||
|
@ -2814,7 +2822,7 @@ function getWorldEntry(name, data, entry) {
|
|||
// Prevent closing the drawer on clicking the input
|
||||
event.stopPropagation();
|
||||
});
|
||||
positionInput.on('input', function () {
|
||||
positionInput.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = Number($(this).val());
|
||||
data.entries[uid].position = !isNaN(value) ? value : 0;
|
||||
|
@ -2836,7 +2844,7 @@ function getWorldEntry(name, data, entry) {
|
|||
// 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);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
|
||||
const roleValue = entry.position === world_info_position.atDepth ? String(entry.role ?? extension_prompt_roles.SYSTEM) : '';
|
||||
|
@ -2852,12 +2860,12 @@ function getWorldEntry(name, data, entry) {
|
|||
/*
|
||||
const disableInput = template.find('input[name="disable"]');
|
||||
disableInput.data("uid", entry.uid);
|
||||
disableInput.on("input", function () {
|
||||
disableInput.on("input", async function () {
|
||||
const uid = $(this).data("uid");
|
||||
const value = $(this).prop("checked");
|
||||
data.entries[uid].disable = value;
|
||||
setOriginalDataValue(data, uid, "enabled", !data.entries[uid].disable);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
disableInput.prop("checked", entry.disable).trigger("input");
|
||||
*/
|
||||
|
@ -2869,7 +2877,7 @@ function getWorldEntry(name, data, entry) {
|
|||
// Prevent closing the drawer on clicking the input
|
||||
event.stopPropagation();
|
||||
});
|
||||
entryStateSelector.on('input', function () {
|
||||
entryStateSelector.on('input', async function () {
|
||||
const uid = entry.uid;
|
||||
const value = $(this).val();
|
||||
switch (value) {
|
||||
|
@ -2910,7 +2918,7 @@ function getWorldEntry(name, data, entry) {
|
|||
template.addClass('disabledWIEntry');
|
||||
break;
|
||||
}
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
|
||||
});
|
||||
|
||||
|
@ -2930,52 +2938,50 @@ function getWorldEntry(name, data, entry) {
|
|||
.prop('selected', true)
|
||||
.trigger('input');
|
||||
|
||||
saveWorldInfo(name, data);
|
||||
|
||||
// exclude recursion
|
||||
const excludeRecursionInput = template.find('input[name="exclude_recursion"]');
|
||||
excludeRecursionInput.data('uid', entry.uid);
|
||||
excludeRecursionInput.on('input', function () {
|
||||
excludeRecursionInput.on('input', async function () {
|
||||
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);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
excludeRecursionInput.prop('checked', entry.excludeRecursion).trigger('input');
|
||||
|
||||
// prevent recursion
|
||||
const preventRecursionInput = template.find('input[name="prevent_recursion"]');
|
||||
preventRecursionInput.data('uid', entry.uid);
|
||||
preventRecursionInput.on('input', function () {
|
||||
preventRecursionInput.on('input', async function () {
|
||||
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);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
preventRecursionInput.prop('checked', entry.preventRecursion).trigger('input');
|
||||
|
||||
// delay until recursion
|
||||
const delayUntilRecursionInput = template.find('input[name="delay_until_recursion"]');
|
||||
delayUntilRecursionInput.data('uid', entry.uid);
|
||||
delayUntilRecursionInput.on('input', function () {
|
||||
delayUntilRecursionInput.on('input', async function () {
|
||||
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);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
delayUntilRecursionInput.prop('checked', entry.delayUntilRecursion).trigger('input');
|
||||
|
||||
// duplicate button
|
||||
const duplicateButton = template.find('.duplicate_entry_button');
|
||||
duplicateButton.data('uid', entry.uid);
|
||||
duplicateButton.on('click', function () {
|
||||
duplicateButton.on('click', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const entry = duplicateWorldInfoEntry(data, uid);
|
||||
if (entry) {
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
updateEditor(entry.uid);
|
||||
}
|
||||
});
|
||||
|
@ -2983,18 +2989,18 @@ function getWorldEntry(name, data, entry) {
|
|||
// delete button
|
||||
const deleteButton = template.find('.delete_entry_button');
|
||||
deleteButton.data('uid', entry.uid);
|
||||
deleteButton.on('click', function () {
|
||||
deleteButton.on('click', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
deleteWorldInfoEntry(data, uid);
|
||||
deleteOriginalDataValue(data, uid);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
updateEditor(navigation_option.previous);
|
||||
});
|
||||
|
||||
// scan depth
|
||||
const scanDepthInput = template.find('input[name="scanDepth"]');
|
||||
scanDepthInput.data('uid', entry.uid);
|
||||
scanDepthInput.on('input', function () {
|
||||
scanDepthInput.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const isEmpty = $(this).val() === '';
|
||||
const value = Number($(this).val());
|
||||
|
@ -3014,59 +3020,59 @@ 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);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
scanDepthInput.val(entry.scanDepth ?? null).trigger('input');
|
||||
|
||||
// case sensitive select
|
||||
const caseSensitiveSelect = template.find('select[name="caseSensitive"]');
|
||||
caseSensitiveSelect.data('uid', entry.uid);
|
||||
caseSensitiveSelect.on('input', function () {
|
||||
caseSensitiveSelect.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).val();
|
||||
|
||||
data.entries[uid].caseSensitive = value === 'null' ? null : value === 'true';
|
||||
setOriginalDataValue(data, uid, 'extensions.case_sensitive', data.entries[uid].caseSensitive);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
caseSensitiveSelect.val((entry.caseSensitive === null || entry.caseSensitive === undefined) ? 'null' : entry.caseSensitive ? 'true' : 'false').trigger('input');
|
||||
|
||||
// match whole words select
|
||||
const matchWholeWordsSelect = template.find('select[name="matchWholeWords"]');
|
||||
matchWholeWordsSelect.data('uid', entry.uid);
|
||||
matchWholeWordsSelect.on('input', function () {
|
||||
matchWholeWordsSelect.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).val();
|
||||
|
||||
data.entries[uid].matchWholeWords = value === 'null' ? null : value === 'true';
|
||||
setOriginalDataValue(data, uid, 'extensions.match_whole_words', data.entries[uid].matchWholeWords);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
matchWholeWordsSelect.val((entry.matchWholeWords === null || entry.matchWholeWords === undefined) ? 'null' : entry.matchWholeWords ? 'true' : 'false').trigger('input');
|
||||
|
||||
// use group scoring select
|
||||
const useGroupScoringSelect = template.find('select[name="useGroupScoring"]');
|
||||
useGroupScoringSelect.data('uid', entry.uid);
|
||||
useGroupScoringSelect.on('input', function () {
|
||||
useGroupScoringSelect.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).val();
|
||||
|
||||
data.entries[uid].useGroupScoring = value === 'null' ? null : value === 'true';
|
||||
setOriginalDataValue(data, uid, 'extensions.use_group_scoring', data.entries[uid].useGroupScoring);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
useGroupScoringSelect.val((entry.useGroupScoring === null || entry.useGroupScoring === undefined) ? 'null' : entry.useGroupScoring ? 'true' : 'false').trigger('input');
|
||||
|
||||
// automation id
|
||||
const automationIdInput = template.find('input[name="automationId"]');
|
||||
automationIdInput.data('uid', entry.uid);
|
||||
automationIdInput.on('input', function () {
|
||||
automationIdInput.on('input', async function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).val();
|
||||
|
||||
data.entries[uid].automationId = value;
|
||||
setOriginalDataValue(data, uid, 'extensions.automation_id', data.entries[uid].automationId);
|
||||
saveWorldInfo(name, data);
|
||||
await saveWorldInfo(name, data);
|
||||
});
|
||||
automationIdInput.val(entry.automationId ?? '').trigger('input');
|
||||
setTimeout(() => createEntryInputAutocomplete(automationIdInput, getAutomationIdCallback(data)), 1);
|
||||
|
@ -3301,6 +3307,9 @@ function createWorldInfoEntry(_name, data) {
|
|||
}
|
||||
|
||||
async function _save(name, data) {
|
||||
// Prevent double saving if both immediate and debounced save are called
|
||||
cancelDebounce(saveWorldDebounced);
|
||||
|
||||
await fetch('/api/worldinfo/edit', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
|
@ -3309,12 +3318,13 @@ async function _save(name, data) {
|
|||
eventSource.emit(event_types.WORLDINFO_UPDATED, name, data);
|
||||
}
|
||||
|
||||
async function saveWorldInfo(name, data, immediately) {
|
||||
async function saveWorldInfo(name, data, immediately = false) {
|
||||
if (!name || !data) {
|
||||
return;
|
||||
}
|
||||
|
||||
worldInfoCache.delete(name);
|
||||
// Update cache immediately, so any future call can pull from this
|
||||
worldInfoCache.set(name, data);
|
||||
|
||||
if (immediately) {
|
||||
return await _save(name, data);
|
||||
|
|
Loading…
Reference in New Issue