diff --git a/aiserver.py b/aiserver.py index a25ae047..6880ebfa 100644 --- a/aiserver.py +++ b/aiserver.py @@ -263,8 +263,10 @@ def sendModelSelection(menu="mainmenu", folder="./models"): else: showdelete=False emit('from_server', {'cmd': 'show_model_menu', 'data': menu_list, 'menu': menu, 'breadcrumbs': breadcrumbs, "showdelete": showdelete}, broadcast=True, room="UI_1") + emit('show_model_menu', {'data': menu_list, 'menu': menu, 'breadcrumbs': breadcrumbs, "showdelete": showdelete}, broadcast=False, room="UI_2") else: emit('from_server', {'cmd': 'show_model_menu', 'data': model_menu[menu], 'menu': menu, 'breadcrumbs': [], "showdelete": False}, broadcast=True, room="UI_1") + emit('show_model_menu', {'data': model_menu[menu], 'menu': menu, 'breadcrumbs': [], "showdelete": False}, broadcast=False, room="UI_2") def get_folder_path_info(base): if base == 'This PC': @@ -333,7 +335,7 @@ def check_if_dir_is_model(path): if os.path.exists(path): try: from transformers import AutoConfig - model_config = AutoConfig.from_pretrained(path, revision=koboldai_vars.revision, cache_dir="cache") + model_config = AutoConfig.from_pretrained(path) except: return False return True @@ -1034,12 +1036,18 @@ def get_model_info(model, directory=""): break_values = break_values.split(",") else: break_values = [layer_count] + break_values = [int(x) for x in break_values] break_values += [0] * (gpu_count - len(break_values)) emit('from_server', {'cmd': 'selected_model_info', 'key_value': key_value, 'key':key, 'gpu':gpu, 'layer_count':layer_count, 'breakmodel':breakmodel, 'disk_break_value': disk_blocks, 'accelerate': utils.HAS_ACCELERATE, 'break_values': break_values, 'gpu_count': gpu_count, 'url': url, 'gpu_names': gpu_names}, broadcast=True, room="UI_1") + emit('selected_model_info', {'key_value': key_value, 'key':key, + 'gpu':gpu, 'layer_count':layer_count, 'breakmodel':breakmodel, + 'disk_break_value': disk_blocks, 'disk_break': not utils.HAS_ACCELERATE, + 'break_values': break_values, 'gpu_count': gpu_count, + 'url': url, 'gpu_names': gpu_names}, broadcast=False, room="UI_2") if key_value != "": get_oai_models(key_value) @@ -1047,18 +1055,16 @@ def get_model_info(model, directory=""): def get_layer_count(model, directory=""): if(model not in ["InferKit", "Colab", "OAI", "GooseAI" , "ReadOnly", "TPUMeshTransformerGPTJ"]): if(koboldai_vars.model == "GPT2Custom"): - model_config = open(koboldai_vars.custmodpth + "/config.json", "r") + model_config = open(directory + "/config.json", "r") # Get the model_type from the config or assume a model type if it isn't present else: from transformers import AutoConfig if directory == "": - model_config = AutoConfig.from_pretrained(koboldai_vars.model, revision=koboldai_vars.revision, cache_dir="cache") - elif(os.path.isdir(koboldai_vars.custmodpth.replace('/', '_'))): - model_config = AutoConfig.from_pretrained(koboldai_vars.custmodpth.replace('/', '_'), revision=koboldai_vars.revision, cache_dir="cache") - elif(os.path.isdir(directory)): - model_config = AutoConfig.from_pretrained(directory, revision=koboldai_vars.revision, cache_dir="cache") + model_config = AutoConfig.from_pretrained(model, cache_dir="cache") + elif os.path.isdir(directory): + model_config = AutoConfig.from_pretrained(directory, cache_dir="cache") else: - model_config = AutoConfig.from_pretrained(koboldai_vars.custmodpth, revision=koboldai_vars.revision, cache_dir="cache") + assert "Selected Model directory doesn't exist" @@ -5821,8 +5827,177 @@ def new_ui_index(): def ui2_connect(): #Send all variables to client koboldai_vars.send_to_ui() + pass +#==================================================================# +# File Popup options +#==================================================================# +@app.route("/popup_test") +def popup_test(): + file_popup("Test Popup", "./", "return_event_name", folder_only=False, editable=True, deleteable=True, jailed=False, item_check=check_if_dir_is_model) + return "ok" + +@socketio.on('popup_change_folder') +def popup_change_folder(data): + print("Doing popup change folder: {}".format(data)) + if 'popup_jailed_dir' not in session: + print("Someone is trying to get at files in your server. Blocked.") + return + if session['popup_jailed_dir'] is None: + get_files_folders(data) + elif session['popup_jailed_dir'] in data: + get_files_folders(data) + else: + print("User is trying to get at files in your server outside the jail. Blocked. Jailed Dir: {} Requested Dir: {}".format(session['popup_jailed_dir'], data)) + +@socketio.on('popup_delete') +def popup_delete(data): + if 'popup_deletable' not in session: + print("Someone is trying to delete a file in your server. Blocked.") + return + if not session['popup_deletable']: + print("Someone is trying to delete a file in your server. Blocked.") + return + + if session['popup_jailed_dir'] is None: + import shutil + if os.path.isdir(data): + shutil.rmtree(data) + else: + os.remove(data) + path = os.path.abspath(data).replace("\\", "/") + if path[-1] == "/": + path = path[:-1] + path = "/".join(path.split("/")[:-1]) + get_files_folders(path) + elif session['popup_jailed_dir'] in data: + import shutil + if os.path.isdir(data): + shutil.rmtree(data) + else: + os.remove(data) + path = os.path.abspath(data).replace("\\", "/") + if path[-1] == "/": + path = path[:-1] + path = "/".join(path.split("/")[:-1]) + get_files_folders(path) + else: + print("User is trying to delete files in your server outside the jail. Blocked. Jailed Dir: {} Requested Dir: {}".format(session['popup_jailed_dir'], data)) + +@socketio.on('popup_edit') +def popup_edit(data): + if 'popup_editable' not in session: + print("Someone is trying to edit a file in your server. Blocked.") + return + if not session['popup_editable']: + print("Someone is trying to edit a file in your server. Blocked.") + return + + if session['popup_jailed_dir'] is None: + emit("popup_edit_file", {"file": data, "text": open(data, 'r').read()}); + elif session['popup_jailed_dir'] in data: + emit("popup_edit_file", {"file": data, "text": open(data, 'r').read()}); + else: + print("User is trying to delete files in your server outside the jail. Blocked. Jailed Dir: {} Requested Dir: {}".format(session['popup_jailed_dir'], data)) + +@socketio.on('popup_change_file') +def popup_change_file(data): + if 'popup_editable' not in session: + print("Someone is trying to edit a file in your server. Blocked.") + return + if not session['popup_editable']: + print("Someone is trying to edit a file in your server. Blocked.") + return + + if session['popup_jailed_dir'] is None: + with open(data['file'], 'w') as f: + f.write(data['data']) + elif session['popup_jailed_dir'] in data['file']: + with open(data['file'], 'w') as f: + f.write(data['data']) + else: + print("User is trying to delete files in your server outside the jail. Blocked. Jailed Dir: {} Requested Dir: {}".format(session['popup_jailed_dir'], data)) + +def file_popup(popup_title, starting_folder, return_event, jailed=True, folder_only=True, deleteable=False, editable=False, show_breadcrumbs=True, item_check=None, show_hidden=False): + #starting_folder = The folder we're going to get folders and/or items from + #return_event = the socketio event that will be emitted when the load button is clicked + #jailed = if set to true will look for the session variable jailed_folder and prevent navigation outside of that folder + #folder_only = will only show folders, no files + #deletable = will show the delete icons/methods. + #editable = will show the edit icons/methods + #show_breadcrumbs = will show the breadcrumbs at the top of the screen + #item_check will call this function to check if the item is valid as a selection if not none. Will pass absolute directory as only argument to function + #show_hidden = ... really, you have to ask? + if jailed: + session['popup_jailed_dir'] = os.path.abspath(starting_folder).replace("\\", "/") + else: + session['popup_jailed_dir'] = None + session['popup_deletable'] = deleteable + session['popup_editable'] = editable + session['popup_show_hidden'] = show_hidden + session['popup_item_check'] = item_check + session['popup_folder_only'] = folder_only + session['popup_show_breadcrumbs'] = show_breadcrumbs + + socketio.emit("load_popup", {"popup_title": popup_title, "call_back": return_event, "deleteable": deleteable, "editable": editable}, broadcast=True, room="UI_2") + socketio.emit("load_popup", {"popup_title": popup_title, "call_back": return_event, "deleteable": deleteable, "editable": editable}, broadcast=True, room="UI_1") + + get_files_folders(starting_folder) + + +def get_files_folders(starting_folder): + import stat + item_check = session['popup_item_check'] + show_breadcrumbs = session['popup_show_breadcrumbs'] + show_hidden = session['popup_show_hidden'] + folder_only = session['popup_folder_only'] + + if starting_folder == 'This PC': + breadcrumbs = [['This PC', 'This PC']] + items = [["{}:/".format(chr(i)), "{}:\\".format(chr(i))] for i in range(65, 91) if os.path.exists("{}:".format(chr(i)))] + else: + path = os.path.abspath(starting_folder).replace("\\", "/") + if path[-1] == "/": + path = path[:-1] + breadcrumbs = [] + for i in range(len(path.split("/"))): + breadcrumbs.append(["/".join(path.split("/")[:i+1]), + path.split("/")[i]]) + if len(breadcrumbs) == 1: + breadcrumbs = [["{}:/".format(chr(i)), "{}:\\".format(chr(i))] for i in range(65, 91) if os.path.exists("{}:".format(chr(i)))] + else: + if len([["{}:/".format(chr(i)), "{}:\\".format(chr(i))] for i in range(65, 91) if os.path.exists("{}:".format(chr(i)))]) > 0: + breadcrumbs.insert(0, ['This PC', 'This PC']) + folders = [] + files = [] + base_path = os.path.abspath(starting_folder).replace("\\", "/") + for item in os.listdir(base_path): + item_full_path = os.path.join(base_path, item).replace("\\", "/") + if hasattr(os.stat(item_full_path), "st_file_attributes"): + hidden = bool(os.stat(item_full_path).st_file_attributes & stat.FILE_ATTRIBUTE_HIDDEN) + else: + hidden = item[0] == "." + if item_check is None: + valid_selection = True + else: + valid_selection = item_check(item_full_path) + + if (show_hidden and hidden) or not hidden: + if os.path.isdir(os.path.join(base_path, item)): + folders.append([True, item_full_path, item, valid_selection]) + else: + files.append([False, item_full_path, item, valid_selection]) + items = folders + if not folder_only: + items += files + + socketio.emit("popup_items", items, broadcast=True, include_self=True, room="UI_2") + socketio.emit("popup_items", items, broadcast=True, include_self=True, room="UI_1") + if show_breadcrumbs: + socketio.emit("popup_breadcrumbs", breadcrumbs, broadcast=True, room="UI_2") + socketio.emit("popup_breadcrumbs", breadcrumbs, broadcast=True, room="UI_1") + #==================================================================# # Event triggered when browser SocketIO detects a variable change #==================================================================# @@ -5914,6 +6089,26 @@ def UI_2_retry(data): koboldai_vars.recentrng = koboldai_vars.recentrngm = None actionsubmit("", actionmode=koboldai_vars.actionmode) +#==================================================================# +# Event triggered when user clicks the load model button +#==================================================================# +@socketio.on('load_model_button') +def UI_2_load_model_button(data): + sendModelSelection() + +#==================================================================# +# Event triggered when user clicks the a model +#==================================================================# +@socketio.on('select_model') +def UI_2_load_model_button(data): + if data['model'] in model_menu: + sendModelSelection(menu=data['model']) + else: + #We now have some model we want to potentially load. + #First we need to send the client the model parameters (layers, etc) + print("getting model info for {}".format(data['model'])) + get_model_info(data['model']) + #==================================================================# # Event triggered to rely a message #==================================================================# diff --git a/static/koboldai.css b/static/koboldai.css index eccbc31e..c8fcac85 100644 --- a/static/koboldai.css +++ b/static/koboldai.css @@ -21,6 +21,8 @@ --enabled_button_text: #fff; --enabled_button_background_color: #337ab7; --enabled_button_border_color: #2e6da4; + --popup_title_bar_color: #337AB7; + --popup_item_color: #262626; --disabled_button_text: #303030; --disabled_button_background_color: #686c68; --disabled_button_border_color: #686c68; @@ -543,6 +545,161 @@ td.sequence:hover { overflow: hidden; } + +/*---------------------------------- Popup -------------------------------------------------*/ +.popup { + position: absolute; + top: 10vh; + left: 10%; + z-index: 999; + width: 80%; + height: 80vh; + background-color: black; + display: flex; + flex-direction: column; + overflow-x: hidden; +} + +.popup .title { + width: 100%; + background-color: var(--popup_title_bar_color); + text-align: center; + font-size: 1.3em; +} + +.popup .popup_list_area { + height: 70vh; + overflow-x: hidden; +} + +.popup .item { + width: 100%; + background-color: var(--popup_item_color); + padding: 2px; + display: grid; + grid-template-areas: "folder_icon delete_icon edit_icon file"; + grid-template-columns: 20px 20px 20px auto; + +} + +.popup .item .folder_icon { + grid-area: folder_icon; +} + +.popup .item .edit_icon { + grid-area: edit_icon; +} + +.popup .item .delete_icon { + grid-area: delete_icon; +} + +.popup .item .file { + grid-area: file; + display: grid; +} + +.popup .item .file:hover { + background-color: #688f1f; +} + +.popup .popup_load_cancel { + text-align: center; + background-color: var(--popup_title_bar_color); +} + +.popup_load_cancel_button { + vertical-align: bottom; + display: inline; +} + +.breadcrumbitem { + padding: 5px 10px 5px 10px; + color: #ffffff; + background-color: transparent; + border: none; + + -moz-transition: background-color 0.25s ease-in; + -o-transition: background-color 0.25s ease-in; + -webkit-transition: background-color 0.25s ease-in; + transition: background-color 0.25s ease-in; +} + +.breadcrumbitem:hover { + cursor: pointer; + background-color: #688f1f; +} +/*----------------------------- Model Load Popup ------------------------------------------*/ + +.popup .item .model { + grid-area: file; + display: grid; + grid-template-areas: "item gpu_size"; + grid-template-columns: auto 40px; +} + +.popup .item .model:hover { + background-color: #688f1f; +} + +.popup .item .model.selected { + background-color: #688f1f; +} + +.model_setting_container { + display: grid; + grid-template-areas: "label label" + "item item" + "minlabel maxlabel"; + grid-template-rows: 20px 25px 10px; + grid-template-columns: auto 40px; + row-gap: 0.2em; + border: 1px; + margin: 2px; +} + +.model_setting_minlabel { + grid-area: minlabel; + overflow: hidden; + text-align: left; + font-size: 0.8em; +} + +.model_setting_maxlabel { + grid-area: maxlabel; + overflow: hidden; + text-align: right; + font-size: 0.8em; +} + +.model_setting_label { + grid-area: label; + overflow: hidden; + text-align: left; +} + +.model_setting_value { + text-align: left; + grid-area: label; + background-color: inherit; + color: inherit; + border: none; + outline: none; +} + +.model_setting_value:focus { + color: var(--text_edit); +} + +.model_setting_item { + grid-area: item; + overflow: hidden; +} + +.model_setting_item_input { + width:95%; +} + /*---------------------------------- Global ------------------------------------------------*/ .hidden { display: none; @@ -573,7 +730,7 @@ input { } -.action_button.disabled { +button.disabled { color: var(--disabled_button_text); background-color: var(--disabled_button_background_color); border-color: var(--disabled_button_border_color); @@ -595,4 +752,8 @@ input { .rawtext { white-space: pre-wrap; +} + +.text_red { + color: red; } \ No newline at end of file diff --git a/static/koboldai.js b/static/koboldai.js index 7eca766e..391964f0 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -8,11 +8,19 @@ socket.on("disconnect", (reason, details) => { }); socket.on('reset_story', function(){reset_story();}); socket.on('var_changed', function(data){var_changed(data);}); +socket.on('load_popup', function(data){load_popup(data);}); +socket.on('popup_items', function(data){popup_items(data);}); +socket.on('popup_breadcrumbs', function(data){popup_breadcrumbs(data);}); +socket.on('popup_edit_file', function(data){popup_edit_file(data);}); +socket.on('show_model_menu', function(data){show_model_menu(data);}); +socket.on('selected_model_info', function(data){selected_model_info(data);}); //socket.onAny(function(event_name, data) {console.log({"event": event_name, "class": data.classname, "data": data});}); var backend_vars = {}; var presets = {} var ai_busy_start = Date.now(); +var popup_deleteable = false; +var popup_editable = false; //-----------------------------------Server to UI Functions----------------------------------------------- function connect() { console.log("connected"); @@ -276,9 +284,465 @@ function var_changed(data) { } } +function load_popup(data) { + popup_deleteable = data.deleteable; + popup_editable = data.editable; + var popup = document.getElementById("popup"); + var popup_title = document.getElementById("popup_title"); + popup_title.textContent = data.popup_title; + var popup_list = document.getElementById("popup_list"); + //first, let's clear out our existing data + while (popup_list.firstChild) { + popup_list.removeChild(popup_list.firstChild); + } + var breadcrumbs = document.getElementById('popup_breadcrumbs'); + while (breadcrumbs.firstChild) { + breadcrumbs.removeChild(breadcrumbs.firstChild); + } + + popup.classList.remove("hidden"); + + //adjust accept button + var accept = document.getElementById("popup_accept"); + accept.classList.add("disabled"); + accept.setAttribute("emit", data.call_back); + accept.setAttribute("selected_value", ""); + accept.onclick = function () { + socket.emit(this.emit, this.getAttribute("selected_value")); + document.getElementById("popup").classList.add("hidden"); + }; + +} + +function popup_items(data) { + var popup_list = document.getElementById('popup_list'); + //first, let's clear out our existing data + while (popup_list.firstChild) { + popup_list.removeChild(popup_list.firstChild); + } + + for (item of data) { + var list_item = document.createElement("span"); + list_item.classList.add("item"); + + //create the folder icon + var folder_icon = document.createElement("span"); + folder_icon.classList.add("folder_icon"); + if (item[0]) { + folder_icon.classList.add("oi"); + folder_icon.setAttribute('data-glyph', "folder"); + } + list_item.append(folder_icon); + + //create the edit icon + var edit_icon = document.createElement("span"); + edit_icon.classList.add("edit_icon"); + if ((popup_editable) && !(item[0])) { + edit_icon.classList.add("oi"); + edit_icon.setAttribute('data-glyph', "pencil"); + edit_icon.id = item[1]; + edit_icon.onclick = function () { + socket.emit("popup_edit", this.id); + }; + } + list_item.append(edit_icon); + + //create the delete icon + var delete_icon = document.createElement("span"); + delete_icon.classList.add("delete_icon"); + if (popup_deleteable) { + delete_icon.classList.add("oi"); + delete_icon.setAttribute('data-glyph', "x"); + delete_icon.id = item[1]; + delete_icon.setAttribute("folder", item[0]); + delete_icon.onclick = function () { + if (this.getAttribute("folder") == "true") { + if (window.confirm("Do you really want to delete this folder and ALL files under it?")) { + socket.emit("popup_delete", this.id); + } + } else { + if (window.confirm("Do you really want to delete this file?")) { + socket.emit("popup_delete", this.id); + } + } + }; + } + list_item.append(delete_icon); + + //create the actual item + var popup_item = document.createElement("span"); + popup_item.classList.add("file"); + popup_item.id = item[1]; + popup_item.setAttribute("folder", item[0]); + popup_item.setAttribute("valid", item[3]); + popup_item.textContent = item[2]; + popup_item.onclick = function () { + var accept = document.getElementById("popup_accept"); + if (this.getAttribute("valid") == "true") { + accept.classList.remove("disabled"); + accept.setAttribute("selected_value", this.id); + } else { + console.log("not valid"); + accept.setAttribute("selected_value", ""); + accept.classList.add("disabled"); + if (this.getAttribute("folder") == "true") { + console.log("folder"); + socket.emit("popup_change_folder", this.id); + } + } + }; + list_item.append(popup_item); + + + popup_list.append(list_item); + + + } +} + +function popup_breadcrumbs(data) { + var breadcrumbs = document.getElementById('popup_breadcrumbs') + while (breadcrumbs.firstChild) { + breadcrumbs.removeChild(breadcrumbs.firstChild); + } + + for (item of data) { + var button = document.createElement("button"); + button.id = item[0]; + button.textContent = item[1]; + button.classList.add("breadcrumbitem"); + button.onclick = function () { + socket.emit("popup_change_folder", this.id); + }; + breadcrumbs.append(button); + var span = document.createElement("span"); + span.textContent = "\\"; + breadcrumbs.append(span); + } +} + +function popup_edit_file(data) { + var popup_list = document.getElementById('popup_list'); + //first, let's clear out our existing data + while (popup_list.firstChild) { + popup_list.removeChild(popup_list.firstChild); + } + var accept = document.getElementById("popup_accept"); + accept.setAttribute("selected_value", ""); + accept.onclick = function () { + var textarea = document.getElementById("filecontents"); + socket.emit("popup_change_file", {"file": textarea.getAttribute("filename"), "data": textarea.value}); + document.getElementById("popup").classList.add("hidden"); + }; + + var textarea = document.createElement("textarea"); + textarea.classList.add("fullwidth"); + textarea.rows = 25; + textarea.id = "filecontents" + textarea.setAttribute("filename", data.file); + textarea.value = data.text; + textarea.onblur = function () { + var accept = document.getElementById("popup_accept"); + accept.classList.remove("disabled"); + }; + popup_list.append(textarea); + +} //--------------------------------------------UI to Server Functions---------------------------------- +function show_model_menu(data) { + document.getElementById("loadmodelcontainer").classList.remove("hidden"); + + //clear old options + document.getElementById("modelkey").classList.add("hidden"); + document.getElementById("modelkey").value = ""; + document.getElementById("modelurl").classList.add("hidden"); + document.getElementById("use_gpu_div").classList.add("hidden"); + document.getElementById("modellayers").classList.add("hidden"); + var model_layer_bars = document.getElementById('model_layer_bars'); + while (model_layer_bars.firstChild) { + model_layer_bars.removeChild(model_layer_bars.firstChild); + } + + //clear out the breadcrumbs + var breadcrumbs = document.getElementById('loadmodellistbreadcrumbs') + while (breadcrumbs.firstChild) { + breadcrumbs.removeChild(breadcrumbs.firstChild); + } + //add breadcrumbs + for (item of data.breadcrumbs) { + var button = document.createElement("button"); + button.classList.add("breadcrumbitem"); + button.id = item[0]; + button.value = item[1]; + button.onclick = function () { + socket.emit('selectmodel', {'data': this.id, 'folder': this.value}); + }; + breadcrumbs.append(button); + var span = document.createElement("span"); + span.textContent = "\\"; + breadcrumbs.append(span); + } + + //clear out the items + var model_list = document.getElementById('loadmodellistcontent') + while (model_list.firstChild) { + model_list.removeChild(model_list.firstChild); + } + //add items + for (item of data.data) { + var list_item = document.createElement("span"); + list_item.classList.add("item"); + + //create the folder icon + var folder_icon = document.createElement("span"); + folder_icon.classList.add("folder_icon"); + if (item[3]) { + folder_icon.classList.add("oi"); + folder_icon.setAttribute('data-glyph', "folder"); + } + list_item.append(folder_icon); + + //create the delete icon + //var delete_icon = document.createElement("span"); + //delete_icon.classList.add("delete_icon"); + //if (popup_deleteable) { + // delete_icon.classList.add("oi"); + // delete_icon.setAttribute('data-glyph', "x"); + // delete_icon.id = item[1]; + // delete_icon.setAttribute("folder", item[0]); + // delete_icon.onclick = function () { + // if (this.getAttribute("folder") == "true") { + // if (window.confirm("Do you really want to delete this folder and ALL files under it?")) { + // socket.emit("popup_delete", this.id); + // } + // } else { + // if (window.confirm("Do you really want to delete this file?")) { + // socket.emit("popup_delete", this.id); + // } + // } + // }; + //} + //list_item.append(delete_icon); + + //create the actual item + var popup_item = document.createElement("span"); + popup_item.classList.add("model"); + popup_item.id = item[1]; + popup_item.setAttribute("Menu", data.menu) + //name text + var text = document.createElement("span"); + text.style="grid-area: item;"; + text.textContent = item[0]; + popup_item.append(text); + //model size text + var text = document.createElement("span"); + text.textContent = item[2]; + text.style="grid-area: gpu_size;padding: 2px;"; + popup_item.append(text); + + popup_item.onclick = function () { + var accept = document.getElementById("popup_accept"); + accept.classList.add("disabled"); + socket.emit("select_model", {"model": this.id, "menu": this.getAttribute("Menu")}); + var model_list = document.getElementById('loadmodellistcontent').getElementsByClassName("selected"); + for (model of model_list) { + model.classList.remove("selected"); + } + this.classList.add("selected"); + }; + list_item.append(popup_item); + + + model_list.append(list_item); + } + +} +function selected_model_info(data) { + var accept = document.getElementById("btn_loadmodelaccept"); + //hide or unhide key + if (data.key) { + document.getElementById("modelkey").classList.remove("hidden"); + document.getElementById("modelkey").value = data.key_value; + } else { + document.getElementById("modelkey").classList.add("hidden"); + document.getElementById("modelkey").value = ""; + } + //hide or unhide URL + if (data.url) { + document.getElementById("modelurl").classList.remove("hidden"); + } else { + document.getElementById("modelurl").classList.add("hidden"); + } + //hide or unhide the use gpu checkbox + if (data.gpu) { + document.getElementById("use_gpu_div").classList.remove("hidden"); + } else { + document.getElementById("use_gpu_div").classList.add("hidden"); + } + //setup breakmodel + if (data.breakmodel) { + document.getElementById("modellayers").classList.remove("hidden"); + //setup model layer count + console.log(data.break_values.reduce((a, b) => a + b, 0)); + document.getElementById("gpu_layers_current").textContent = data.break_values.reduce((a, b) => a + b, 0); + document.getElementById("gpu_layers_max").textContent = data.layer_count; + document.getElementById("gpu_count").value = data.gpu_count; + + //create the gpu load bars + var model_layer_bars = document.getElementById('model_layer_bars'); + while (model_layer_bars.firstChild) { + model_layer_bars.removeChild(model_layer_bars.firstChild); + } + + //Add the bars + for (let i = 0; i < data.gpu_names.length; i++) { + var div = document.createElement("div"); + div.classList.add("model_setting_container"); + //build GPU text + var span = document.createElement("span"); + span.classList.add("model_setting_label"); + span.textContent = "GPU " + i + " " + data.gpu_names[i] + ": " + //build layer count box + var input = document.createElement("input"); + input.classList.add("model_setting_value"); + input.classList.add("setting_value"); + input.inputmode = "numeric"; + input.id = "gpu_layers_box_"+i; + input.value = data.break_values[i]; + input.onblur = function () { + document.getElementById(this.id.replace("_box", "")).value = this.value; + update_gpu_layers(); + } + span.append(input); + div.append(span); + //build layer count slider + var input = document.createElement("input"); + input.classList.add("model_setting_item"); + input.type = "range"; + input.min = 0; + input.max = data.layer_count; + input.step = 1; + input.value = data.break_values[i]; + input.id = "gpu_layers_" + i; + input.onchange = function () { + document.getElementById(this.id.replace("gpu_layers", "gpu_layers_box")).value = this.value; + update_gpu_layers(); + } + div.append(input); + //build slider bar #s + //min + var span = document.createElement("span"); + span.classList.add("model_setting_minlabel"); + var span2 = document.createElement("span"); + span2.style="top: -4px; position: relative;"; + span2.textContent = 0; + span.append(span2); + div.append(span); + //max + var span = document.createElement("span"); + span.classList.add("model_setting_maxlabel"); + var span2 = document.createElement("span"); + span2.style="top: -4px; position: relative;"; + span2.textContent = data.layer_count; + span.append(span2); + div.append(span); + + model_layer_bars.append(div); + } + + //add the disk layers + var div = document.createElement("div"); + div.classList.add("model_setting_container"); + //build GPU text + var span = document.createElement("span"); + span.classList.add("model_setting_label"); + span.textContent = "Disk cache: " + //build layer count box + var input = document.createElement("input"); + input.classList.add("model_setting_value"); + input.classList.add("setting_value"); + input.inputmode = "numeric"; + input.id = "disk_layers_box"; + input.value = data.disk_break_value; + input.onblur = function () { + document.getElementById(this.id.replace("_box", "")).value = this.value; + update_gpu_layers(); + } + span.append(input); + div.append(span); + //build layer count slider + var input = document.createElement("input"); + input.classList.add("model_setting_item"); + input.type = "range"; + input.min = 0; + input.max = data.layer_count; + input.step = 1; + input.value = data.disk_break_value; + input.id = "disk_layers"; + input.onchange = function () { + document.getElementById(this.id+"_box").value = this.value; + update_gpu_layers(); + } + div.append(input); + //build slider bar #s + //min + var span = document.createElement("span"); + span.classList.add("model_setting_minlabel"); + var span2 = document.createElement("span"); + span2.style="top: -4px; position: relative;"; + span2.textContent = 0; + span.append(span2); + div.append(span); + //max + var span = document.createElement("span"); + span.classList.add("model_setting_maxlabel"); + var span2 = document.createElement("span"); + span2.style="top: -4px; position: relative;"; + span2.textContent = data.layer_count; + span.append(span2); + div.append(span); + + model_layer_bars.append(div); + + update_gpu_layers(); + } else { + document.getElementById("modellayers").classList.add("hidden"); + accept.classList.remove("disabled"); + } + + +} + +function update_gpu_layers() { + var gpu_layers + gpu_layers = 0; + for (let i=0; i < document.getElementById("gpu_count").value; i++) { + gpu_layers += parseInt(document.getElementById("gpu_layers_"+i).value); + } + if (document.getElementById("disk_layers")) { + gpu_layers += parseInt(document.getElementById("disk_layers").value); + } + if (gpu_layers > parseInt(document.getElementById("gpu_layers_max").textContent)) { + document.getElementById("gpu_layers_current").textContent = gpu_layers; + document.getElementById("gpu_layers_current").classList.add("text_red"); + var accept = document.getElementById("btn_loadmodelaccept"); + accept.classList.add("disabled"); + } else { + var accept = document.getElementById("btn_loadmodelaccept"); + accept.classList.remove("disabled"); + document.getElementById("gpu_layers_current").textContent = gpu_layers; + document.getElementById("gpu_layers_current").classList.remove("text_red"); + } +} + +function load_model() { + message = {'cmd': 'load_model', 'use_gpu': $('#use_gpu')[0].checked, + 'key': $('#modelkey')[0].value, 'gpu_layers': gpu_layers.slice(0, -1), + 'disk_layers': disk_layers, 'url': $('#modelurl')[0].value, + 'online_model': $('#oaimodel')[0].value}; +} //--------------------------------------------General UI Functions------------------------------------ String.prototype.toHHMMSS = function () { var sec_num = parseInt(this, 10); // don't forget the second param diff --git a/templates/index_new.html b/templates/index_new.html index 5ae82c30..44e36106 100644 --- a/templates/index_new.html +++ b/templates/index_new.html @@ -61,5 +61,53 @@
{% include 'story flyout.html' %}
+ + + + + + \ No newline at end of file diff --git a/templates/settings flyout.html b/templates/settings flyout.html index a12744bd..b0159d44 100644 --- a/templates/settings flyout.html +++ b/templates/settings flyout.html @@ -33,7 +33,7 @@
Running Model: ReadOnly
-
+
{% with menu='Model' %} {% include 'settings item.html' %}