Replace implementation of world info

This commit is contained in:
SillyLossy
2023-02-20 18:19:46 +02:00
parent 94d4b06dc7
commit 53bfce557f
5 changed files with 333 additions and 552 deletions

View File

@@ -1,30 +0,0 @@
{
"folders": {
"Sample Folder": [
0,
1
]
},
"entries": {
"0": {
"uid": 0,
"title": "AAA",
"key": [ "AAA" ],
"keysecondary": [ ],
"constant": false,
"content": "AAA is a city where BBB lives.",
"comment": "AAA definition",
"selective": true
},
"1": {
"uid": 1,
"title": "BBB",
"key": [ "BBB" ],
"keysecondary": [ ],
"constant": false,
"content": "BBB is a 21-year old female student of CCC academy.",
"comment": "BBB definition",
"selective": true
}
}
}

View File

@@ -99,7 +99,6 @@
var create_save_mes_example = ''; var create_save_mes_example = '';
var timerSaveEdit; var timerSaveEdit;
var timerKoboldSync;
var timerWorldSave; var timerWorldSave;
var durationSaveEdit = 200; var durationSaveEdit = 200;
//animation right menu //animation right menu
@@ -136,12 +135,10 @@
var user_avatar = 'you.png'; var user_avatar = 'you.png';
var temp = 0.5; var temp = 0.5;
var amount_gen = 80; var amount_gen = 80;
var kobold_world = null; var world_info = null;
var koboldai_world_names; var world_names;
var kobold_world_synced = false; var world_info_data = null;
var kobold_sync_failed = false; var world_info_depth = 3;
var kobold_is_united = false;
var kobold_world_data = null;
var imported_world_name = ''; var imported_world_name = '';
var max_context = 2048;//2048; var max_context = 2048;//2048;
var rep_pen = 1; var rep_pen = 1;
@@ -338,9 +335,6 @@
online_status = data.result; online_status = data.result;
if(online_status == undefined){ if(online_status == undefined){
online_status = 'no_connection'; online_status = 'no_connection';
kobold_world_synced = false;
updateWorldStatus();
} }
if(online_status.toLowerCase().indexOf('pygmalion') != -1){ if(online_status.toLowerCase().indexOf('pygmalion') != -1){
is_pygmalion = true; is_pygmalion = true;
@@ -353,7 +347,6 @@
resultCheckStatus(); resultCheckStatus();
if(online_status !== 'no_connection'){ if(online_status !== 'no_connection'){
var checkStatusNow = setTimeout(getStatus, 3000);//getStatus(); var checkStatusNow = setTimeout(getStatus, 3000);//getStatus();
syncKoboldWorldInfo(false);
} }
}, },
error: function (jqXHR, exception) { error: function (jqXHR, exception) {
@@ -361,18 +354,12 @@
console.log(jqXHR); console.log(jqXHR);
online_status = 'no_connection'; online_status = 'no_connection';
// invalidate world info when losing connection to kobold
kobold_world_synced = false;
updateWorldStatus();
resultCheckStatus(); resultCheckStatus();
} }
}); });
}else{ }else{
if(is_get_status_novel != true){ if(is_get_status_novel != true){
online_status = 'no_connection'; online_status = 'no_connection';
kobold_world_synced = false;
updateWorldStatus();
} }
} }
} }
@@ -731,6 +718,63 @@
return name; return name;
} }
function checkWorldInfo(chat) {
if (world_info_data.entries.length == 0) {
return '';
}
const messagesToLookBack = world_info_depth * 2;
let textToScan = chat.slice(0, messagesToLookBack).join('').toLowerCase();
let worldInfo = '';
let needsToScan = true;
let allActivatedEntries = new Set();
while (needsToScan) {
let activatedNow = new Set();
for (let entryUid in world_info_data.entries) {
const entry = world_info_data.entries[entryUid];
if (allActivatedEntries.has(entry.uid)) {
continue;
}
if (entry.constant) {
activatedNow.add(entry.uid);
}
if (Array.isArray(entry.key) && entry.key.length) {
primary: for (let key of entry.key) {
if (key && textToScan.includes(key.trim().toLowerCase())) {
if (entry.selective && Array.isArray(entry.keysecondary) && entry.keysecondary.length) {
secondary: for (let keysecondary of entry.keysecondary) {
if (keysecondary && textToScan.includes(keysecondary.trim().toLowerCase())) {
activatedNow.add(entry.uid);
break secondary;
}
}
} else {
activatedNow.add(entry.uid);
break primary;
}
}
}
}
}
needsToScan = activatedNow.size > 0;
const newContents = [...activatedNow].map(x => world_info_data.entries[x]).map(x => x.content).join('\n');
worldInfo = worldInfo + newContents;
if (needsToScan) {
textToScan = newContents.toLowerCase();
}
allActivatedEntries = new Set([...allActivatedEntries, ...activatedNow]);
}
return worldInfo;
}
function isHelpRequest(message) { function isHelpRequest(message) {
const helpTokens = ['/?', '/help']; const helpTokens = ['/?', '/help'];
return helpTokens.includes(message.trim().toLowerCase()); return helpTokens.includes(message.trim().toLowerCase());
@@ -846,7 +890,6 @@
} }
} }
//********************************* //*********************************
//PRE FORMATING STRING //PRE FORMATING STRING
//********************************* //*********************************
@@ -992,6 +1035,12 @@
} }
} }
let worldInfoString = '';
if (world_info && world_info_data) {
worldInfoString = checkWorldInfo(chat2);
}
var i = 0; var i = 0;
for (var item of chat2) {//console.log(encode("dsfs").length); for (var item of chat2) {//console.log(encode("dsfs").length);
@@ -1145,8 +1194,7 @@
var generate_data; var generate_data;
if(main_api == 'kobold'){ if(main_api == 'kobold'){
const use_world_info = Boolean(kobold_world && kobold_world_synced); var generate_data = {prompt: finalPromt, gui_settings: true,max_length: amount_gen,temperature: temp, max_context_length: max_context};
var generate_data = {prompt: finalPromt, gui_settings: true,max_length: amount_gen,temperature: temp, max_context_length: max_context, use_world_info};
if(preset_settings != 'gui'){ if(preset_settings != 'gui'){
var this_settings = koboldai_settings[koboldai_setting_names[preset_settings]]; var this_settings = koboldai_settings[koboldai_setting_names[preset_settings]];
@@ -1188,7 +1236,7 @@
s5:this_settings.sampler_order[4], s5:this_settings.sampler_order[4],
s6:this_settings.sampler_order[5], s6:this_settings.sampler_order[5],
s7:this_settings.sampler_order[6], s7:this_settings.sampler_order[6],
use_world_info: use_world_info, use_world_info: false,
}; };
} }
} }
@@ -1454,9 +1502,6 @@
$( "#rm_button_characters" ).children("h2").css(deselected_button_style); $( "#rm_button_characters" ).children("h2").css(deselected_button_style);
$( "#rm_button_settings" ).children("h2").css(seleced_button_style); $( "#rm_button_settings" ).children("h2").css(seleced_button_style);
$( "#rm_button_selected_ch" ).children("h2").css(deselected_button_style); $( "#rm_button_selected_ch" ).children("h2").css(deselected_button_style);
// Dumb call, but won't need an interval
updateWorldStatus();
}); });
$( "#rm_button_characters" ).click(function() { $( "#rm_button_characters" ).click(function() {
selected_button = 'characters'; selected_button = 'characters';
@@ -1763,15 +1808,15 @@
}); });
} }
if (popup_type === 'world_imported' && imported_world_name) { if (popup_type === 'world_imported' && imported_world_name) {
koboldai_world_names.forEach((item, i) => { world_names.forEach((item, i) => {
if (item === imported_world_name) { if (item === imported_world_name) {
$('#world_info').val(i).change(); $('#world_info').val(i).change();
} }
}) })
imported_world_name = ''; imported_world_name = '';
} }
if (popup_type === 'del_world' && kobold_world) { if (popup_type === 'del_world' && world_info) {
deleteWorldInfo(kobold_world); deleteWorldInfo(world_info);
} }
if(popup_type == 'new_chat' && this_chid != undefined && menu_type != "create"){//Fix it; New chat doesn't create while open create character menu if(popup_type == 'new_chat' && this_chid != undefined && menu_type != "create"){//Fix it; New chat doesn't create while open create character menu
clearChat(); clearChat();
@@ -2100,7 +2145,6 @@
is_get_status = true; is_get_status = true;
is_api_button_press = true; is_api_button_press = true;
getStatus(); getStatus();
detectUnitedKobold();
clearSoftPromptsList(); clearSoftPromptsList();
getSoftPromptsList(); getSoftPromptsList();
} }
@@ -2201,21 +2245,19 @@
}); });
$("#world_info").change(function() { $("#world_info").change(async function() {
const selectedWorld = $('#world_info').find(":selected").val(); const selectedWorld = $('#world_info').find(":selected").val();
kobold_world_synced = false; world_info = null;
kobold_sync_failed = false; world_info_data = null;
kobold_world = null;
if (selectedWorld !== 'None') { if (selectedWorld !== 'None') {
const worldIndex = Number(selectedWorld); const worldIndex = Number(selectedWorld);
kobold_world = !isNaN(worldIndex) ? koboldai_world_names[worldIndex] : null; world_info = !isNaN(worldIndex) ? world_names[worldIndex] : null;
await loadWorldInfoData();
} }
hideWorldEditor(); hideWorldEditor();
syncKoboldWorldInfo(true);
saveSettings(); saveSettings();
updateWorldStatus();
}); });
$( "#settings_perset" ).change(function() { $( "#settings_perset" ).change(function() {
@@ -2316,7 +2358,6 @@
main_api = 'kobold'; main_api = 'kobold';
$('#max_context_block').css('display', 'block'); $('#max_context_block').css('display', 'block');
$('#amount_gen_block').css('display', 'block'); $('#amount_gen_block').css('display', 'block');
$('#world_info_block').css('display', 'flex');
$('#softprompt_block').css('display', 'block'); $('#softprompt_block').css('display', 'block');
} }
if($('#main_api').find(":selected").val() == 'novel'){ if($('#main_api').find(":selected").val() == 'novel'){
@@ -2325,11 +2366,8 @@
main_api = 'novel'; main_api = 'novel';
$('#max_context_block').css('display', 'none'); $('#max_context_block').css('display', 'none');
$('#amount_gen_block').css('display', 'none'); $('#amount_gen_block').css('display', 'none');
$('#world_info_block').css('display', 'none');
$('#softprompt_block').css('display', 'none'); $('#softprompt_block').css('display', 'none');
} }
updateWorldStatus();
} }
async function getUserAvatars(){ async function getUserAvatars(){
const response = await fetch("/getuseravatars", { const response = await fetch("/getuseravatars", {
@@ -2358,103 +2396,6 @@
} }
} }
function updateWorldStatus() {
if($('#world_info_block').is(':visible') && kobold_world) {
$('#world_info_edit_button').show();
$('#world_status').show();
if (kobold_world_synced) {
$("#world_status_indicator").css("background-color", "green");
$("#world_status_text").html("Synchronized with KoboldAI")
}
else {
let statusText = online_status === 'no_connection'
? "Waiting for connection"
: "Synchronizing...";
if (kobold_sync_failed) {
statusText = "Synchronization failed (see console)";
}
$("#world_status_text").html(statusText);
$("#world_status_indicator").css("background-color", "red");
}
if (kobold_is_united) {
$("#world_status_text").html('<span style="font-size:90%">KoboldAI United detected. WI may not work as intended.<br>If experiencing issues, please select "None".</span>');
}
} else {
$('#world_status').hide();
$('#world_info_edit_button').hide();
}
}
async function detectUnitedKobold() {
if (!api_server || main_api !== 'kobold') {
return;
}
// If we can reach Kobold's new ui, then it should be United branch
kobold_is_united = false;
try {
const kobold_united_ui2 = api_server.replace('/api', '/new_ui');
const response = await fetch(kobold_united_ui2, { method: 'HEAD'});
if (response.ok && response.status == 200) {
kobold_is_united = true;
}
}
catch {
// empty catch
}
}
async function syncKoboldWorldInfo(force) {
// Don't sync if no world selected or if synced and not forcing
if (online_status === 'no_connection' || (!kobold_world && !force) || (kobold_world_synced && !force)) {
updateWorldStatus();
return;
}
const response = await fetch("/synckoboldworld", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": token,
},
body: JSON.stringify({ "name": kobold_world })
});
if (response.ok) {
const syncData = await response.json();
if (syncData.ok) {
kobold_world_synced = true;
kobold_sync_failed = false;
}
if (syncData.busy) {
// console.log('Sync API is busy. Retrying in 3sec');
clearTimeout(timerKoboldSync);
timerKoboldSync = setTimeout(() => syncKoboldWorldInfo(force), 3000);
return;
}
} else {
kobold_sync_failed = true;
let responseLog = response.statusText;
try {
var responseBody = await response.text();
responseLog += ('\n' + responseBody);
} catch {
// empty catch
}
console.error(`Sync API response: ${responseLog}`);
}
updateWorldStatus();
}
$(document).on('input', '#temp', function() { $(document).on('input', '#temp', function() {
temp = $(this).val(); temp = $(this).val();
if(isInt(temp)){ if(isInt(temp)){
@@ -2474,6 +2415,11 @@
$('#max_context_counter').html( $(this).val() +' Tokens'); $('#max_context_counter').html( $(this).val() +' Tokens');
var max_contextTimer = setTimeout(saveSettings, 500); var max_contextTimer = setTimeout(saveSettings, 500);
}); });
$(document).on('input', '#world_info_depth', function() {
world_info_depth = parseInt($(this).val());
$('#world_info_depth_counter').html(`${$(this).val()} Messages`);
setTimeout(saveSettings, 500);
});
$('#style_anchor').change(function() { $('#style_anchor').change(function() {
style_anchor = !!$('#style_anchor').prop('checked'); style_anchor = !!$('#style_anchor').prop('checked');
saveSettings(); saveSettings();
@@ -2605,6 +2551,7 @@
if(settings.anchor_order !== undefined) anchor_order = parseInt(settings.anchor_order); if(settings.anchor_order !== undefined) anchor_order = parseInt(settings.anchor_order);
if(settings.style_anchor !== undefined) style_anchor = !!settings.style_anchor; if(settings.style_anchor !== undefined) style_anchor = !!settings.style_anchor;
if(settings.character_anchor !== undefined) character_anchor = !!settings.character_anchor; if(settings.character_anchor !== undefined) character_anchor = !!settings.character_anchor;
if(settings.world_info_depth !== undefined) world_info_depth = parseInt(settings.world_info_depth);
rep_pen = settings.rep_pen; rep_pen = settings.rep_pen;
rep_pen_size = settings.rep_pen_size; rep_pen_size = settings.rep_pen_size;
@@ -2624,6 +2571,9 @@
$('#amount_gen').val(amount_gen); $('#amount_gen').val(amount_gen);
$('#amount_gen_counter').html(amount_gen+' Tokens'); $('#amount_gen_counter').html(amount_gen+' Tokens');
$('#world_info_depth_counter').html(`${world_info_depth} Messages`);
$('#world_info_depth').val(world_info_depth);
addZeros = ""; addZeros = "";
if(isInt(rep_pen)) addZeros = ".00"; if(isInt(rep_pen)) addZeros = ".00";
$('#rep_pen').val(rep_pen); $('#rep_pen').val(rep_pen);
@@ -2686,20 +2636,18 @@
$('#api_url_text').val(api_server); $('#api_url_text').val(api_server);
// world info settings // world info settings
koboldai_world_names = data.koboldai_world_names?.length ? data.koboldai_world_names : []; world_names = data.world_names?.length ? data.world_names : [];
if(settings.kobold_world != undefined) { if(settings.world_info != undefined) {
if (koboldai_world_names.includes(settings.kobold_world)) { if (world_names.includes(settings.world_info)) {
kobold_world = settings.kobold_world; world_info = settings.world_info;
kobold_world_synced = false;
kobold_sync_failed = false;
} }
} }
koboldai_world_names.forEach((item, i) => { world_names.forEach((item, i) => {
$('#world_info').append(`<option value='${i}'>${item}</option>`); $('#world_info').append(`<option value='${i}'>${item}</option>`);
// preselect world if saved // preselect world if saved
if (item == kobold_world) { if (item == world_info) {
$('#world_info').val(i).change(); $('#world_info').val(i).change();
} }
}); });
@@ -2742,7 +2690,8 @@
temp_novel: temp_novel, temp_novel: temp_novel,
rep_pen_novel: rep_pen_novel, rep_pen_novel: rep_pen_novel,
rep_pen_size_novel: rep_pen_size_novel, rep_pen_size_novel: rep_pen_size_novel,
kobold_world: kobold_world, world_info: world_info,
world_info_depth: world_info_depth,
                 }),                  }),
beforeSend: function(){ beforeSend: function(){
@@ -2757,8 +2706,6 @@
if(type === 'change_name'){ if(type === 'change_name'){
location.reload(); location.reload();
} }
syncKoboldWorldInfo(false);
}, },
error: function (jqXHR, exception) { error: function (jqXHR, exception) {
console.log(exception); console.log(exception);
@@ -3246,15 +3193,15 @@
if (result.ok) { if (result.ok) {
var data = await result.json(); var data = await result.json();
koboldai_world_names = data.koboldai_world_names?.length ? data.koboldai_world_names : []; world_names = data.world_names?.length ? data.world_names : [];
$('#world_info').find('option[value!="None"]').remove(); $('#world_info').find('option[value!="None"]').remove();
koboldai_world_names.forEach((item, i) => { world_names.forEach((item, i) => {
$('#world_info').append(`<option value='${i}'>${item}</option>`); $('#world_info').append(`<option value='${i}'>${item}</option>`);
}); });
if (importedWorldName) { if (importedWorldName) {
const indexOf = koboldai_world_names.indexOf(kobold_world); const indexOf = world_names.indexOf(world_info);
$('#world_info').val(indexOf); $('#world_info').val(indexOf);
popup_type = 'world_imported'; popup_type = 'world_imported';
@@ -3274,30 +3221,34 @@
// World Info Editor // World Info Editor
async function showWorldEditor() { async function showWorldEditor() {
is_world_edit_open = true; is_world_edit_open = true;
$('#world_popup_name').val(kobold_world); $('#world_popup_name').val(world_info);
$('#world_popup').css('display', 'flex'); $('#world_popup').css('display', 'flex');
await loadWorldInfoData();
displayWorldEntries(world_info_data);
}
async function loadWorldInfoData() {
if (!world_info) {
return;
}
if (kobold_world) {
const response = await fetch("/getworldinfo", { const response = await fetch("/getworldinfo", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"X-CSRF-Token": token, "X-CSRF-Token": token,
}, },
body: JSON.stringify({ name: kobold_world }) body: JSON.stringify({ name: world_info })
}); });
if (response.ok) { if (response.ok) {
kobold_world_data = await response.json(); world_info_data = await response.json();
displayWorldEntries(kobold_world_data);
}
} }
} }
function hideWorldEditor() { function hideWorldEditor() {
is_world_edit_open = false; is_world_edit_open = false;
$('#world_popup').css('display', 'none'); $('#world_popup').css('display', 'none');
syncKoboldWorldInfo(true);
} }
function displayWorldEntries(data) { function displayWorldEntries(data) {
@@ -3323,7 +3274,7 @@
keyInput.on('input', function () { keyInput.on('input', function () {
const uid = $(this).data('uid'); const uid = $(this).data('uid');
const value = $(this).val(); const value = $(this).val();
kobold_world_data.entries[uid].key = value.split(',').map(x => x.trim()).filter(x => x); world_info_data.entries[uid].key = value.split(',').map(x => x.trim()).filter(x => x);
saveWorldInfo(); saveWorldInfo();
}); });
keyInput.val(entry.key.join(',')).trigger('input'); keyInput.val(entry.key.join(',')).trigger('input');
@@ -3334,7 +3285,7 @@
keySecondaryInput.on('input', function() { keySecondaryInput.on('input', function() {
const uid = $(this).data('uid'); const uid = $(this).data('uid');
const value = $(this).val(); const value = $(this).val();
kobold_world_data.entries[uid].keysecondary = value.split(',').map(x => x.trim()).filter(x => x); world_info_data.entries[uid].keysecondary = value.split(',').map(x => x.trim()).filter(x => x);
saveWorldInfo(); saveWorldInfo();
}); });
keySecondaryInput.val(entry.keysecondary.join(',')).trigger('input'); keySecondaryInput.val(entry.keysecondary.join(',')).trigger('input');
@@ -3345,7 +3296,7 @@
commentInput.on('input', function() { commentInput.on('input', function() {
const uid = $(this).data('uid'); const uid = $(this).data('uid');
const value = $(this).val(); const value = $(this).val();
kobold_world_data.entries[uid].comment = value; world_info_data.entries[uid].comment = value;
saveWorldInfo(); saveWorldInfo();
}); });
commentInput.val(entry.comment).trigger('input'); commentInput.val(entry.comment).trigger('input');
@@ -3356,7 +3307,7 @@
contentInput.on('input', function() { contentInput.on('input', function() {
const uid = $(this).data('uid'); const uid = $(this).data('uid');
const value = $(this).val(); const value = $(this).val();
kobold_world_data.entries[uid].content = value; world_info_data.entries[uid].content = value;
saveWorldInfo(); saveWorldInfo();
// count tokens // count tokens
@@ -3371,7 +3322,7 @@
selectiveInput.on('input', function() { selectiveInput.on('input', function() {
const uid = $(this).data('uid'); const uid = $(this).data('uid');
const value = $(this).prop('checked'); const value = $(this).prop('checked');
kobold_world_data.entries[uid].selective = value; world_info_data.entries[uid].selective = value;
saveWorldInfo(); saveWorldInfo();
const keysecondary = $(this).closest('.world_entry').find('.keysecondary'); const keysecondary = $(this).closest('.world_entry').find('.keysecondary');
@@ -3389,7 +3340,7 @@
constantInput.on('input', function() { constantInput.on('input', function() {
const uid = $(this).data('uid'); const uid = $(this).data('uid');
const value = $(this).prop('checked'); const value = $(this).prop('checked');
kobold_world_data.entries[uid].constant = value; world_info_data.entries[uid].constant = value;
saveWorldInfo(); saveWorldInfo();
}); });
constantInput.prop('checked', entry.constant).trigger('input'); constantInput.prop('checked', entry.constant).trigger('input');
@@ -3415,22 +3366,11 @@
} }
async function deleteWorldInfoEntry(uid) { async function deleteWorldInfoEntry(uid) {
if (!kobold_world_data || !('entries' in kobold_world_data)) { if (!world_info_data || !('entries' in world_info_data)) {
return; return;
} }
delete kobold_world_data.entries[uid]; delete world_info_data.entries[uid];
if ('folders' in kobold_world_data) {
for (const folderName in kobold_world_data.folders) {
const folder = kobold_world_data.folders[folderName]
const index = folder.indexOf(Number(uid));
if (index !== -1) {
folder.splice(index, 1);
}
}
}
} }
function createWorldInfoEntry() { function createWorldInfoEntry() {
@@ -3450,22 +3390,14 @@
} }
const newEntry = { uid: newUid, ...newEntryTemplate }; const newEntry = { uid: newUid, ...newEntryTemplate };
kobold_world_data.entries[newUid] = newEntry; world_info_data.entries[newUid] = newEntry;
if ('folders' in kobold_world_data) {
if (kobold_world in kobold_world_data.folders && Array.isArray(kobold_world_data.folders)) {
kobold_world_data.folders[kobold_world].push(newUid);
} else {
kobold_world_data.folders[kobold_world] = [newUid];
}
}
const entryTemplate = appendWorldEntry(newEntry); const entryTemplate = appendWorldEntry(newEntry);
entryTemplate.get(0).scrollIntoView({behavior: 'smooth'}); entryTemplate.get(0).scrollIntoView({behavior: 'smooth'});
} }
async function saveWorldInfo(immediately) { async function saveWorldInfo(immediately) {
if (!kobold_world || !kobold_world_data) { if (!world_info || !world_info_data) {
return; return;
} }
@@ -3476,12 +3408,8 @@
"Content-Type": "application/json", "Content-Type": "application/json",
"X-CSRF-Token": token, "X-CSRF-Token": token,
}, },
body: JSON.stringify({ name: kobold_world, data: kobold_world_data }) body: JSON.stringify({ name: world_info, data: world_info_data })
}); });
if (response.ok) {
kobold_world_synced = false;
}
} }
if (immediately) { if (immediately) {
@@ -3493,20 +3421,20 @@
} }
async function renameWorldInfo() { async function renameWorldInfo() {
const oldName = kobold_world; const oldName = world_info;
const newName = $('#world_popup_name').val(); const newName = $('#world_popup_name').val();
if (oldName === newName) { if (oldName === newName) {
return; return;
} }
kobold_world = newName; world_info = newName;
await saveWorldInfo(true); await saveWorldInfo(true);
await deleteWorldInfo(oldName, newName); await deleteWorldInfo(oldName, newName);
} }
async function deleteWorldInfo(worldInfoName, selectWorldName) { async function deleteWorldInfo(worldInfoName, selectWorldName) {
if (!koboldai_world_names.includes(worldInfoName)) { if (!world_names.includes(worldInfoName)) {
return; return;
} }
@@ -3522,7 +3450,7 @@
if (response.ok) { if (response.ok) {
await updateWorldInfoList(); await updateWorldInfoList();
const selectedIndex = koboldai_world_names.indexOf(selectWorldName); const selectedIndex = world_names.indexOf(selectWorldName);
if (selectedIndex !== -1) { if (selectedIndex !== -1) {
$('#world_info').val(selectedIndex).change(); $('#world_info').val(selectedIndex).change();
} }
@@ -3535,13 +3463,13 @@
} }
function getFreeWorldEntryUid() { function getFreeWorldEntryUid() {
if (!kobold_world_data || !('entries' in kobold_world_data)) { if (!world_info_data || !('entries' in world_info_data)) {
return null; return null;
} }
const MAX_UID = 1_000_000; // <- should be safe enough :) const MAX_UID = 1_000_000; // <- should be safe enough :)
for (let uid = 0; uid < MAX_UID; uid++) { for (let uid = 0; uid < MAX_UID; uid++) {
if (uid in kobold_world_data.entries) { if (uid in world_info_data.entries) {
continue; continue;
} }
return uid; return uid;
@@ -3554,7 +3482,7 @@
const MAX_FREE_NAME = 100_000; const MAX_FREE_NAME = 100_000;
for (let index = 1; index < MAX_FREE_NAME; index++) { for (let index = 1; index < MAX_FREE_NAME; index++) {
const newName = `New World (${index})`; const newName = `New World (${index})`;
if (koboldai_world_names.includes(newName)) { if (world_names.includes(newName)) {
continue; continue;
} }
return newName; return newName;
@@ -3564,19 +3492,19 @@
} }
async function createNewWorldInfo() { async function createNewWorldInfo() {
const worldInfoTemplate = { folders: {}, entries: {} }; const worldInfoTemplate = { entries: {} };
const worldInfoName = getFreeWorldName(); const worldInfoName = getFreeWorldName();
if (!worldInfoName) { if (!worldInfoName) {
return; return;
} }
kobold_world = worldInfoName; world_info = worldInfoName;
kobold_world_data = { ...worldInfoTemplate }; world_info_data = { ...worldInfoTemplate };
await saveWorldInfo(true); await saveWorldInfo(true);
await updateWorldInfoList(); await updateWorldInfoList();
const selectedIndex = koboldai_world_names.indexOf(worldInfoName); const selectedIndex = world_names.indexOf(worldInfoName);
if (selectedIndex !== -1) { if (selectedIndex !== -1) {
$('#world_info').val(selectedIndex).change(); $('#world_info').val(selectedIndex).change();
} }
@@ -3590,9 +3518,9 @@
}); });
$('#world_popup_export').click(() => { $('#world_popup_export').click(() => {
if (kobold_world && kobold_world_data) { if (world_info && world_info_data) {
const jsonValue = JSON.stringify(kobold_world_data); const jsonValue = JSON.stringify(world_info_data);
const fileName = `${kobold_world}.json`; const fileName = `${world_info}.json`;
download(jsonValue, fileName, 'application/json'); download(jsonValue, fileName, 'application/json');
} }
}); });
@@ -3733,7 +3661,7 @@
<h4>Content</h4> <h4>Content</h4>
<h5>Text that will be inserted to the prompt upon activation.</h5> <h5>Text that will be inserted to the prompt upon activation.</h5>
</label> </label>
<textarea class="text_pole" name="content" rows="2" placeholder=""></textarea> <textarea class="text_pole" name="content" rows="4" placeholder=""></textarea>
</div> </div>
<div class="world_entry_form_control world_entry_form_horizontal"> <div class="world_entry_form_control world_entry_form_horizontal">
<label class="checkbox" for="constant"> <label class="checkbox" for="constant">
@@ -3914,25 +3842,6 @@
<h4>Repetition Penalty Range</h4><h5 id="rep_pen_size_counter">select</h5> <h4>Repetition Penalty Range</h4><h5 id="rep_pen_size_counter">select</h5>
<input type="range" id="rep_pen_size" name="volume" min="0" max="2048" step="1"> <input type="range" id="rep_pen_size" name="volume" min="0" max="2048" step="1">
</div> </div>
<div>
<h4 id="world_info_block">
<span>World Info</span>
<div id="world_create_button" class="right_menu_button"><h2>+Create</h2></div>
<div id="world_import_button" class="right_menu_button"><h2>+Import</h2></div>
</h4>
<h5>How to use (<a href="/notes/13" target="_blank">?</a>)</h5>
<div id="rm_world_import" class="right_menu" style="display: none;">
<form id="form_world_import" action="javascript:void(null);" method="post" enctype="multipart/form-data">
<input type="file" id="world_import_file" accept=".json" name="avatar">
</form>
</div>
<select id="world_info" class="option_select_right_menu">
<option value="None">None</option>
</select>
<input id="world_info_edit_button" type="button" value="Details">
<div id="world_status">
<div id="world_status_indicator"></div><div id="world_status_text"></div>
</div>
<div id="softprompt_block"> <div id="softprompt_block">
<h4>Soft Prompt</h4> <h4>Soft Prompt</h4>
<h5>About soft prompts (<a href="/notes/14" target="_blank">?</a>)</h5> <h5>About soft prompts (<a href="/notes/14" target="_blank">?</a>)</h5>
@@ -3983,6 +3892,29 @@
<input id="your_name_button" type="submit" value="Change"> <input id="your_name_button" type="submit" value="Change">
</form> </form>
<hr> <hr>
<div id="world_info_block">
<h3>World Info</h3>
<div id="world_info_buttons">
<div id="world_create_button" class="right_menu_button"><h4>+Create</h4></div>
<div id="world_import_button" class="right_menu_button"><h4>+Import</h4></div>
</div>
</div>
<h5>How to use (<a href="/notes/13" target="_blank">?</a>)</h5>
<div id="rm_world_import" class="right_menu" style="display: none;">
<form id="form_world_import" action="javascript:void(null);" method="post" enctype="multipart/form-data">
<input type="file" id="world_import_file" accept=".json" name="avatar">
</form>
</div>
<select id="world_info" class="option_select_right_menu">
<option value="None">None</option>
</select>
<input id="world_info_edit_button" type="button" value="Details">
<div id="world_info_depth_block">
<h4>Scan Depth </h4><h5 id="world_info_depth_counter">select</h5>
<input type="range" id="world_info_depth" name="volume" min="1" max="5" step="1">
</div>
<hr>
<div style="opacity:0.80"> <div style="opacity:0.80">
<h3 style='margin-bottom: 10px;'>Pro Settings</h3> <h3 style='margin-bottom: 10px;'>Pro Settings</h3>
<div id="amount_gen_block"> <div id="amount_gen_block">

View File

@@ -1165,7 +1165,7 @@ input[type=button] {
} }
#world_info { #world_info {
margin-bottom: 12px; margin-bottom: 0;
} }
#world_info_block { #world_info_block {
@@ -1173,26 +1173,6 @@ input[type=button] {
align-items: center; align-items: center;
} }
#world_status{
opacity: 0.5;
margin-top: 2px;
margin-left: 10px;
margin-bottom: 20px;
}
#world_status_indicator{
border-radius: 7px;
width: 14px;
height: 14px;
background-color: red;
display: inline-block;
}
#world_status_text {
margin-left: 4px;
display: inline-block;
}
#world_import_button, #world_create_button { #world_import_button, #world_create_button {
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
@@ -1219,7 +1199,7 @@ input[type=button] {
backdrop-filter: blur(50px); backdrop-filter: blur(50px);
flex-direction: column; flex-direction: column;
max-width: 800px; max-width: 800px;
height: 83vh; height: 100vh;
position: absolute; position: absolute;
z-index: 2064; z-index: 2064;
margin-left: auto; margin-left: auto;
@@ -1248,6 +1228,19 @@ input[type=button] {
opacity: 0.8; opacity: 0.8;
} }
#world_info_buttons {
margin-left: 1rem;
}
#world_info_depth_block {
opacity: 0.8;
margin-top: 20px;
}
#world_info_depth_block input[type="range"] {
margin-left: 10px;
}
#entry_edit_template { #entry_edit_template {
display: none !important; display: none !important;
} }

131
public/worlds/Toaru.json Normal file
View File

@@ -0,0 +1,131 @@
{
"entries": {
"0": {
"uid": 0,
"key": [
"Tokiwadai Middle School",
"Tokiwadai"
],
"keysecondary": [],
"comment": "",
"content": "Place(\"Tokiwadai Middle School\")[\"prestigious girls' school\", \"females only\", \"renowned in the world\", \"requires Esper ability Level Three or higher\"]",
"constant": false,
"selective": false
},
"1": {
"uid": 1,
"key": [
"Esper",
"Ability User",
"Level"
],
"keysecondary": [],
"comment": "",
"content": "Category(\"Esper\")[\"psychic\", \"user of supernatural powers\", \"scientifically based\", \"emits AIM\", \"ranked by Levels of strength\"]",
"constant": false,
"selective": false
},
"2": {
"uid": 2,
"key": [
"Anti-Skill",
"Guard"
],
"keysecondary": [],
"comment": "",
"content": "Faction(\"Anti-Skill\")[\"police of Academy City\", \"security forces\", \"SWAT unit\", \"purple symbol\", \"blue uniform\", \"SWAT armor\", \"riot shields\", \"firearms\"]",
"constant": false,
"selective": false
},
"3": {
"uid": 3,
"key": [
"Level 5",
"Level Five"
],
"keysecondary": [],
"comment": "",
"content": "Category(\"Level Five Rank\")[\"highest esper level\", \"only seven people in Academy City have this rank\"]",
"constant": false,
"selective": false
},
"4": {
"uid": 4,
"key": [
"Academy City",
"Gakuen Toshi",
"City"
],
"keysecondary": [],
"comment": "",
"content": "Place(\"Academy City\")[\"Located west of Tokyo\", \"city of several schools\", \"most advanced city in the world\", \"scientists research on psychic powers and higher technology\", \"composed of 23 districts\", \"population over 2 millions\"]",
"constant": false,
"selective": false
},
"5": {
"uid": 5,
"key": [
"Saten Ruiko",
"Saten",
"Ruiko",
"Saten-san"
],
"keysecondary": [],
"comment": "",
"content": "Character(\"Saten Ruiko\")[\"Female\", \"outgoing\", \"friendly\", \"shameless\", \"Level Zero\", \"friends with: {Misaka, Uiharu, Kuroko}\", \"Student (Sakugawa Middle School)\", \"Classmate of Uiharu\"]",
"constant": false,
"selective": false
},
"6": {
"uid": 6,
"key": [
"Misaka Mikoto",
"Misaka",
"Mikoto",
"Onee-sama"
],
"keysecondary": [],
"comment": "",
"content": "Character(\"Misaka Mikoto\")[\"Female\", \"tsundere\", \"short tempered\", \"boyish\", \"Level Five Esper\", \"third most powerful esper of Academy City\", \"Student (Tokiwadai Middle School)\", \"Railgun\", \"Electromaster\", \"Roommate of Kuroko\", \"Friends with: {Kuroko, Uiharu, Saten}\"]",
"constant": false,
"selective": false
},
"7": {
"uid": 7,
"key": [
"Kuroko",
"Shirai Kuroko",
"Shirai"
],
"keysecondary": [],
"comment": "",
"content": "Character(\"Shirai Kuroko\")[\"Female\", \"Level Four Esper\", \"Teleporter powers\", \"Student (Tokiwadai Middle School)\", \"works at Judgement with Uiharu\", \"Roommate of Misaka\", \"obsessed with Misaka\", \"calls Misaka Onee-sama\", \"Friends with: {Misaka, Uiharu, Saten}\"]",
"constant": false,
"selective": false
},
"8": {
"uid": 8,
"key": [
"Uihari",
"Uiharu Kazari",
"Kazari"
],
"keysecondary": [],
"comment": "",
"content": "Character(\"Uiharu Kazari\")[\"Female\", \"works for Judgement with Kuroko\", \"expert in computers and hacking\", \"wears a flower circlet\", \"Level One\", \"friends with: {Misaka, Saten, Kuroko}\", \"Student (Sakugawa Middle School)\", \"Classmate of Saten\"]",
"constant": false,
"selective": false
},
"9": {
"uid": 9,
"key": [
"Judgement"
],
"keysecondary": [],
"comment": "",
"content": "Faction(\"Judgement\")[\"composed of students\", \"student-based disciplinary committee\", \"tasked to maintain peace-and-order within the school system\", \"members wear armbands on right sleeves\", \"green shield symbol with white stripes\"]",
"constant": false,
"selective": false
}
}
}

287
server.js
View File

@@ -61,7 +61,7 @@ if (is_colab && process.env.googledrive == 2){
const jsonParser = express.json({limit: '100mb'}); const jsonParser = express.json({limit: '100mb'});
const urlencodedParser = express.urlencoded({extended: true, limit: '100mb'}); const urlencodedParser = express.urlencoded({extended: true, limit: '100mb'});
const baseRequestArgs = { headers: { "Content-Type": "application/json" } }; const baseRequestArgs = { headers: { "Content-Type": "application/json" } };
const directories = { worlds: 'public/KoboldAI Worlds/' }; const directories = { worlds: 'public/worlds/' };
// CSRF Protection // // CSRF Protection //
const doubleCsrf = require('csrf-csrf').doubleCsrf; const doubleCsrf = require('csrf-csrf').doubleCsrf;
@@ -753,7 +753,7 @@ app.post('/getsettings', jsonParser, (request, response) => { //Wintermute's cod
.readdirSync(directories.worlds) .readdirSync(directories.worlds)
.filter(file => path.extname(file).toLowerCase() === '.json') .filter(file => path.extname(file).toLowerCase() === '.json')
.sort((a, b) => a < b); .sort((a, b) => a < b);
const koboldai_world_names = worldFiles.map(item => path.parse(item).name); const world_names = worldFiles.map(item => path.parse(item).name);
files.forEach(item => { files.forEach(item => {
const file = fs.readFileSync( const file = fs.readFileSync(
@@ -797,37 +797,12 @@ app.post('/getsettings', jsonParser, (request, response) => { //Wintermute's cod
settings, settings,
koboldai_settings, koboldai_settings,
koboldai_setting_names, koboldai_setting_names,
koboldai_world_names, world_names,
novelai_settings, novelai_settings,
novelai_setting_names novelai_setting_names
}); });
}); });
// Work around to disable parallel requests to endpoint
let kobold_world_sync_busy = false;
app.post('/synckoboldworld', jsonParser, async (request, response) => {
if(!request.body) return response.sendStatus(400);
if (!api_server || kobold_world_sync_busy) {
response.send({ busy: true });
return;
}
try {
kobold_world_sync_busy = true;
const worldName = request.body.name;
await synchronizeKoboldWorldInfo(worldName);
response.send({ ok: true });
} catch (err) {
var message = JSON.stringify(err);
console.error(`Error during world synchronization: ${message}`);
response.status(500).send(message);
} finally {
kobold_world_sync_busy = false;
}
});
app.post('/getworldinfo', jsonParser, (request, response) => { app.post('/getworldinfo', jsonParser, (request, response) => {
if (!request.body?.name) { if (!request.body?.name) {
return response.sendStatus(400); return response.sendStatus(400);
@@ -835,7 +810,7 @@ app.post('/getworldinfo', jsonParser, (request, response) => {
const file = readWorldInfoFile(request.body.name); const file = readWorldInfoFile(request.body.name);
return response.send(file.tavernWorldInfo); return response.send(file);
}); });
app.post('/deleteworldinfo', jsonParser, (request, response) => { app.post('/deleteworldinfo', jsonParser, (request, response) => {
@@ -856,6 +831,23 @@ app.post('/deleteworldinfo', jsonParser, (request, response) => {
return response.sendStatus(200); return response.sendStatus(200);
}); });
function readWorldInfoFile(worldInfoName) {
if (!worldInfoName) {
return { entries: {} };
}
const filename = `${worldInfoName}.json`;
const pathToWorldInfo = path.join(directories.worlds, filename);
if (!fs.existsSync(pathToWorldInfo)) {
throw new Error(`World info file ${filename} doesn't exist.`);
}
const worldInfoText = fs.readFileSync(pathToWorldInfo, 'utf8');
const worldInfo = JSON.parse(worldInfoText);
return worldInfo;
}
function getCharaterFile(directories,response,i){ //old need del function getCharaterFile(directories,response,i){ //old need del
if(directories.length > i){ if(directories.length > i){
@@ -1286,234 +1278,6 @@ app.post('/editworldinfo', jsonParser, (request, response) => {
return response.send({ ok: true }); return response.send({ ok: true });
}); });
function findTavernWorldEntry(info, key, content) {
for (const entryId in info.entries) {
const entry = info.entries[entryId];
const keyString = entry.key.join(',');
if (keyString === key && entry.content === content) {
return entry;
}
}
return null;
}
async function synchronizeKoboldWorldInfo(worldInfoName) {
const { koboldFolderName, tavernWorldInfo } = readWorldInfoFile(worldInfoName);
// Get existing world info
const koboldWorldInfo = await getAsync(`${api_server}/v1/world_info`, baseRequestArgs);
// Validate kobold world info
let {
shouldCreateWorld,
koboldWorldUid,
tavernEntriesToCreate,
koboldEntriesToDelete,
koboldFoldersToDelete,
} = await validateKoboldWorldInfo(koboldFolderName, koboldWorldInfo, tavernWorldInfo);
// Create folder if not already exists
if (koboldFolderName && shouldCreateWorld) {
koboldWorldUid = await createKoboldFolder(koboldFolderName, tavernEntriesToCreate, tavernWorldInfo);
}
await deleteKoboldFolders(koboldFoldersToDelete);
await deleteKoboldEntries(koboldEntriesToDelete);
await createTavernEntries(tavernEntriesToCreate, koboldWorldUid, tavernWorldInfo);
}
function readWorldInfoFile(worldInfoName) {
if (!worldInfoName) {
return { koboldFolderName: null, tavernWorldInfo: { entries: {}, folders: {} }};
}
const koboldFolderName = getKoboldWorldInfoName(worldInfoName);
const filename = `${worldInfoName}.json`;
const pathToWorldInfo = path.join(directories.worlds, filename);
if (!fs.existsSync(pathToWorldInfo)) {
throw new Error(`World info file ${filename} doesn't exist.`);
}
const tavernWorldInfoText = fs.readFileSync(pathToWorldInfo, 'utf8');
const tavernWorldInfo = JSON.parse(tavernWorldInfoText);
return { koboldFolderName, tavernWorldInfo };
}
async function createKoboldFolder(koboldFolderName, tavernEntriesToCreate, tavernWorldInfo) {
const createdFolder = await postAsync(`${api_server}/v1/world_info/folders`, { data: {}, ...baseRequestArgs });
const koboldWorldUid = createdFolder.uid;
// Set a name so we could find the folder later
const setNameArgs = { data: { value: koboldFolderName }, ...baseRequestArgs };
await putAsync(`${api_server}/v1/world_info/folders/${koboldWorldUid}/name`, setNameArgs);
// Create all world info entries
tavernEntriesToCreate.push(...Object.keys(tavernWorldInfo.entries));
return koboldWorldUid;
}
async function createTavernEntries(tavernEntriesToCreate, koboldWorldUid, tavernWorldInfo) {
if (tavernEntriesToCreate.length && koboldWorldUid) {
for (const tavernUid of tavernEntriesToCreate) {
try {
const tavernEntry = tavernWorldInfo.entries[tavernUid];
const koboldEntry = await postAsync(`${api_server}/v1/world_info/folders/${koboldWorldUid}`, { data: {}, ...baseRequestArgs });
await setKoboldEntryData(tavernEntry, koboldEntry);
} catch (err) {
console.error(`Couldn't create Kobold world info entry, tavernUid=${tavernUid}. Skipping...`);
console.error(err);
}
}
}
}
async function deleteKoboldEntries(koboldEntriesToDelete) {
if (koboldEntriesToDelete.length) {
for (const uid of koboldEntriesToDelete) {
try {
await deleteAsync(`${api_server}/v1/world_info/${uid}`);
} catch (err) {
console.error(`Couldn't delete Kobold world info entry, uid=${uid}. Skipping...`);
console.error(err);
}
}
}
}
async function deleteKoboldFolders(koboldFoldersToDelete) {
if (koboldFoldersToDelete.length) {
for (const uid of koboldFoldersToDelete) {
try {
await deleteAsync(api_server + `/v1/world_info/folders/${uid}`, baseRequestArgs);
} catch (err) {
console.error(`Couldn't delete Kobold world info folder, uid=${uid}. Skipping...`);
console.error(err);
}
}
}
}
async function setKoboldEntryData(tavernEntry, koboldEntry) {
// 1. Set primary key
if (tavernEntry.key?.length) {
const keyArgs = { data: { value: tavernEntry.key.join(',') }, ...baseRequestArgs };
await putAsync(`${api_server}/v1/world_info/${koboldEntry.uid}/key`, keyArgs);
}
// 2. Set secondary key
if (tavernEntry.keysecondary?.length) {
const keySecondaryArgs = { data: { value: tavernEntry.keysecondary.join(',') }, ...baseRequestArgs };
await putAsync(`${api_server}/v1/world_info/${koboldEntry.uid}/keysecondary`, keySecondaryArgs);
}
// 3. Set content
if (tavernEntry.content) {
const contentArgs = { data: { value: tavernEntry.content }, ...baseRequestArgs };
await putAsync(`${api_server}/v1/world_info/${koboldEntry.uid}/content`, contentArgs);
}
// 4. Set comment
if (tavernEntry.comment) {
const commentArgs = { data: { value: tavernEntry.comment }, ...baseRequestArgs };
await putAsync(`${api_server}/v1/world_info/${koboldEntry.uid}/comment`, commentArgs);
};
/* Fixed in Kobold United only: https://github.com/henk717/KoboldAI/pull/280 */
try {
// 5. Set constant flag
if (tavernEntry.constant) {
const constantArgs = { data: { value: tavernEntry.constant.toString() }, ...baseRequestArgs };
await putToPromise(`${api_server}/v1/world_info/${koboldEntry.uid}/constant`, constantArgs);
}
// 6. Set selective flag
if (tavernEntry.selective) {
const selectiveArgs = { data: { value: tavernEntry.selective.toString() }, ...baseRequestArgs };
await putToPromise(`${api_server}/v1/world_info/${koboldEntry.uid}/selective`, selectiveArgs);
}
} catch {
// couldn't set fields = ignore
}
}
async function validateKoboldWorldInfo(koboldFolderName, koboldWorldInfo, tavernWorldInfo) {
let shouldCreateWorld = true;
let koboldWorldUid = null;
const koboldEntriesToDelete = []; // KoboldUIDs
const koboldFoldersToDelete = []; // KoboldUIDs
const tavernEntriesToCreate = []; // TavernUIDs
if (koboldWorldInfo?.folders?.length) {
let existingFolderAlreadyFound = false;
for (const folder of koboldWorldInfo.folders) {
// Don't care about non-Tavern folders
if (!isTavernKoboldWorldInfo(folder.name)) {
continue;
}
// Other Tavern folders should be deleted (including dupes). If folder name selected is null, then delete anyway to clean-up
if (!koboldFolderName || folder.name !== koboldFolderName || existingFolderAlreadyFound) {
koboldFoldersToDelete.push(folder.uid);
// Should also delete all entries in folder otherwise they will be detached
if (Array.isArray(folder.entries)) {
koboldEntriesToDelete.push(...folder.entries.map(entry => entry.uid));
}
}
// Validate existing entries in Kobold world
if (folder.name === koboldFolderName) {
existingFolderAlreadyFound = true;
shouldCreateWorld = false;
koboldWorldUid = folder.uid;
if (folder.entries?.length) {
const foundTavernEntries = [];
for (const koboldEntry of folder.entries) {
const tavernEntry = findTavernWorldEntry(tavernWorldInfo, koboldEntry.key, koboldEntry.content);
if (tavernEntry) {
foundTavernEntries.push(tavernEntry.uid);
if (isEntryOutOfSync(tavernEntry, koboldEntry)) {
// Entry is out of sync. Should be recreated
koboldEntriesToDelete.push(koboldEntry.uid);
tavernEntriesToCreate.push(tavernEntry.uid);
}
}
else {
// We don't have that entry in our world. It should be deleted
koboldEntriesToDelete.push(koboldEntry.uid);
}
}
// Check if every tavern entry was found in kobold world
// BTW. Entries is an object, not an array!
for (const tavernEntryUid in tavernWorldInfo.entries) {
const tavernEntry = tavernWorldInfo.entries[tavernEntryUid];
if (!foundTavernEntries.includes(tavernEntry.uid)) {
tavernEntriesToCreate.push(tavernEntry.uid);
}
}
}
}
}
}
return { shouldCreateWorld, koboldWorldUid, tavernEntriesToCreate, koboldEntriesToDelete, koboldFoldersToDelete };
}
function isEntryOutOfSync(tavernEntry, koboldEntry) {
return tavernEntry.content !== koboldEntry.content ||
tavernEntry.comment !== koboldEntry.comment ||
tavernEntry.selective !== koboldEntry.selective ||
tavernEntry.constant !== koboldEntry.constant ||
tavernEntry.key.join(',') !== koboldEntry.key ||
(koboldEntry.selective ? tavernEntry.keysecondary.join(',') !== koboldEntry.keysecondary : false);
}
// ** REST CLIENT ASYNC WRAPPERS ** // ** REST CLIENT ASYNC WRAPPERS **
function deleteAsync(url, args) { function deleteAsync(url, args) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -1560,15 +1324,6 @@ function getAsync(url, args) {
} }
// ** END ** // ** END **
function getKoboldWorldInfoName(worldInfoName) {
return worldInfoName ? `TavernAI_${worldInfoName}_WI` : null;
}
function isTavernKoboldWorldInfo(folderName) {
return /^TavernAI_(.*)_WI$/.test(folderName);
}
app.listen(server_port, function() { app.listen(server_port, function() {
if(process.env.colab !== undefined){ if(process.env.colab !== undefined){
if(process.env.colab == 2){ if(process.env.colab == 2){