#502 Import Novel Lorebooks (JSON-based)

This commit is contained in:
Cohee
2023-06-23 18:43:11 +03:00
parent 6cbfb56fff
commit 2302785242
3 changed files with 54 additions and 14 deletions

View File

@@ -1973,7 +1973,7 @@
<div id="world_popup_new" class="menu_button fa-solid fa-plus" title="New Entry"></div>
<div class="flex-container">
<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" hidden>
<input type="file" id="world_import_file" accept=".json,.lorebook" name="avatar" hidden>
</form>
<form id="form_rename_world" action="javascript:void(null);" method="post" enctype="multipart/form-data">
<div id="world_create_button" class="menu_button fa-solid fa-globe fa-fw" title="Create"></div>

View File

@@ -1,5 +1,5 @@
import { saveSettings, callPopup, substituteParams, getTokenCount, getRequestHeaders, chat_metadata, this_chid, characters } from "../script.js";
import { download, debounce, initScrollHeight, resetScrollHeight } from "./utils.js";
import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile } from "./utils.js";
import { getContext } from "./extensions.js";
import { metadata_keys, shouldWIAddPrompt } from "./extensions/floating-prompt/index.js";
import { registerSlashCommand } from "./slash-commands.js";
@@ -823,6 +823,35 @@ function matchKeys(haystack, needle) {
return false;
}
function convertNovelLorebook(inputObj) {
const outputObj = {
entries: {}
};
inputObj.entries.forEach((entry, index) => {
const displayName = entry.displayName;
const addMemo = displayName !== undefined && displayName.trim() !== '';
outputObj.entries[index] = {
uid: index,
key: entry.keys,
keysecondary: [],
comment: displayName || '',
content: entry.text,
constant: false,
selective: false,
order: entry.contextConfig?.budgetPriority ?? 0,
position: 0,
disable: !entry.enabled,
addMemo: addMemo,
excludeRecursion: false,
displayIndex: index,
};
});
return outputObj;
}
function convertCharacterBook(characterBook) {
const result = { entries: {} };
@@ -913,20 +942,29 @@ jQuery(() => {
$("#world_import_file").trigger('click');
});
$("#world_import_file").on("change", function (e) {
var file = e.target.files[0];
$("#world_import_file").on("change", async function (e) {
const file = e.target.files[0];
if (!file) {
return;
}
const ext = file.name.match(/\.(\w+)$/);
if (!ext || ext[1].toLowerCase() !== "json") {
const formData = new FormData($("#form_world_import").get(0));
try {
// File should be a JSON file
const jsonData = await parseJsonFile(file);
// Convert Novel Lorebook
if (jsonData.lorebookVersion !== undefined) {
formData.append('convertedData', JSON.stringify(convertNovelLorebook(jsonData)));
}
} catch (error) {
toastr.error(`Error parsing file: ${error}`);
return;
}
const formData = new FormData($("#form_world_import").get(0));
jQuery.ajax({
type: "POST",
url: "/importworldinfo",

View File

@@ -2105,15 +2105,17 @@ app.post("/importchat", urlencodedParser, function (request, response) {
app.post('/importworldinfo', urlencodedParser, (request, response) => {
if (!request.file) return response.sendStatus(400);
const filename = sanitize(request.file.originalname);
const filename = `${path.parse(sanitize(request.file.originalname)).name}.json`;
if (path.parse(filename).ext.toLowerCase() !== '.json') {
return response.status(400).send('Only JSON files are supported.')
let fileContents = null;
if (request.body.convertedData) {
fileContents = request.body.convertedData;
} else {
const pathToUpload = path.join('./uploads/', request.file.filename);
fileContents = fs.readFileSync(pathToUpload, 'utf8');
}
const pathToUpload = path.join('./uploads/', request.file.filename);
const fileContents = fs.readFileSync(pathToUpload, 'utf8');
try {
const worldContent = json5.parse(fileContents);
if (!('entries' in worldContent)) {