mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
#1226 Add chat-bound lorebooks
This commit is contained in:
@ -3428,6 +3428,7 @@
|
|||||||
<input type="hidden" id="fav_checkbox" name="fav" />
|
<input type="hidden" id="fav_checkbox" name="fav" />
|
||||||
<div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions" data-i18n="[title]Advanced Definition"></div>
|
<div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions" data-i18n="[title]Advanced Definition"></div>
|
||||||
<div id="world_button" class="menu_button fa-solid fa-globe" title="Character Lore" data-i18n="[title]Character Lore"></div>
|
<div id="world_button" class="menu_button fa-solid fa-globe" title="Character Lore" data-i18n="[title]Character Lore"></div>
|
||||||
|
<div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore" data-i18n="[title]Chat Lore"></div>
|
||||||
<div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download" data-i18n="[title]Export and Download"></div>
|
<div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download" data-i18n="[title]Export and Download"></div>
|
||||||
<!-- <div id="set_chat_scenario" class="menu_button fa-solid fa-scroll" title="Set a chat scenario override"></div> -->
|
<!-- <div id="set_chat_scenario" class="menu_button fa-solid fa-scroll" title="Set a chat scenario override"></div> -->
|
||||||
<!-- <div id="set_character_world" class="menu_button fa-solid fa-globe" title="Set a character World Info / Lorebook"></div> -->
|
<!-- <div id="set_character_world" class="menu_button fa-solid fa-globe" title="Set a character World Info / Lorebook"></div> -->
|
||||||
@ -3543,8 +3544,11 @@
|
|||||||
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="inline-drawer-content">
|
<div class="inline-drawer-content">
|
||||||
<div name="group-metadata-controls" class="marginTopBot5">
|
<div id="group-metadata-controls" class="marginTopBot5">
|
||||||
<input id="rm_group_chat_name" class="text_pole wide100p" type="text" name="chat_name" data-i18n="[placeholder]Chat Name (Optional)" placeholder="Chat Name (Optional)" maxlength="100" />
|
<div class="flex-container wide100p">
|
||||||
|
<input id="rm_group_chat_name" class="text_pole flex1" type="text" name="chat_name" data-i18n="[placeholder]Chat Name (Optional)" placeholder="Chat Name (Optional)" maxlength="100" />
|
||||||
|
<div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore" data-i18n="[title]Chat Lore"></div>
|
||||||
|
</div>
|
||||||
<div id="group_tags_div" class="wide100p">
|
<div id="group_tags_div" class="wide100p">
|
||||||
<div class="tag_controls">
|
<div class="tag_controls">
|
||||||
<input id="groupTagInput" class="text_pole tag_input flex1 margin0" data-i18n="[placeholder]Search / Create Tags" placeholder="Search / Create tags" maxlength="25" />
|
<input id="groupTagInput" class="text_pole tag_input flex1 margin0" data-i18n="[placeholder]Search / Create Tags" placeholder="Search / Create tags" maxlength="25" />
|
||||||
@ -3896,6 +3900,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="chat_world_template" class="template_element">
|
||||||
|
<div class="chat_world range-block flexFlowColumn flex-container">
|
||||||
|
<div class="range-block-title">
|
||||||
|
<h4 data-i18n="Chat Lorebook">Chat Lorebook for <span class="chat_name"></span></h4>
|
||||||
|
</div>
|
||||||
|
<div class="range-block-counter justifyLeft flex-container flexFlowColumn margin-bot-10px">
|
||||||
|
<span data-i18n="A selected World Info will be bound to this chat.">
|
||||||
|
A selected World Info will be bound to this chat. When generating an AI reply,
|
||||||
|
it will be combined with the entries from global and character lorebooks.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="range-block-range wide100p">
|
||||||
|
<select class="chat_world_info_selector wide100p">
|
||||||
|
<option value="">--- None ---</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="character_world_template" class="template_element">
|
<div id="character_world_template" class="template_element">
|
||||||
<div class="character_world range-block flexFlowColumn flex-container">
|
<div class="character_world range-block flexFlowColumn flex-container">
|
||||||
<div class="range-block-title">
|
<div class="range-block-title">
|
||||||
|
@ -5729,6 +5729,7 @@ export function select_selected_character(chid) {
|
|||||||
checkEmbeddedWorld(chid);
|
checkEmbeddedWorld(chid);
|
||||||
|
|
||||||
$("#form_create").attr("actiontype", "editcharacter");
|
$("#form_create").attr("actiontype", "editcharacter");
|
||||||
|
$('.form_create_bottom_buttons_block .chat_lorebook_button').show();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5787,6 +5788,7 @@ function select_rm_create() {
|
|||||||
checkEmbeddedWorld();
|
checkEmbeddedWorld();
|
||||||
|
|
||||||
$("#form_create").attr("actiontype", "createcharacter");
|
$("#form_create").attr("actiontype", "createcharacter");
|
||||||
|
$('.form_create_bottom_buttons_block .chat_lorebook_button').hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
function select_rm_characters() {
|
function select_rm_characters() {
|
||||||
|
@ -1110,6 +1110,7 @@ function select_group_chats(groupId, skipAnimation) {
|
|||||||
$("#rm_group_submit").hide();
|
$("#rm_group_submit").hide();
|
||||||
$("#rm_group_delete").show();
|
$("#rm_group_delete").show();
|
||||||
$("#rm_group_scenario").show();
|
$("#rm_group_scenario").show();
|
||||||
|
$('#group-metadata-controls .chat_lorebook_button').removeClass('disabled').prop('disabled', false);
|
||||||
} else {
|
} else {
|
||||||
$("#rm_group_submit").show();
|
$("#rm_group_submit").show();
|
||||||
if ($("#groupAddMemberListToggle .inline-drawer-content").css('display') !== 'block') {
|
if ($("#groupAddMemberListToggle .inline-drawer-content").css('display') !== 'block') {
|
||||||
@ -1117,6 +1118,7 @@ function select_group_chats(groupId, skipAnimation) {
|
|||||||
}
|
}
|
||||||
$("#rm_group_delete").hide();
|
$("#rm_group_delete").hide();
|
||||||
$("#rm_group_scenario").hide();
|
$("#rm_group_scenario").hide();
|
||||||
|
$('#group-metadata-controls .chat_lorebook_button').addClass('disabled').prop('disabled', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFavButtonState(group?.fav ?? false);
|
updateFavButtonState(group?.fav ?? false);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { saveSettings, callPopup, substituteParams, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types, getExtensionPrompt, MAX_INJECTION_DEPTH, extension_prompt_types, getExtensionPromptByName } from "../script.js";
|
import { saveSettings, callPopup, substituteParams, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types, getExtensionPrompt, MAX_INJECTION_DEPTH, extension_prompt_types, getExtensionPromptByName, saveMetadata, getCurrentChatId } from "../script.js";
|
||||||
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition } from "./utils.js";
|
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition } from "./utils.js";
|
||||||
import { extension_settings, getContext } from "./extensions.js";
|
import { extension_settings, getContext } from "./extensions.js";
|
||||||
import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from "./authors-note.js";
|
import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from "./authors-note.js";
|
||||||
@ -53,6 +53,7 @@ let updateEditor = (navigation) => { navigation; };
|
|||||||
// 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());
|
const worldInfoFilter = new FilterHelper(() => updateEditor());
|
||||||
const SORT_ORDER_KEY = 'world_info_sort_order';
|
const SORT_ORDER_KEY = 'world_info_sort_order';
|
||||||
|
const METADATA_KEY = 'world_info';
|
||||||
|
|
||||||
const InputWidthReference = $("#WIInputWidthReference");
|
const InputWidthReference = $("#WIInputWidthReference");
|
||||||
|
|
||||||
@ -167,6 +168,11 @@ function setWorldInfoSettings(settings, data) {
|
|||||||
|
|
||||||
$('#world_info_sort_order').val(localStorage.getItem(SORT_ORDER_KEY) || '0');
|
$('#world_info_sort_order').val(localStorage.getItem(SORT_ORDER_KEY) || '0');
|
||||||
$("#world_editor_select").trigger("change");
|
$("#world_editor_select").trigger("change");
|
||||||
|
|
||||||
|
eventSource.on(event_types.CHAT_CHANGED, () => {
|
||||||
|
const hasWorldInfo = !!chat_metadata[METADATA_KEY] && world_names.includes(chat_metadata[METADATA_KEY]);
|
||||||
|
$('.chat_lorebook_button').toggleClass('world_set', hasWorldInfo);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// World Info Editor
|
// World Info Editor
|
||||||
@ -1301,10 +1307,26 @@ async function getGlobalLore() {
|
|||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getChatLore() {
|
||||||
|
const chatWorld = chat_metadata[METADATA_KEY];
|
||||||
|
|
||||||
|
if (!chatWorld) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await loadWorldInfoData(chatWorld);
|
||||||
|
const entries = data ? Object.keys(data.entries).map((x) => data.entries[x]) : [];
|
||||||
|
|
||||||
|
console.debug(`Chat lore has ${entries.length} entries`);
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
async function getSortedEntries() {
|
async function getSortedEntries() {
|
||||||
try {
|
try {
|
||||||
const globalLore = await getGlobalLore();
|
const globalLore = await getGlobalLore();
|
||||||
const characterLore = await getCharacterLore();
|
const characterLore = await getCharacterLore();
|
||||||
|
const chatLore = await getChatLore();
|
||||||
|
|
||||||
let entries;
|
let entries;
|
||||||
|
|
||||||
@ -1327,6 +1349,9 @@ async function getSortedEntries() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Chat lore always goes first
|
||||||
|
entries = [...chatLore.sort(sortFn), ...entries];
|
||||||
|
|
||||||
console.debug(`Sorted ${entries.length} world lore entries using strategy ${world_info_character_strategy}`);
|
console.debug(`Sorted ${entries.length} world lore entries using strategy ${world_info_character_strategy}`);
|
||||||
|
|
||||||
// Need to deep clone the entries to avoid modifying the cached data
|
// Need to deep clone the entries to avoid modifying the cached data
|
||||||
@ -1911,6 +1936,39 @@ export async function importWorldInfo(file) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function assignLorebookToChat() {
|
||||||
|
const selectedName = chat_metadata[METADATA_KEY];
|
||||||
|
const template = $('#chat_world_template .chat_world').clone();
|
||||||
|
|
||||||
|
const worldSelect = template.find('select');
|
||||||
|
const chatName = template.find('.chat_name');
|
||||||
|
chatName.text(getCurrentChatId());
|
||||||
|
|
||||||
|
for (const worldName of world_names) {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = worldName;
|
||||||
|
option.innerText = worldName;
|
||||||
|
option.selected = selectedName === worldName;
|
||||||
|
worldSelect.append(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
worldSelect.on('change', function () {
|
||||||
|
const worldName = $(this).val();
|
||||||
|
|
||||||
|
if (worldName) {
|
||||||
|
chat_metadata[METADATA_KEY] = worldName;
|
||||||
|
$('.chat_lorebook_button').addClass('world_set');
|
||||||
|
} else {
|
||||||
|
delete chat_metadata[METADATA_KEY];
|
||||||
|
$('.chat_lorebook_button').removeClass('world_set');
|
||||||
|
}
|
||||||
|
|
||||||
|
saveMetadata();
|
||||||
|
});
|
||||||
|
|
||||||
|
callPopup(template, 'text');
|
||||||
|
}
|
||||||
|
|
||||||
jQuery(() => {
|
jQuery(() => {
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
@ -2051,6 +2109,8 @@ jQuery(() => {
|
|||||||
updateEditor(navigation_option.none);
|
updateEditor(navigation_option.none);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$(document).on('click', '.chat_lorebook_button', assignLorebookToChat);
|
||||||
|
|
||||||
// Not needed on mobile
|
// Not needed on mobile
|
||||||
const deviceInfo = getDeviceInfo();
|
const deviceInfo = getDeviceInfo();
|
||||||
if (deviceInfo && deviceInfo.device.type === 'desktop') {
|
if (deviceInfo && deviceInfo.device.type === 'desktop') {
|
||||||
|
@ -1316,7 +1316,7 @@ select option:not(:checked) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.menu_button.disabled {
|
.menu_button.disabled {
|
||||||
filter: brightness(50%);
|
filter: brightness(75%) grayscale(1);
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1911,10 +1911,10 @@ grammarly-extension {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
height: 32px;
|
height: 26px;
|
||||||
filter: grayscale(0.5);
|
filter: grayscale(0.5);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 20px;
|
font-size: 17px;
|
||||||
aspect-ratio: 1 / 1;
|
aspect-ratio: 1 / 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2307,7 +2307,7 @@ input[type="range"]::-webkit-slider-thumb {
|
|||||||
|
|
||||||
#char-management-dropdown,
|
#char-management-dropdown,
|
||||||
#tagInput {
|
#tagInput {
|
||||||
height: 32px;
|
height: 26px;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1811,15 +1811,18 @@ function convertWorldInfoToCharacterBook(name, entries) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readWorldInfoFile(worldInfoName) {
|
function readWorldInfoFile(worldInfoName) {
|
||||||
|
const dummyObject = { entries: {} };
|
||||||
|
|
||||||
if (!worldInfoName) {
|
if (!worldInfoName) {
|
||||||
return { entries: {} };
|
return dummyObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filename = `${worldInfoName}.json`;
|
const filename = `${worldInfoName}.json`;
|
||||||
const pathToWorldInfo = path.join(DIRECTORIES.worlds, filename);
|
const pathToWorldInfo = path.join(DIRECTORIES.worlds, filename);
|
||||||
|
|
||||||
if (!fs.existsSync(pathToWorldInfo)) {
|
if (!fs.existsSync(pathToWorldInfo)) {
|
||||||
throw new Error(`World info file ${filename} doesn't exist.`);
|
console.log(`World info file ${filename} doesn't exist.`);
|
||||||
|
return dummyObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
const worldInfoText = fs.readFileSync(pathToWorldInfo, 'utf8');
|
const worldInfoText = fs.readFileSync(pathToWorldInfo, 'utf8');
|
||||||
|
Reference in New Issue
Block a user