Story import / export

This commit is contained in:
somebody
2022-12-01 21:48:17 -06:00
parent 34fce81209
commit 930c592206
3 changed files with 139 additions and 78 deletions

View File

@@ -7916,6 +7916,31 @@ def upload_file(data):
f.write(data['data']) f.write(data['data'])
get_files_folders(session['current_folder']) get_files_folders(session['current_folder'])
@app.route("/upload_kai_story/<string:file_name>", methods=["POST"])
@logger.catch
def UI_2_upload_kai_story(file_name: str):
assert "/" not in file_name
raw_folder_name = file_name.replace(".kaistory", "")
folder_path = path.join("stories", raw_folder_name)
disambiguator = 0
while path.exists(folder_path):
disambiguator += 1
folder_path = path.join("stories", f"{raw_folder_name} ({disambiguator})")
buffer = BytesIO()
dat = request.get_data()
with open("debug.zip", "wb") as file:
file.write(dat)
buffer.write(dat)
with zipfile.ZipFile(buffer, "r") as zipf:
zipf.extractall(folder_path)
return ":)"
@socketio.on('popup_change_folder') @socketio.on('popup_change_folder')
@logger.catch @logger.catch
def popup_change_folder(data): def popup_change_folder(data):
@@ -8329,17 +8354,31 @@ def UI_2_save_story(data):
#We have an ack that it's OK to save over the file if one exists #We have an ack that it's OK to save over the file if one exists
koboldai_vars.save_story() koboldai_vars.save_story()
def directory_to_zip_data(directory: str) -> bytes:
buffer = BytesIO()
with zipfile.ZipFile(buffer, "w") as zipf:
for root, _, files in os.walk(directory):
for file in files:
p = os.path.join(root, file)
zipf.write(
p,
os.path.join(*p.split(os.path.sep)[2:])
)
return buffer.getvalue()
#==================================================================# #==================================================================#
# Save story to json # Save story to json
#==================================================================# #==================================================================#
@app.route("/json") @app.route("/story_download")
@logger.catch @logger.catch
def UI_2_save_to_json(): def UI_2_download_story():
return Response( return Response(
koboldai_vars.to_json('story_settings'), directory_to_zip_data(koboldai_vars.save_paths.base),
mimetype="application/json", mimetype="application/octet-stream",
headers={"Content-disposition": headers={"Content-disposition": f"attachment; filename={koboldai_vars.story_name}.kaistory"}
"attachment; filename={}.v2.json".format(koboldai_vars.story_name)}) )
#==================================================================# #==================================================================#

View File

@@ -1008,7 +1008,7 @@ function load_popup(data) {
for (file of fileList) { for (file of fileList) {
reader = new FileReader(); reader = new FileReader();
reader.onload = function (event) { reader.onload = function (event) {
socket.emit("upload_file", {'filename': file.name, "data": event.target.result}); socket.emit("upload_file", {'filename': file.name, "data": event.target.result, 'upload_no_save': true});
}; };
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);
} }
@@ -2600,20 +2600,24 @@ function process_log_message(full_data) {
} }
//--------------------------------------------UI to Server Functions---------------------------------- //--------------------------------------------UI to Server Functions----------------------------------
async function download_story_to_zip() { async function download_story() {
//document.getElementById('download_iframe').src = 'json';
downloaded = false;
if (socket.connected) { if (socket.connected) {
try { try {
let r = await fetch("zip"); let name = $el(".var_sync_story_story_name").innerText;
let j = await r.json(); let r = await fetch("story_download");
downloadString(JSON.stringify(j), j['story_name']+".kaistory") downloadBlob(await r.blob(), `${name}.kaistory`);
downloaded = true; return;
} }
catch(err) { catch(err) {
downloaded = false; console.error("Error in online download");
console.error(err);
} }
} if (downloaded == false) { }
console.warn("Online download failed! Using offline download...")
/* Offline Download - Compile JSON file from what we have in ram */
//first we're going to find all the var_sync_story_ classes used in the document. //first we're going to find all the var_sync_story_ classes used in the document.
let allClasses = []; let allClasses = [];
const allElements = document.querySelectorAll('*'); const allElements = document.querySelectorAll('*');
@@ -2677,7 +2681,6 @@ async function download_story_to_zip() {
downloadString(JSON.stringify(j), j['story_name']+".json") downloadString(JSON.stringify(j), j['story_name']+".json")
} }
}
function unload_userscripts() { function unload_userscripts() {
files_to_unload = document.getElementById('loaded_userscripts'); files_to_unload = document.getElementById('loaded_userscripts');
@@ -4335,6 +4338,14 @@ function downloadString(string, fileName) {
a.click(); a.click();
} }
function downloadBlob(blob, fileName) {
const a = $e("a", null, {
href: URL.createObjectURL(blob),
download: fileName
});
a.click();
}
function getRedactedValue(value) { function getRedactedValue(value) {
if (typeof value === "string") return `[Redacted string with length ${value.length}]`; if (typeof value === "string") return `[Redacted string with length ${value.length}]`;
if (value instanceof Array) return `[Redacted array with length ${value.length}]`; if (value instanceof Array) return `[Redacted array with length ${value.length}]`;
@@ -4593,10 +4604,14 @@ async function loadNAILorebook(data, filename, image=null) {
} }
} }
async function loadKoboldData(data, filename) { async function loadKoboldJSON(data, filename) {
if (data.gamestarted !== undefined) { if (data.gamestarted !== undefined) {
// Story // Story
socket.emit("upload_file", {"filename": filename, "data": JSON.stringify(data)}); socket.emit("upload_file", {
filename: filename,
data: new Blob([JSON.stringify(data)]),
upload_no_save: true
});
socket.emit("load_story_list", ""); socket.emit("load_story_list", "");
} else if (data.folders !== undefined && data.entries !== undefined) { } else if (data.folders !== undefined && data.entries !== undefined) {
// World Info Folder // World Info Folder
@@ -4676,9 +4691,16 @@ async function processDroppedFile(file) {
readLoreCard(file); readLoreCard(file);
break; break;
case "json": case "json":
// KoboldAI file // KoboldAI file (old story, etc)
data = JSON.parse(await file.text()); data = JSON.parse(await file.text());
loadKoboldData(data, file.name); loadKoboldJSON(data, file.name);
break;
case "kaistory":
// KoboldAI story file
let r = await fetch(`/upload_kai_story/${file.name}`, {
method: "POST",
body: file
});
break; break;
case "lorebook": case "lorebook":
// NovelAI lorebook, JSON encoded. // NovelAI lorebook, JSON encoded.

View File

@@ -60,7 +60,7 @@
<span class="var_sync_story_story_name fullwidth" contenteditable=true onblur="sync_to_server(this);"></span> <span class="var_sync_story_story_name fullwidth" contenteditable=true onblur="sync_to_server(this);"></span>
</span> </span>
<span> <span>
<span class="material-icons-outlined cursor" style="padding-top: 8px;" tooltip="Download Story" onclick="download_story_to_zip()">file_download</span> <span class="material-icons-outlined cursor" style="padding-top: 8px;" tooltip="Download Story" onclick="download_story();">file_download</span>
</span> </span>
</div> </div>
<div id="text_storyname"> <div id="text_storyname">