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'])
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')
@logger.catch
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
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
#==================================================================#
@app.route("/json")
@app.route("/story_download")
@logger.catch
def UI_2_save_to_json():
def UI_2_download_story():
return Response(
koboldai_vars.to_json('story_settings'),
mimetype="application/json",
headers={"Content-disposition":
"attachment; filename={}.v2.json".format(koboldai_vars.story_name)})
directory_to_zip_data(koboldai_vars.save_paths.base),
mimetype="application/octet-stream",
headers={"Content-disposition": f"attachment; filename={koboldai_vars.story_name}.kaistory"}
)
#==================================================================#

View File

@@ -1008,7 +1008,7 @@ function load_popup(data) {
for (file of fileList) {
reader = new FileReader();
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);
}
@@ -2600,20 +2600,24 @@ function process_log_message(full_data) {
}
//--------------------------------------------UI to Server Functions----------------------------------
async function download_story_to_zip() {
//document.getElementById('download_iframe').src = 'json';
downloaded = false;
async function download_story() {
if (socket.connected) {
try {
let r = await fetch("zip");
let j = await r.json();
downloadString(JSON.stringify(j), j['story_name']+".kaistory")
downloaded = true;
let name = $el(".var_sync_story_story_name").innerText;
let r = await fetch("story_download");
downloadBlob(await r.blob(), `${name}.kaistory`);
return;
}
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.
let allClasses = [];
const allElements = document.querySelectorAll('*');
@@ -2676,7 +2680,6 @@ async function download_story_to_zip() {
j['gamestarted'] = true;
downloadString(JSON.stringify(j), j['story_name']+".json")
}
}
function unload_userscripts() {
@@ -4335,6 +4338,14 @@ function downloadString(string, fileName) {
a.click();
}
function downloadBlob(blob, fileName) {
const a = $e("a", null, {
href: URL.createObjectURL(blob),
download: fileName
});
a.click();
}
function getRedactedValue(value) {
if (typeof value === "string") return `[Redacted string 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) {
// 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", "");
} else if (data.folders !== undefined && data.entries !== undefined) {
// World Info Folder
@@ -4676,9 +4691,16 @@ async function processDroppedFile(file) {
readLoreCard(file);
break;
case "json":
// KoboldAI file
// KoboldAI file (old story, etc)
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;
case "lorebook":
// 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>
<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>
</div>
<div id="text_storyname">