mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
#21 Add world info export, edit popup and deletion
This commit is contained in:
@@ -54,6 +54,7 @@
|
||||
var is_mes_reload_avatar = false;
|
||||
|
||||
var is_advanced_char_open = false;
|
||||
var is_world_edit_open = false;
|
||||
|
||||
var menu_type = '';//what is selected in the menu
|
||||
var selected_button = '';//which button pressed
|
||||
@@ -108,6 +109,7 @@
|
||||
var kobold_world_synced = false;
|
||||
var kobold_sync_failed = false;
|
||||
var kobold_is_united = false;
|
||||
var imported_world_name = '';
|
||||
var max_context = 2048;//2048;
|
||||
var rep_pen = 1;
|
||||
var rep_pen_size = 100;
|
||||
@@ -1524,8 +1526,16 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
if (popup_type === 'world_imported') {
|
||||
// switch to a new world
|
||||
if (popup_type === 'world_imported' && imported_world_name) {
|
||||
koboldai_world_names.forEach((item, i) => {
|
||||
if (item === imported_world_name) {
|
||||
$('#world_info').val(i).change();
|
||||
}
|
||||
})
|
||||
imported_world_name = '';
|
||||
}
|
||||
if (popup_type === 'del_world' && kobold_world) {
|
||||
deleteWorldInfo(kobold_world);
|
||||
}
|
||||
if(popup_type == 'new_chat' && this_chid != undefined && menu_type != "create"){//Fix it; New chat doesn't create while open create character menu
|
||||
clearChat();
|
||||
@@ -1558,6 +1568,7 @@
|
||||
$("#dialogue_popup_ok").css("background-color", "#191b31CC");
|
||||
$("#dialogue_popup_ok").text("Yes");
|
||||
break;
|
||||
case 'del_world':
|
||||
default:
|
||||
$("#dialogue_popup_ok").css("background-color", "#791b31");
|
||||
$("#dialogue_popup_ok").text("Delete");
|
||||
@@ -1963,6 +1974,7 @@
|
||||
kobold_world = !isNaN(worldIndex) ? koboldai_world_names[worldIndex] : null;
|
||||
}
|
||||
|
||||
hideWorldEditor();
|
||||
syncKoboldWorldInfo(true);
|
||||
saveSettings();
|
||||
updateWorldStatus();
|
||||
@@ -2085,6 +2097,7 @@
|
||||
|
||||
function updateWorldStatus() {
|
||||
if($('#world_info_block').is(':visible') && kobold_world) {
|
||||
$('#world_info_edit_button').show();
|
||||
$('#world_status').show();
|
||||
|
||||
if (kobold_world_synced) {
|
||||
@@ -2109,6 +2122,7 @@
|
||||
}
|
||||
} else {
|
||||
$('#world_status').hide();
|
||||
$('#world_info_edit_button').hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2140,7 +2154,7 @@
|
||||
body: JSON.stringify({ "name": kobold_world })
|
||||
});
|
||||
|
||||
if (response.ok === true) {
|
||||
if (response.ok) {
|
||||
const syncData = await response.json();
|
||||
|
||||
if (syncData.ok) {
|
||||
@@ -2327,7 +2341,7 @@
|
||||
$('#world_info').append(`<option value='${i}'>${item}</option>`);
|
||||
// preselect world if saved
|
||||
if (item == kobold_world){
|
||||
$(`#world_info option[value=${i}]`).attr('selected', 'true');
|
||||
$('#world_info').val(i).change();
|
||||
}
|
||||
});
|
||||
// end world info settings
|
||||
@@ -2921,9 +2935,8 @@
|
||||
processData: false,
|
||||
success: function(data){
|
||||
if (data.name) {
|
||||
// TODO reload list of custom worlds to allow selection then offer a popup
|
||||
// popup_type = 'world_imported';
|
||||
// callPopup('<h3>World imported successfully! Select it now?</h3>');
|
||||
imported_world_name = data.name;
|
||||
updateWorldInfoList(imported_world_name);
|
||||
}
|
||||
},
|
||||
error: (jqXHR, exception) => {},
|
||||
@@ -2933,6 +2946,104 @@
|
||||
$('#form_world_import').trigger("reset");
|
||||
});
|
||||
|
||||
async function updateWorldInfoList(importedWorldName) {
|
||||
var result = await fetch('/getsettings', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({})
|
||||
});
|
||||
|
||||
if (result.ok) {
|
||||
var data = await result.json();
|
||||
koboldai_world_names = data.koboldai_world_names?.length ? data.koboldai_world_names : [];
|
||||
$('#world_info').find('option[value!="None"]').remove();
|
||||
|
||||
koboldai_world_names.forEach((item, i) => {
|
||||
$('#world_info').append(`<option value='${i}'>${item}</option>`);
|
||||
});
|
||||
|
||||
if (importedWorldName) {
|
||||
const indexOf = koboldai_world_names.indexOf(kobold_world);
|
||||
$(`#world_info`).val(indexOf);
|
||||
|
||||
popup_type = 'world_imported';
|
||||
callPopup('<h3>World imported successfully! Select it now?</h3>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function download(content, fileName, contentType) {
|
||||
var a = document.createElement("a");
|
||||
var file = new Blob([content], {type: contentType});
|
||||
a.href = URL.createObjectURL(file);
|
||||
a.download = fileName;
|
||||
a.click();
|
||||
}
|
||||
|
||||
// World Info Editor
|
||||
async function showWorldEditor() {
|
||||
is_world_edit_open = true;
|
||||
$('#world_text_content').val('');
|
||||
$('#world_popup').css('display', 'flex');
|
||||
|
||||
if (kobold_world) {
|
||||
const response = await fetch("/getworldinfo", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ name: kobold_world })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const worldInfoData = await response.text();
|
||||
$('#world_text_content').val(worldInfoData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hideWorldEditor() {
|
||||
is_world_edit_open = false;
|
||||
$('#world_popup').css('display', 'none');
|
||||
$('#world_text_content').val('');
|
||||
}
|
||||
|
||||
async function deleteWorldInfo(worldInfoName) {
|
||||
if (!koboldai_world_names.includes(worldInfoName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch("/deleteworldinfo", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ name: worldInfoName })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
await updateWorldInfoList();
|
||||
$('#world_info').val('None').change();
|
||||
hideWorldEditor();
|
||||
}
|
||||
}
|
||||
|
||||
$('#world_info_edit_button').click(() => {
|
||||
is_world_edit_open ? hideWorldEditor() : showWorldEditor();
|
||||
});
|
||||
|
||||
$('#world_popup_export').click(() => {
|
||||
const jsonValue = $('#world_text_content').val();
|
||||
if (kobold_world && jsonValue) {
|
||||
const fileName = `${kobold_world}.json`;
|
||||
download(jsonValue, fileName, 'application/json');
|
||||
}
|
||||
});
|
||||
|
||||
$('#world_popup_delete').click(() => {
|
||||
popup_type = 'del_world';
|
||||
callPopup('<h3>Delete the World Info?</h3>');
|
||||
});
|
||||
|
||||
$('#world_cross').click(() => {
|
||||
hideWorldEditor();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<title>Tavern.AI</title>
|
||||
@@ -2990,6 +3101,27 @@
|
||||
<div></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="world_popup">
|
||||
<div id="world_popup_text">
|
||||
<img id="world_cross" src="img/cross.png">
|
||||
<div>
|
||||
<!-- Probably needs a logo (probably) -->
|
||||
<!-- <img src="img/book2.png" id="world_logo"> -->
|
||||
<h3>World Info creation</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Placeholder until actual editor is implemented -->
|
||||
<h4>File content (read-only)</h4>
|
||||
<textarea id="world_text_content" placeholder="Loading..." form="form_create" disabled></textarea>
|
||||
|
||||
<div id="world_popup_bottom_holder">
|
||||
<div id="world_popup_export" class="menu_button">Export</div>
|
||||
<div id="world_popup_delete" class="menu_button">Delete</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="shadow_select_chat_popup">
|
||||
<div id="select_chat_popup">
|
||||
<div id="select_chat_popup_text">
|
||||
@@ -3141,7 +3273,11 @@
|
||||
<input type="range" id="rep_pen_size" name="volume" min="0" max="2048" step="1">
|
||||
</div>
|
||||
<div>
|
||||
<h4 id="world_info_block">World Info</h4><h5>How to use (<a href="/notes/13" target="_blank">?</a>)</h5>
|
||||
<h4 id="world_info_block">
|
||||
World Info
|
||||
<div id="world_import_button" class="right_menu_button"><h2>+Import</h2></div>
|
||||
<h5>How to use (<a href="/notes/13" target="_blank">?</a>)</h5>
|
||||
</h4>
|
||||
<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">
|
||||
@@ -3150,7 +3286,7 @@
|
||||
<select id="world_info" class="option_select_right_menu">
|
||||
<option value="None">None</option>
|
||||
</select>
|
||||
<div id="world_import_button" class="right_menu_button"><h2>+Import</h2></div>
|
||||
<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>
|
||||
|
@@ -956,12 +956,15 @@ input[type=button] {
|
||||
|
||||
#world_info {
|
||||
margin-bottom: 12px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
#world_status{
|
||||
opacity: 0.5;
|
||||
margin-top: 2px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#world_status_indicator{
|
||||
border-radius: 7px;
|
||||
width: 14px;
|
||||
@@ -969,21 +972,99 @@ input[type=button] {
|
||||
background-color: red;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#world_status_text {
|
||||
margin-left: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#world_import_button {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#world_import_button h2 {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
font-size: 17px;
|
||||
margin-left: 1rem;
|
||||
font-size: 16px;
|
||||
color: rgb(188, 193, 200, 0.5);
|
||||
}
|
||||
|
||||
#world_info_edit_button {
|
||||
cursor: pointer;
|
||||
color: #ffffffaa;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
#world_popup {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
max-width: 800px;
|
||||
height: 83vh;
|
||||
position: absolute;
|
||||
z-index: 2060;
|
||||
background-color: blue;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-top: 0px;
|
||||
box-shadow: 0 0 2px rgba(200, 200, 200, 0.1);
|
||||
padding: 4px 36px;
|
||||
background: #191b31F5;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
#world_text_content {
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#world_popup_bottom_holder {
|
||||
padding: 1rem 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
#world_popup_bottom_holder div {
|
||||
margin-left: 1rem;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#world_cross {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 15px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
#world_popup h5 a {
|
||||
color: #936f4a;
|
||||
}
|
||||
|
||||
#world_popup h5 a:hover {
|
||||
color: #998e6b;
|
||||
}
|
||||
|
||||
#world_popup h4 a {
|
||||
color: #936f4a;
|
||||
}
|
||||
|
||||
#world_popup h4 a:hover {
|
||||
color: #998e6b;
|
||||
}
|
||||
|
||||
#world_popup h5 {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
.del_checkbox{
|
||||
display: none;
|
||||
opacity: 0.5;
|
||||
|
27
server.js
27
server.js
@@ -709,6 +709,33 @@ app.post('/synckoboldworld', jsonParser, async (request, response) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/getworldinfo', jsonParser, async (request, response) => {
|
||||
if (!request.body?.name) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const file = readWorldInfoFile(request.body.name);
|
||||
|
||||
return response.send(file.tavernWorldInfo);
|
||||
});
|
||||
|
||||
app.post('/deleteworldinfo', jsonParser, async (request, response) => {
|
||||
if (!request.body?.name) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const worldInfoName = request.body.name;
|
||||
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.`);
|
||||
}
|
||||
|
||||
fs.rmSync(pathToWorldInfo);
|
||||
|
||||
return response.sendStatus(200);
|
||||
});
|
||||
|
||||
function getCharaterFile(directories,response,i){ //old need del
|
||||
if(directories.length > i){
|
||||
|
Reference in New Issue
Block a user