Add MVP set of WI manipulation commands
This commit is contained in:
parent
4e634f00ec
commit
fe355c5d4f
|
@ -95,6 +95,10 @@ function decrementGlobalVariable(name) {
|
||||||
* @returns {string} Variable value or the string literal
|
* @returns {string} Variable value or the string literal
|
||||||
*/
|
*/
|
||||||
export function resolveVariable(name) {
|
export function resolveVariable(name) {
|
||||||
|
if (name === undefined) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
if (existsLocalVariable(name)) {
|
if (existsLocalVariable(name)) {
|
||||||
return getLocalVariable(name);
|
return getLocalVariable(name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { FILTER_TYPES, FilterHelper } from "./filters.js";
|
||||||
import { getTokenCount } from "./tokenizers.js";
|
import { getTokenCount } from "./tokenizers.js";
|
||||||
import { power_user } from "./power-user.js";
|
import { power_user } from "./power-user.js";
|
||||||
import { getTagKeyForCharacter } from "./tags.js";
|
import { getTagKeyForCharacter } from "./tags.js";
|
||||||
|
import { resolveVariable } from "./variables.js";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
world_info,
|
world_info,
|
||||||
|
@ -189,6 +190,149 @@ function setWorldInfoSettings(settings, data) {
|
||||||
const hasWorldInfo = !!chat_metadata[METADATA_KEY] && world_names.includes(chat_metadata[METADATA_KEY]);
|
const hasWorldInfo = !!chat_metadata[METADATA_KEY] && world_names.includes(chat_metadata[METADATA_KEY]);
|
||||||
$('.chat_lorebook_button').toggleClass('world_set', hasWorldInfo);
|
$('.chat_lorebook_button').toggleClass('world_set', hasWorldInfo);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add slash commands
|
||||||
|
registerWorldInfoSlashCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerWorldInfoSlashCommands() {
|
||||||
|
async function getEntriesFromFile(file) {
|
||||||
|
if (!file || !world_names.includes(file)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await loadWorldInfoData(file);
|
||||||
|
|
||||||
|
if (!data || !("entries" in data)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const entries = Object.values(data.entries);
|
||||||
|
|
||||||
|
if (!entries || entries.length === 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getChatBookCallback() {
|
||||||
|
const chatId = getCurrentChatId();
|
||||||
|
|
||||||
|
if (!chatId) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chat_metadata[METADATA_KEY] && world_names.includes(chat_metadata[METADATA_KEY])) {
|
||||||
|
return chat_metadata[METADATA_KEY];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace non-alphanumeric characters with underscores, cut to 64 characters
|
||||||
|
const name = `Chat Book ${getCurrentChatId()}`.replace(/[^a-z0-9]/gi, '_').replace(/_{2,}/g, '_').substring(0, 64);
|
||||||
|
await createNewWorldInfo(name);
|
||||||
|
|
||||||
|
chat_metadata[METADATA_KEY] = name;
|
||||||
|
await saveMetadata();
|
||||||
|
$('.chat_lorebook_button').addClass('world_set');
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findBookEntryCallback(args, value) {
|
||||||
|
const file = resolveVariable(args.file);
|
||||||
|
const field = args.field || 'key';
|
||||||
|
|
||||||
|
const entries = await getEntriesFromFile(file);
|
||||||
|
|
||||||
|
if (!entries) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const fuse = new Fuse(entries, {
|
||||||
|
keys: [{ name: field, weight: 1 }],
|
||||||
|
includeScore: true,
|
||||||
|
threshold: 0.3,
|
||||||
|
});
|
||||||
|
|
||||||
|
const results = fuse.search(value);
|
||||||
|
|
||||||
|
if (!results || results.length === 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = results[0]?.item?.uid;
|
||||||
|
|
||||||
|
if (result === undefined) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getEntryFieldCallback(args, uid) {
|
||||||
|
const file = resolveVariable(args.file);
|
||||||
|
const field = args.field || 'content';
|
||||||
|
|
||||||
|
const entries = await getEntriesFromFile(file);
|
||||||
|
|
||||||
|
if (!entries) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const entry = entries.find(x => x.uid === uid);
|
||||||
|
|
||||||
|
if (!entry) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const fieldValue = entry[field];
|
||||||
|
|
||||||
|
if (fieldValue === undefined) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(fieldValue)) {
|
||||||
|
return fieldValue.map(x => substituteParams(x)).join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return substituteParams(fieldValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createEntryCallback(args, content) {
|
||||||
|
const file = resolveVariable(args.file);
|
||||||
|
const key = args.key;
|
||||||
|
|
||||||
|
const data = await loadWorldInfoData(file);
|
||||||
|
|
||||||
|
if (!data || !("entries" in data)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const entry = createWorldInfoEntry(file, data, true);
|
||||||
|
|
||||||
|
if (key) {
|
||||||
|
entry.key.push(key);
|
||||||
|
entry.addMemo = true;
|
||||||
|
entry.comment = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content) {
|
||||||
|
entry.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
await saveWorldInfo(file, data, true);
|
||||||
|
|
||||||
|
const selectedIndex = world_names.indexOf(file);
|
||||||
|
if (selectedIndex !== -1) {
|
||||||
|
$('#world_editor_select').val(selectedIndex).trigger('change');
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry.uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerSlashCommand('getchatbook', getChatBookCallback, ['getchatlore', 'getchatwi'], '– get a name of the chat-bound lorebook or create a new one if was unbound, and pass it down the pipe', true, true);
|
||||||
|
registerSlashCommand('findentry', findBookEntryCallback, ['findlore', 'findwi'], `<span class="monospace">(file=bookName by=field [texts])</span> – find a UID of the record from the specified book using the fuzzy match of a field value (default: key) and pass it down the pipe, e.g. <tt>/findentry file=chatLore by=key Shadowfang</tt>`, true, true);
|
||||||
|
registerSlashCommand('getentryfield', getEntryFieldCallback, ['getlorefield', 'getwifield'], '<span class="monospace">(file=bookName field=field [UID])</span> – get a field value (default: content) of the record with the UID from the specified book and pass it down the pipe, e.g. <tt>/getentryfield file=chatLore field=content 123</tt>', true, true);
|
||||||
|
registerSlashCommand('createentry', createEntryCallback, ['createlore', 'createwi'], '<span class="monospace">(file=bookName key=key [content])</span> – create a new record in the specified book with the key and content (both are optional) and pass the UID down the pipe, e.g. <tt>/createentry file=chatLore key=Shadowfang The sword of the king</tt>', true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// World Info Editor
|
// World Info Editor
|
||||||
|
@ -1134,7 +1278,7 @@ async function deleteWorldInfoEntry(data, uid) {
|
||||||
delete data.entries[uid];
|
delete data.entries[uid];
|
||||||
}
|
}
|
||||||
|
|
||||||
function createWorldInfoEntry(name, data) {
|
function createWorldInfoEntry(name, data, fromSlashCommand = false) {
|
||||||
const newEntryTemplate = {
|
const newEntryTemplate = {
|
||||||
key: [],
|
key: [],
|
||||||
keysecondary: [],
|
keysecondary: [],
|
||||||
|
@ -1161,7 +1305,11 @@ function createWorldInfoEntry(name, data) {
|
||||||
const newEntry = { uid: newUid, ...newEntryTemplate };
|
const newEntry = { uid: newUid, ...newEntryTemplate };
|
||||||
data.entries[newUid] = newEntry;
|
data.entries[newUid] = newEntry;
|
||||||
|
|
||||||
updateEditor(newUid);
|
if (!fromSlashCommand) {
|
||||||
|
updateEditor(newUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _save(name, data) {
|
async function _save(name, data) {
|
||||||
|
|
Loading…
Reference in New Issue