mirror of
https://github.com/KoboldAI/KoboldAI-Client.git
synced 2025-06-05 21:59:24 +02:00
Story import / export
This commit is contained in:
51
aiserver.py
51
aiserver.py
@@ -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)})
|
)
|
||||||
|
|
||||||
|
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
|
@@ -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.
|
||||||
|
@@ -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">
|
||||||
|
Reference in New Issue
Block a user