(WIP) Assign World Info to a character. [Out of spec]

This commit is contained in:
Cohee
2023-06-19 01:59:09 +03:00
parent 81d9cead5c
commit 7e975e9df0
5 changed files with 285 additions and 98 deletions

View File

@ -1835,7 +1835,7 @@
</div> </div>
<div id="wi-holder" class="margin5"> <div id="wi-holder" class="margin5">
<h3> <h3>
World Selector Global World Info / Lorebook Selector
<a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/" class="notes-link" target="_blank"> <a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/" class="notes-link" target="_blank">
<span class="note-link-span">?</span> <span class="note-link-span">?</span>
</a> </a>
@ -1853,7 +1853,7 @@
<div id="world_info_edit_button" class="menu_button fa-solid fa-pencil faSmallFontSquareFix" title="Details"></div> <div id="world_info_edit_button" class="menu_button fa-solid fa-pencil faSmallFontSquareFix" title="Details"></div>
</div> </div>
<div class="flex-container alignitemscenter"> <div class="flex-container gap10px alignitemscenter">
<div name="WIScanAndTokens" class="flex1 flex-container flexFlowColumn"> <div name="WIScanAndTokens" class="flex1 flex-container flexFlowColumn">
<div class="flex1 gap5px range-block"> <div class="flex1 gap5px range-block">
<div class="wide10pMinFit"> <div class="wide10pMinFit">
@ -1887,6 +1887,18 @@
</div> </div>
</div> </div>
</div> </div>
<div class="flex1 flex-container flexFlowColumn">
<div class="flex gap5px range-block">
<label for="world_info_character_strategy">
Character Lore Insertion Strategy
</label>
<select id="world_info_character_strategy" class="flexGrow">
<option value="0">Sorted Evenly</option>
<option value="1">Character Lore First</option>
<option value="2">Global Lore First</option>
</select>
</div>
</div>
<div class="range-block flex-container flexFlowColumn"> <div class="range-block flex-container flexFlowColumn">
<label title="Entries can activate other entries by mentioning their keywords" class="checkbox_label"> <label title="Entries can activate other entries by mentioning their keywords" class="checkbox_label">
<input id="world_info_recursive" type="checkbox" /> <input id="world_info_recursive" type="checkbox" />
@ -1919,18 +1931,18 @@
<a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/#world-info-entry" class="notes-link" target="_blank"><span class="note-link-span">?</span></a> <a href="https://docs.sillytavern.app/usage/core-concepts/worldinfo/#world-info-entry" class="notes-link" target="_blank"><span class="note-link-span">?</span></a>
</h3> </h3>
</div> </div>
<div id="OpenAllWIEntries" class="menu_button fa-solid fa-expand"></div> <div id="OpenAllWIEntries" class="menu_button fa-solid fa-expand" title="Open all Entries"></div>
<div id="CloseAllWIEntries" class="menu_button fa-solid fa-compress"></div> <div id="CloseAllWIEntries" class="menu_button fa-solid fa-compress" title="Close all Entries"></div>
<div class="flex-container"> <div class="flex-container">
<form id="form_rename_world" action="javascript:void(null);" method="post" enctype="multipart/form-data"> <form id="form_rename_world" action="javascript:void(null);" method="post" enctype="multipart/form-data">
<input id="world_popup_name" name="world_popup_name" class="text_pole" maxlength="99" size="32" value="" autocomplete="off"> <input id="world_popup_name" name="world_popup_name" class="text_pole" maxlength="99" size="32" value="" autocomplete="off">
<label for="world_popup_name_button" class="menu_button fa-solid fa-pencil faSmallFontSquareFix"> <label for="world_popup_name_button" class="menu_button fa-solid fa-pencil faSmallFontSquareFix" title="Rename World Info">
<input id="world_popup_name_button" type="submit" value=""> <input id="world_popup_name_button" type="submit" value="">
</label> </label>
<div id="world_popup_bottom_holder" class="flex-container"> <div id="world_popup_bottom_holder" class="flex-container">
<div id="world_popup_new" class="menu_button fa-solid fa-plus margin0 faSmallFontSquareFix"></div> <div id="world_popup_new" class="menu_button fa-solid fa-plus margin0 faSmallFontSquareFix" title="New Entry"></div>
<div id="world_popup_export" class="menu_button fa-solid fa-file-export margin0 faSmallFontSquareFix"></div> <div id="world_popup_export" class="menu_button fa-solid fa-file-export margin0 faSmallFontSquareFix" title="Export World Info"></div>
<div id="world_popup_delete" class="menu_button fa-solid fa-trash-can redWarningBG margin0 faSmallFontSquareFix"></div> <div id="world_popup_delete" class="menu_button fa-solid fa-trash-can redWarningBG margin0 faSmallFontSquareFix" title="Delete World Info"></div>
</div> </div>
</form> </form>
@ -2380,6 +2392,7 @@
<div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions"></div> <div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions"></div>
<div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download"></div> <div id="export_button" class="menu_button fa-solid fa-file-export " 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="dupe_button" class="menu_button fa-solid fa-clone " title="Duplicate Character"></div> <div id="dupe_button" class="menu_button fa-solid fa-clone " title="Duplicate Character"></div>
<label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character"> <label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character">
<input type="submit" id="create_button" name="create_button"> <input type="submit" id="create_button" name="create_button">
@ -2430,6 +2443,7 @@
<input id="selected_chat_pole" name="chat" type="hidden"> <input id="selected_chat_pole" name="chat" type="hidden">
<input id="create_date_pole" name="create_date" type="hidden"> <input id="create_date_pole" name="create_date" type="hidden">
<input id="last_mes_pole" name="last_mes" type="hidden"> <input id="last_mes_pole" name="last_mes" type="hidden">
<input id="character_world" name="world" type="hidden">
</div> </div>
<!-- now back to normal divs for display purposes--> <!-- now back to normal divs for display purposes-->
@ -2783,6 +2797,27 @@
</div> </div>
</div> </div>
<div id="character_world_template" class="template_element">
<div class="character_world range-block flexFlowColumn flex-container">
<div class="range-block-title">
<h3>
Select a World Info file for <span class="character_name"></span>:
</h3>
</div>
<div class="range-block-counter justifyLeft flex-container flexFlowColumn margin-bot-10px">
A selected World Info / Lorebook will be bound to this character.
When generating an AI reply, it will be combined with the entries from a global World Info / Lorebook selector.
<!-- Telling lies? Uncomment when actually implemented. -->
<!-- Exporting a character would also export the selected World Info file embedded in the JSON data. -->
</div>
<div class="range-block-range wide100p">
<select class="character_world_info_selector">
<option value="">--- None ---</option>
</select>
</div>
</div>
</div>
<div id="past_chat_template" class="template_element"> <div id="past_chat_template" class="template_element">
<div class="select_chat_block_wrapper"> <div class="select_chat_block_wrapper">
<div class="select_chat_block" file_name=""> <div class="select_chat_block" file_name="">

View File

@ -30,6 +30,8 @@ import {
world_info_recursive, world_info_recursive,
world_info_case_sensitive, world_info_case_sensitive,
world_info_match_whole_words, world_info_match_whole_words,
world_names,
world_info_character_strategy,
} from "./scripts/world-info.js"; } from "./scripts/world-info.js";
import { import {
@ -566,21 +568,24 @@ var is_advanced_char_open = false;
var menu_type = ""; //what is selected in the menu var menu_type = ""; //what is selected in the menu
var selected_button = ""; //which button pressed var selected_button = ""; //which button pressed
//create pole save //create pole save
let create_save_name = ""; let create_save = {
let create_save_description = ""; name: "",
let create_save_creator_notes = ""; description: "",
let create_save_post_history_instructions = ""; creator_notes: "",
let create_save_character_version = ""; post_history_instructions: "",
let create_save_system_prompt = ""; character_version: "",
let create_save_tags = ""; system_prompt: "",
let create_save_creator = ""; tags: "",
let create_save_personality = ""; creator: "",
let create_save_first_message = ""; personality: "",
let create_save_avatar = ""; first_message: "",
let create_save_scenario = ""; avatar: "",
let create_save_mes_example = ""; scenario: "",
let create_save_talkativeness = talkativeness_default; mes_example: "",
let create_save_alternate_greetings = []; world: "",
talkativeness: talkativeness_default,
alternate_greetings: []
};
//animation right menu //animation right menu
let animation_duration = 250; let animation_duration = 250;
@ -2014,7 +2019,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
// Extension added strings // Extension added strings
//WI moved to top in order to allow it to hijack AN if necessary //WI moved to top in order to allow it to hijack AN if necessary
let { worldInfoString, worldInfoBefore, worldInfoAfter } = getWorldInfoPrompt(chat2); let { worldInfoString, worldInfoBefore, worldInfoAfter } = await getWorldInfoPrompt(chat2);
let allAnchors = getAllExtensionPrompts(); let allAnchors = getAllExtensionPrompts();
const afterScenarioAnchor = getExtensionPrompt(extension_prompt_types.AFTER_SCENARIO); const afterScenarioAnchor = getExtensionPrompt(extension_prompt_types.AFTER_SCENARIO);
let zeroDepthAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, 0, ' '); let zeroDepthAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, 0, ' ');
@ -3615,7 +3620,7 @@ async function saveChat(chat_name, withMetadata) {
async function read_avatar_load(input) { async function read_avatar_load(input) {
if (input.files && input.files[0]) { if (input.files && input.files[0]) {
if (selected_button == "create") { if (selected_button == "create") {
create_save_avatar = input.files; create_save.avatar = input.files;
} }
const e = await new Promise((resolve, reject) => { const e = await new Promise((resolve, reject) => {
@ -4389,6 +4394,7 @@ async function saveSettings(type) {
world_info_recursive: world_info_recursive, world_info_recursive: world_info_recursive,
world_info_case_sensitive: world_info_case_sensitive, world_info_case_sensitive: world_info_case_sensitive,
world_info_match_whole_words: world_info_match_whole_words, world_info_match_whole_words: world_info_match_whole_words,
world_info_character_strategy: world_info_character_strategy,
textgenerationwebui_settings: textgenerationwebui_settings, textgenerationwebui_settings: textgenerationwebui_settings,
swipes: swipes, swipes: swipes,
horde_settings: horde_settings, horde_settings: horde_settings,
@ -4768,6 +4774,7 @@ export function select_selected_character(chid) {
$("#character_popup_text_h3").text(characters[chid].name); $("#character_popup_text_h3").text(characters[chid].name);
$("#character_name_pole").val(characters[chid].name); $("#character_name_pole").val(characters[chid].name);
$("#description_textarea").val(characters[chid].description); $("#description_textarea").val(characters[chid].description);
$("#character_world").val(characters[chid].data?.extensions?.world || '');
$("#creator_notes_textarea").val(characters[chid].data?.creator_notes || characters[chid].creatorcomment); $("#creator_notes_textarea").val(characters[chid].data?.creator_notes || characters[chid].creatorcomment);
$("#character_version_textarea").val(characters[chid].data?.character_version || ''); $("#character_version_textarea").val(characters[chid].data?.character_version || '');
$("#system_prompt_textarea").val(characters[chid].data?.system_prompt || ''); $("#system_prompt_textarea").val(characters[chid].data?.system_prompt || '');
@ -4798,6 +4805,8 @@ export function select_selected_character(chid) {
$("#name_div").addClass('displayNone'); $("#name_div").addClass('displayNone');
$("#renameCharButton").css("display", ""); $("#renameCharButton").css("display", "");
$('.open_alternate_greetings').data('chid', chid); $('.open_alternate_greetings').data('chid', chid);
$('#set_character_world').data('chid', chid);
$('#set_character_world').toggleClass('world_set', !!(characters[chid].data?.extensions?.world));
$("#form_create").attr("actiontype", "editcharacter"); $("#form_create").attr("actiontype", "editcharacter");
saveSettingsDebounced(); saveSettingsDebounced();
@ -4808,8 +4817,8 @@ function select_rm_create() {
//console.log('select_rm_Create() -- selected button: '+selected_button); //console.log('select_rm_Create() -- selected button: '+selected_button);
if (selected_button == "create") { if (selected_button == "create") {
if (create_save_avatar != "") { if (create_save.avatar != "") {
$("#add_avatar_button").get(0).files = create_save_avatar; $("#add_avatar_button").get(0).files = create_save.avatar;
read_avatar_load($("#add_avatar_button").get(0)); read_avatar_load($("#add_avatar_button").get(0));
} }
} }
@ -4830,25 +4839,28 @@ function select_rm_create() {
$("#rm_button_back").css("display", ""); $("#rm_button_back").css("display", "");
$("#character_import_button").css("display", ""); $("#character_import_button").css("display", "");
$("#character_popup_text_h3").text("Create character"); $("#character_popup_text_h3").text("Create character");
$("#character_name_pole").val(create_save_name); $("#character_name_pole").val(create_save.name);
$("#description_textarea").val(create_save_description); $("#description_textarea").val(create_save.description);
$("#creator_notes_textarea").val(create_save_creator_notes); $('#character_world').val(create_save.world);
$("#post_history_instructions_textarea").val(create_save_post_history_instructions); $("#creator_notes_textarea").val(create_save.creator_notes);
$("#system_prompt_textarea").val(create_save_system_prompt); $("#post_history_instructions_textarea").val(create_save.post_history_instructions);
$("#tags_textarea").val(create_save_tags); $("#system_prompt_textarea").val(create_save.system_prompt);
$("#creator_textarea").val(create_save_creator); $("#tags_textarea").val(create_save.tags);
$("#character_version_textarea").val(create_save_character_version); $("#creator_textarea").val(create_save.creator);
$("#personality_textarea").val(create_save_personality); $("#character_version_textarea").val(create_save.character_version);
$("#firstmessage_textarea").val(create_save_first_message); $("#personality_textarea").val(create_save.personality);
$("#talkativeness_slider").val(create_save_talkativeness); $("#firstmessage_textarea").val(create_save.first_message);
$("#scenario_pole").val(create_save_scenario); $("#talkativeness_slider").val(create_save.talkativeness);
$("#mes_example_textarea").val(create_save_mes_example.trim().length === 0 ? '<START>' : create_save_mes_example); $("#scenario_pole").val(create_save.scenario);
$("#mes_example_textarea").val(create_save.mes_example.trim().length === 0 ? '<START>' : create_save.mes_example);
$("#avatar_div").css("display", "flex"); $("#avatar_div").css("display", "flex");
$("#avatar_load_preview").attr("src", default_avatar); $("#avatar_load_preview").attr("src", default_avatar);
$("#renameCharButton").css('display', 'none'); $("#renameCharButton").css('display', 'none');
$("#name_div").removeClass('displayNone'); $("#name_div").removeClass('displayNone');
$("#name_div").addClass('displayBlock'); $("#name_div").addClass('displayBlock');
$('.open_alternate_greetings').data('chid', undefined); $('.open_alternate_greetings').data('chid', undefined);
$('#set_character_world').data('chid', undefined);
$('#set_character_world').toggleClass('world_set', !!create_save.world);
updateFavButtonState(false); updateFavButtonState(false);
$("#form_create").attr("actiontype", "createcharacter"); $("#form_create").attr("actiontype", "createcharacter");
@ -5222,6 +5234,50 @@ function updateAlternateGreetingsHintVisibility(root) {
$(root).find('.alternate_grettings_hint').toggle(numberOfGreetings == 0); $(root).find('.alternate_grettings_hint').toggle(numberOfGreetings == 0);
} }
function openCharacterWorldPopup() {
const chid = $('#set_character_world').data('chid');
if (menu_type != 'create' && chid == undefined) {
toastr.error('Does not have an Id for this character in world select menu.');
return;
}
function onSelectCharacterWorld() {
const value = $(this).find('option:selected').val();
const worldIndex = Number(value);
const name = !isNaN(worldIndex) ? world_names[worldIndex] : '';
$('#character_world').val(name);
console.debug('Character world selected:', name);
if (menu_type == 'create') {
create_save.world = name;
} else {
createOrEditCharacter();
}
$('#set_character_world').toggleClass('world_set', !!value);
}
const name = (menu_type == 'create' ? create_save.name : characters[chid]?.data?.name) || 'Nameless';
const worldId = (menu_type == 'create' ? create_save.world : characters[chid]?.data?.extensions?.world) || '';
const template = $('#character_world_template .character_world').clone();
const select = template.find('.character_world_info_selector');
template.find('.character_name').text(name);
world_names.forEach((item, i) => {
const option = document.createElement('option');
option.value = i;
option.innerText = item;
option.selected = item === worldId;
select.append(option);
});
select.on('change', onSelectCharacterWorld);
callPopup(template, 'text');
}
function openAlternateGreetings() { function openAlternateGreetings() {
const chid = $('.open_alternate_greetings').data('chid'); const chid = $('.open_alternate_greetings').data('chid');
@ -5236,7 +5292,7 @@ function openAlternateGreetings() {
} }
const template = $('#alternate_greetings_template .alternate_grettings').clone(); const template = $('#alternate_greetings_template .alternate_grettings').clone();
const getArray = () => menu_type == 'create' ? create_save_alternate_greetings : characters[chid].data.alternate_greetings; const getArray = () => menu_type == 'create' ? create_save.alternate_greetings : characters[chid].data.alternate_greetings;
for (let index = 0; index < getArray().length; index++) { for (let index = 0; index < getArray().length; index++) {
addAlternateGreeting(template, getArray()[index], index, getArray); addAlternateGreeting(template, getArray()[index], index, getArray);
@ -5275,7 +5331,7 @@ function addAlternateGreeting(template, greeting, index, getArray) {
async function createOrEditCharacter(e) { async function createOrEditCharacter(e) {
$("#rm_info_avatar").html(""); $("#rm_info_avatar").html("");
let save_name = create_save_name; let save_name = create_save.name;
var formData = new FormData($("#form_create").get(0)); var formData = new FormData($("#form_create").get(0));
formData.set('fav', fav_ch_checked); formData.set('fav', fav_ch_checked);
if ($("#form_create").attr("actiontype") == "createcharacter") { if ($("#form_create").attr("actiontype") == "createcharacter") {
@ -5288,7 +5344,7 @@ async function createOrEditCharacter(e) {
} }
formData.delete('alternate_greetings'); formData.delete('alternate_greetings');
for (const value of create_save_alternate_greetings) { for (const value of create_save.alternate_greetings) {
formData.append('alternate_greetings', value); formData.append('alternate_greetings', value);
} }
@ -5306,21 +5362,22 @@ async function createOrEditCharacter(e) {
success: async function (html) { success: async function (html) {
$("#character_cross").trigger('click'); //closes the advanced character editing popup $("#character_cross").trigger('click'); //closes the advanced character editing popup
const fields = [ const fields = [
{ id: '#character_name_pole', callback: value => create_save_name = value }, { id: '#character_name_pole', callback: value => create_save.name = value },
{ id: '#description_textarea', callback: value => create_save_description = value }, { id: '#description_textarea', callback: value => create_save.description = value },
{ id: '#creator_notes_textarea', callback: value => create_save_creator_notes = value }, { id: '#creator_notes_textarea', callback: value => create_save.creator_notes = value },
{ id: '#character_version_textarea', callback: value => create_save_character_version = value }, { id: '#character_version_textarea', callback: value => create_save.character_version = value },
{ id: '#post_history_instructions_textarea', callback: value => create_save_post_history_instructions = value }, { id: '#post_history_instructions_textarea', callback: value => create_save.post_history_instructions = value },
{ id: '#system_prompt_textarea', callback: value => create_save_system_prompt = value }, { id: '#system_prompt_textarea', callback: value => create_save.system_prompt = value },
{ id: '#tags_textarea', callback: value => create_save_tags = value }, { id: '#tags_textarea', callback: value => create_save.tags = value },
{ id: '#creator_textarea', callback: value => create_save_creator = value }, { id: '#creator_textarea', callback: value => create_save.creator = value },
{ id: '#personality_textarea', callback: value => create_save_personality = value }, { id: '#personality_textarea', callback: value => create_save.personality = value },
{ id: '#firstmessage_textarea', callback: value => create_save_first_message = value }, { id: '#firstmessage_textarea', callback: value => create_save.first_message = value },
{ id: '#talkativeness_slider', callback: value => create_save_talkativeness = value, defaultValue: talkativeness_default }, { id: '#talkativeness_slider', callback: value => create_save.talkativeness = value, defaultValue: talkativeness_default },
{ id: '#scenario_pole', callback: value => create_save_scenario = value }, { id: '#scenario_pole', callback: value => create_save.scenario = value },
{ id: '#mes_example_textarea', callback: value => create_save_mes_example = value }, { id: '#mes_example_textarea', callback: value => create_save.mes_example = value },
{ id: '#character_json_data', callback: () => { } }, { id: '#character_json_data', callback: () => { } },
{ id: '#alternate_greetings_template', callback: value => create_save_alternate_greetings = value, defaultValue: [] }, { id: '#alternate_greetings_template', callback: value => create_save.alternate_greetings = value, defaultValue: [] },
{ id: '#character_world', callback: value => create_save.world = value },
]; ];
fields.forEach(field => { fields.forEach(field => {
@ -5331,7 +5388,7 @@ async function createOrEditCharacter(e) {
$("#character_popup_text_h3").text("Create character"); $("#character_popup_text_h3").text("Create character");
create_save_avatar = ""; create_save.avatar = "";
$("#create_button").removeAttr("disabled"); $("#create_button").removeAttr("disabled");
$("#add_avatar_button").replaceWith( $("#add_avatar_button").replaceWith(
@ -6366,23 +6423,23 @@ $(document).ready(function () {
$("#character_name_pole").on("input", function () { $("#character_name_pole").on("input", function () {
if (menu_type == "create") { if (menu_type == "create") {
create_save_name = $("#character_name_pole").val(); create_save.name = $("#character_name_pole").val();
} }
}); });
const elementsToUpdate = { const elementsToUpdate = {
'#description_textarea': function () { create_save_description = $("#description_textarea").val(); }, '#description_textarea': function () { create_save.description = $("#description_textarea").val(); },
'#creator_notes_textarea': function () { create_save_creator_notes = $("#creator_notes_textarea").val(); }, '#creator_notes_textarea': function () { create_save.creator_notes = $("#creator_notes_textarea").val(); },
'#character_version_textarea': function () { create_save_character_version = $("#character_version_textarea").val(); }, '#character_version_textarea': function () { create_save.character_version = $("#character_version_textarea").val(); },
'#system_prompt_textarea': function () { create_save_system_prompt = $("#system_prompt_textarea").val(); }, '#system_prompt_textarea': function () { create_save.system_prompt = $("#system_prompt_textarea").val(); },
'#post_history_instructions_textarea': function () { create_save_post_history_instructions = $("#post_history_instructions_textarea").val(); }, '#post_history_instructions_textarea': function () { create_save.post_history_instructions = $("#post_history_instructions_textarea").val(); },
'#creator_textarea': function () { create_save_creator = $("#creator_textarea").val(); }, '#creator_textarea': function () { create_save.creator = $("#creator_textarea").val(); },
'#tags_textarea': function () { create_save_tags = $("#tags_textarea").val(); }, '#tags_textarea': function () { create_save.tags = $("#tags_textarea").val(); },
'#personality_textarea': function () { create_save_personality = $("#personality_textarea").val(); }, '#personality_textarea': function () { create_save.personality = $("#personality_textarea").val(); },
'#scenario_pole': function () { create_save_scenario = $("#scenario_pole").val(); }, '#scenario_pole': function () { create_save.scenario = $("#scenario_pole").val(); },
'#mes_example_textarea': function () { create_save_mes_example = $("#mes_example_textarea").val(); }, '#mes_example_textarea': function () { create_save.mes_example = $("#mes_example_textarea").val(); },
'#firstmessage_textarea': function () { create_save_first_message = $("#firstmessage_textarea").val(); }, '#firstmessage_textarea': function () { create_save.first_message = $("#firstmessage_textarea").val(); },
'#talkativeness_slider': function () { create_save_talkativeness = $("#talkativeness_slider").val(); }, '#talkativeness_slider': function () { create_save.talkativeness = $("#talkativeness_slider").val(); },
}; };
Object.keys(elementsToUpdate).forEach(function (id) { Object.keys(elementsToUpdate).forEach(function (id) {
@ -7373,6 +7430,7 @@ $(document).ready(function () {
$("#world_popup_entries_list").children().find('.up').click() $("#world_popup_entries_list").children().find('.up').click()
}); });
$(document).on('click', '.open_alternate_greetings', openAlternateGreetings); $(document).on('click', '.open_alternate_greetings', openAlternateGreetings);
$('#set_character_world').on('click', openCharacterWorldPopup);
$(document).keyup(function (e) { $(document).keyup(function (e) {
if (e.key === "Escape") { if (e.key === "Escape") {

View File

@ -1,4 +1,4 @@
import { saveSettings, callPopup, substituteParams, getTokenCount, getRequestHeaders, chat_metadata } from "../script.js"; import { saveSettings, callPopup, substituteParams, getTokenCount, getRequestHeaders, chat_metadata, this_chid, characters } from "../script.js";
import { download, debounce, delay, initScrollHeight, resetScrollHeight } from "./utils.js"; import { download, debounce, delay, initScrollHeight, resetScrollHeight } from "./utils.js";
import { getContext } from "./extensions.js"; import { getContext } from "./extensions.js";
import { metadata_keys } from "./extensions/floating-prompt/index.js"; import { metadata_keys } from "./extensions/floating-prompt/index.js";
@ -11,6 +11,7 @@ export {
world_info_recursive, world_info_recursive,
world_info_case_sensitive, world_info_case_sensitive,
world_info_match_whole_words, world_info_match_whole_words,
world_info_character_strategy,
world_names, world_names,
imported_world_name, imported_world_name,
checkWorldInfo, checkWorldInfo,
@ -20,6 +21,12 @@ export {
getWorldInfoPrompt, getWorldInfoPrompt,
} }
const world_info_insertion_strategy = {
evenly: 0,
character_first: 1,
global_first: 2,
}
let world_info = null; let world_info = null;
let world_names; let world_names;
let world_info_data = null; let world_info_data = null;
@ -29,6 +36,7 @@ let is_world_edit_open = false;
let world_info_recursive = false; let world_info_recursive = false;
let world_info_case_sensitive = false; let world_info_case_sensitive = false;
let world_info_match_whole_words = false; let world_info_match_whole_words = false;
let world_info_character_strategy = world_info_insertion_strategy.evenly;
let imported_world_name = ""; let imported_world_name = "";
const saveWorldDebounced = debounce(async () => await _save(), 1000); const saveWorldDebounced = debounce(async () => await _save(), 1000);
const saveSettingsDebounced = debounce(() => saveSettings(), 1000); const saveSettingsDebounced = debounce(() => saveSettings(), 1000);
@ -41,15 +49,14 @@ const world_info_position = {
}; };
function getWorldInfoPrompt(chat2) { async function getWorldInfoPrompt(chat2) {
let worldInfoString = "", worldInfoBefore = "", worldInfoAfter = ""; let worldInfoString = "", worldInfoBefore = "", worldInfoAfter = "";
if (world_info && world_info_data) { const activatedWorldInfo = await checkWorldInfo(chat2);
const activatedWorldInfo = checkWorldInfo(chat2); worldInfoBefore = activatedWorldInfo.worldInfoBefore;
worldInfoBefore = activatedWorldInfo.worldInfoBefore; worldInfoAfter = activatedWorldInfo.worldInfoAfter;
worldInfoAfter = activatedWorldInfo.worldInfoAfter; worldInfoString = worldInfoBefore + worldInfoAfter;
worldInfoString = worldInfoBefore + worldInfoAfter;
}
return { worldInfoString, worldInfoBefore, worldInfoAfter }; return { worldInfoString, worldInfoBefore, worldInfoAfter };
} }
@ -64,6 +71,8 @@ function setWorldInfoSettings(settings, data) {
world_info_case_sensitive = Boolean(settings.world_info_case_sensitive); world_info_case_sensitive = Boolean(settings.world_info_case_sensitive);
if (settings.world_info_match_whole_words !== undefined) if (settings.world_info_match_whole_words !== undefined)
world_info_match_whole_words = Boolean(settings.world_info_match_whole_words); world_info_match_whole_words = Boolean(settings.world_info_match_whole_words);
if (settings.world_info_character_strategy !== undefined)
world_info_character_strategy = Number(settings.world_info_character_strategy);
$("#world_info_depth_counter").text(world_info_depth); $("#world_info_depth_counter").text(world_info_depth);
$("#world_info_depth").val(world_info_depth); $("#world_info_depth").val(world_info_depth);
@ -75,6 +84,9 @@ function setWorldInfoSettings(settings, data) {
$("#world_info_case_sensitive").prop('checked', world_info_case_sensitive); $("#world_info_case_sensitive").prop('checked', world_info_case_sensitive);
$("#world_info_match_whole_words").prop('checked', world_info_match_whole_words); $("#world_info_match_whole_words").prop('checked', world_info_match_whole_words);
$(`#world_info_character_strategy option[value='${world_info_character_strategy}']`).prop('selected', true);
$("#world_info_character_strategy").val(world_info_character_strategy);
world_names = data.world_names?.length ? data.world_names : []; world_names = data.world_names?.length ? data.world_names : [];
if (settings.world_info != undefined) { if (settings.world_info != undefined) {
@ -102,24 +114,27 @@ async function showWorldEditor() {
is_world_edit_open = true; is_world_edit_open = true;
$("#world_popup_name").val(world_info); $("#world_popup_name").val(world_info);
$("#world_popup").css("display", "flex"); $("#world_popup").css("display", "flex");
await loadWorldInfoData(); world_info_data = await loadWorldInfoData(world_info);
displayWorldEntries(world_info_data); displayWorldEntries(world_info_data);
} }
async function loadWorldInfoData() { async function loadWorldInfoData(name) {
if (!world_info) { if (!name) {
return; return;
} }
const response = await fetch("/getworldinfo", { const response = await fetch("/getworldinfo", {
method: "POST", method: "POST",
headers: getRequestHeaders(), headers: getRequestHeaders(),
body: JSON.stringify({ name: world_info }), body: JSON.stringify({ name: name }),
}); });
if (response.ok) { if (response.ok) {
world_info_data = await response.json(); const data = await response.json();
return data;
} }
return null;
} }
async function updateWorldInfoList(importedWorldName) { async function updateWorldInfoList(importedWorldName) {
@ -533,11 +548,70 @@ function transformString(str) {
return world_info_case_sensitive ? str : str.toLowerCase(); return world_info_case_sensitive ? str : str.toLowerCase();
} }
function checkWorldInfo(chat) { async function getCharacterLore() {
if (world_info_data.entries.length == 0) { const name = characters[this_chid]?.data?.extensions?.world;
return "";
if (!name) {
return [];
} }
if (!world_names.includes(name)) {
console.warn(`Character ${characters[this_chid]?.name} has invalid world info name: ${name}`);
return [];
}
const data = await loadWorldInfoData(name);
const entries = data ? Object.keys(data.entries).map((x) => data.entries[x]) : [];
console.debug(`Character ${characters[this_chid]?.name} lore (${name}) has ${entries.length} world info entries`);
return entries;
}
function getGlobalLore() {
if (!world_info || !world_info_data) {
return [];
}
const entries = Object.keys(world_info_data.entries).map((x) => world_info_data.entries[x]);
console.debug(`Global world info has ${entries.length} entries`);
return entries;
}
async function getSortedEntries() {
try {
const globalLore = getGlobalLore();
const characterLore = await getCharacterLore();
let entries;
const sortFn = (a, b) => b.order - a.order;
switch (world_info_character_strategy) {
case world_info_insertion_strategy.evenly:
entries = [...globalLore, ...characterLore].sort(sortFn);
break;
case world_info_insertion_strategy.character_first:
entries = [...characterLore.sort(sortFn), ...globalLore.sort(sortFn)];
break;
case world_info_insertion_strategy.global_first:
entries = [...globalLore.sort(sortFn), ...characterLore.sort(sortFn)];
break;
default:
console.error(`Unknown insertion strategy: ${world_info_character_strategy}`);
entries = [...globalLore, ...characterLore].sort(sortFn);
break;
}
console.debug(`Sorted ${entries.length} world lore entries using strategy ${world_info_character_strategy}`);
return entries;
}
catch (e) {
console.error(e);
return [];
}
}
async function checkWorldInfo(chat) {
const context = getContext(); const context = getContext();
const messagesToLookBack = world_info_depth * 2; const messagesToLookBack = world_info_depth * 2;
let textToScan = transformString(chat.slice(0, messagesToLookBack).join("")); let textToScan = transformString(chat.slice(0, messagesToLookBack).join(""));
@ -547,9 +621,11 @@ function checkWorldInfo(chat) {
let count = 0; let count = 0;
let allActivatedEntries = new Set(); let allActivatedEntries = new Set();
const sortedEntries = Object.keys(world_info_data.entries) const sortedEntries = await getSortedEntries();
.map((x) => world_info_data.entries[x])
.sort((a, b) => b.order - a.order); if (sortedEntries.length === 0) {
return { worldInfoBefore, worldInfoAfter };
}
while (needsToScan) { while (needsToScan) {
// Track how many times the loop has run // Track how many times the loop has run
@ -558,12 +634,13 @@ function checkWorldInfo(chat) {
let activatedNow = new Set(); let activatedNow = new Set();
for (let entry of sortedEntries) { for (let entry of sortedEntries) {
if (allActivatedEntries.has(entry.uid) || entry.disable == true || (count > 1 && world_info_recursive && entry.excludeRecursion)) { if (allActivatedEntries.has(entry) || entry.disable == true || (count > 1 && world_info_recursive && entry.excludeRecursion)) {
continue; continue;
} }
if (entry.constant) { if (entry.constant) {
activatedNow.add(entry.uid); activatedNow.add(entry);
continue;
} }
if (Array.isArray(entry.key) && entry.key.length) { if (Array.isArray(entry.key) && entry.key.length) {
@ -578,12 +655,12 @@ function checkWorldInfo(chat) {
secondary: for (let keysecondary of entry.keysecondary) { secondary: for (let keysecondary of entry.keysecondary) {
const secondarySubstituted = substituteParams(keysecondary); const secondarySubstituted = substituteParams(keysecondary);
if (secondarySubstituted && matchKeys(textToScan, secondarySubstituted.trim())) { if (secondarySubstituted && matchKeys(textToScan, secondarySubstituted.trim())) {
activatedNow.add(entry.uid); activatedNow.add(entry);
break secondary; break secondary;
} }
} }
} else { } else {
activatedNow.add(entry.uid); activatedNow.add(entry);
break primary; break primary;
} }
} }
@ -593,7 +670,6 @@ function checkWorldInfo(chat) {
needsToScan = world_info_recursive && activatedNow.size > 0; needsToScan = world_info_recursive && activatedNow.size > 0;
const newEntries = [...activatedNow] const newEntries = [...activatedNow]
.map((x) => world_info_data.entries[x])
.sort((a, b) => sortedEntries.indexOf(a) - sortedEntries.indexOf(b)); .sort((a, b) => sortedEntries.indexOf(a) - sortedEntries.indexOf(b));
let ANInjectionTokens = 0; let ANInjectionTokens = 0;
for (const entry of newEntries) { for (const entry of newEntries) {
@ -683,7 +759,7 @@ jQuery(() => {
if (selectedWorld !== "None") { if (selectedWorld !== "None") {
const worldIndex = Number(selectedWorld); const worldIndex = Number(selectedWorld);
world_info = !isNaN(worldIndex) ? world_names[worldIndex] : null; world_info = !isNaN(worldIndex) ? world_names[worldIndex] : null;
await loadWorldInfoData(); world_info_data = await loadWorldInfoData(world_info);
} }
if (selectedWorld === "None") { hideWorldEditor(); } if (selectedWorld === "None") { hideWorldEditor(); }
@ -759,8 +835,12 @@ jQuery(() => {
renameWorldInfo(); renameWorldInfo();
}); });
$("#world_create_button").click(() => { $("#world_create_button").on('click', async () => {
createNewWorldInfo(); const confirm = await callPopup("<h3>Create a new World Info?</h3>", "confirm");
if (confirm) {
await createNewWorldInfo();
}
}); });
$(document).on("input", "#world_info_depth", function () { $(document).on("input", "#world_info_depth", function () {
@ -789,4 +869,9 @@ jQuery(() => {
world_info_match_whole_words = !!$(this).prop('checked'); world_info_match_whole_words = !!$(this).prop('checked');
saveSettingsDebounced(); saveSettingsDebounced();
}); });
$('#world_info_character_strategy').on('change', function () {
world_info_character_strategy = $(this).val();
saveSettingsDebounced();
})
}); });

View File

@ -1190,6 +1190,10 @@ select option:not(:checked) {
color: #c5b457 !important; color: #c5b457 !important;
} }
.world_set {
color: #4b9c00 !important;
}
.displayBlock { .displayBlock {
display: block !important; display: block !important;
} }
@ -1338,6 +1342,10 @@ input[type=search]:focus::-webkit-search-cancel-button {
gap: 5px !important; gap: 5px !important;
} }
.gap10px {
gap: 10px !important;
}
.wide10pMinFit { .wide10pMinFit {
width: 10%; width: 10%;
min-width: fit-content; min-width: fit-content;

View File

@ -830,6 +830,7 @@ function charaFormatData(data) {
// ST extension fields to V2 object // ST extension fields to V2 object
_.set(char, 'data.extensions.talkativeness', data.talkativeness); _.set(char, 'data.extensions.talkativeness', data.talkativeness);
_.set(char, 'data.extensions.fav', data.fav == 'true'); _.set(char, 'data.extensions.fav', data.fav == 'true');
_.set(char, 'data.extensions.world', data.world || '');
//_.set(char, 'data.extensions.create_date', humanizedISO8601DateTime()); //_.set(char, 'data.extensions.create_date', humanizedISO8601DateTime());
//_.set(char, 'data.extensions.avatar', 'none'); //_.set(char, 'data.extensions.avatar', 'none');
//_.set(char, 'data.extensions.chat', data.ch_name + ' - ' + humanizedISO8601DateTime()); //_.set(char, 'data.extensions.chat', data.ch_name + ' - ' + humanizedISO8601DateTime());