diff --git a/aiserver.py b/aiserver.py index b4dbbc31..03ede98e 100644 --- a/aiserver.py +++ b/aiserver.py @@ -495,7 +495,6 @@ from flask_socketio import SocketIO, emit, join_room, leave_room from flask_socketio import emit as _emit from flask_session import Session from flask_compress import Compress -import secrets from werkzeug.exceptions import HTTPException, NotFound, InternalServerError import secrets app = Flask(__name__, root_path=os.getcwd()) @@ -8237,13 +8236,12 @@ def story_sort(base_path, desc=False): with open(filename, "r") as f: try: js = json.load(f) + if 'story_name' in js and js['story_name'] in koboldai_vars.story_loads: + files[file.name] = datetime.datetime.strptime(koboldai_vars.story_loads[js['story_name']], "%m/%d/%Y, %H:%M:%S") + else: + files[file.name] = datetime.datetime.fromtimestamp(file.stat().st_mtime) except: pass - - if 'story_name' in js and js['story_name'] in koboldai_vars.story_loads: - files[file.name] = datetime.datetime.strptime(koboldai_vars.story_loads[js['story_name']], "%m/%d/%Y, %H:%M:%S") - else: - files[file.name] = datetime.datetime.fromtimestamp(file.stat().st_mtime) return [key[0] for key in sorted(files.items(), key=lambda kv: (kv[1], kv[0]), reverse=desc)] @@ -9044,6 +9042,24 @@ def UI_2_refresh_auto_memory(data): koboldai_vars.auto_memory += "\n\n Final Result:\n" + output + +#==================================================================# +# Get next 100 actions for infinate scroll +#==================================================================# +@socketio.on("get_next_100_actions") +@logger.catch +def UI_2_get_next_100_actions(data): + logger.debug("Sending an additional 100 actions, starting at action {}".format(data-1)) + sent = 0 + data_to_send = [] + for i in reversed(list(koboldai_vars.actions.actions)): + if i < data: + if sent >= 50: + break + data_to_send.append({"id": i, "action": koboldai_vars.actions.actions[i]}) + sent += 1 + emit("var_changed", {"classname": "story", "name": "actions", "old_value": None, "value":data_to_send}) + #==================================================================# # Test #==================================================================# diff --git a/koboldai_settings.py b/koboldai_settings.py index 99044bec..9ebd47ca 100644 --- a/koboldai_settings.py +++ b/koboldai_settings.py @@ -44,19 +44,24 @@ def process_variable_changes(socketio, classname, name, value, old_value, debug_ #logger.debug("sending data to room (multi_story={},classname={}): {}".format(multi_story, classname, room)) #Special Case for KoboldStoryRegister if isinstance(value, KoboldStoryRegister): + #To speed up loading time we will only transmit the last 100 actions to the UI, then rely on scrolling triggers to load more as needed if not has_request_context(): if queue is not None: #logger.debug("Had to use queue") queue.put(["var_changed", {"classname": "actions", "name": "Action Count", "old_value": None, "value":value.action_count}, {"broadcast":True, "room":room}]) - for i in value.actions: - queue.put(["var_changed", {"classname": "story", "name": "actions", "old_value": None, "value":{"id": i, "action": value.actions[i]}}, {"broadcast":True, "room":room}]) + data_to_send = [] + for i in list(value.actions)[-100:]: + data_to_send.append({"id": i, "action": value.actions[i]}) + queue.put(["var_changed", {"classname": "story", "name": "actions", "old_value": None, "value":data_to_send}, {"broadcast":True, "room":room}]) else: socketio.emit("var_changed", {"classname": "actions", "name": "Action Count", "old_value": None, "value":value.action_count}, broadcast=True, room=room) - for i in value.actions: - socketio.emit("var_changed", {"classname": "story", "name": "actions", "old_value": None, "value":{"id": i, "action": value.actions[i]}}, broadcast=True, room=room) + data_to_send = [] + for i in list(value.actions)[-100:]: + data_to_send.append({"id": i, "action": value.actions[i]}) + socketio.emit("var_changed", {"classname": "story", "name": "actions", "old_value": None, "value": data_to_send}, broadcast=True, room=room) elif isinstance(value, KoboldWorldInfo): value.send_to_ui() else: @@ -757,6 +762,22 @@ class story_settings(settings): new_world_info.socketio = self.socketio self.worldinfo_v2 = new_world_info + def assign_world_info_to_actions(self, action_id=None, wuid=None): + if action_id is None or action_id not in self.actions.actions: + actions_to_check = self.actions.actions + else: + actions_to_check = {action_id: self.actions.actions[action_id]} + if wuid is None or wuid not in self.worldinfo_v2.world_info: + wi_to_check = self.worldinfo_v2.world_info + else: + wi_to_check = {wuid: self.worldinfo_v2.world_info[wuid]} + + for action_id, action in actions_to_check.items(): + for uid, wi in wi_to_check.items(): + for key in sorted(wi['key'], key=len, reverse=True): + if key in action['Selected Text']: + self.actions.add_wi_to_action(action_id, key, wi['content']) + break def __setattr__(self, name, value): new_variable = name not in self.__dict__ @@ -1020,7 +1041,7 @@ class KoboldStoryRegister(object): self.koboldai_vars = koboldai_vars #### DO NOT DIRECTLY EDIT THE ACTIONS DICT. IT WILL NOT TRANSMIT TO CLIENT. USE FUCTIONS BELOW TO DO SO ### #### doing actions[x] = game text is OK - self.actions = {} #keys = "Selected Text", "Options", "Selected Text Length", "In AI Input", "Probabilities". + self.actions = {} #keys = "Selected Text", "WI Search Text", "Wi_highlighted_text", "Options", "Selected Text Length", "In AI Input", "Probabilities". #Options being a list of dict with keys of "text", "Pinned", "Previous Selection", "Edited", "Probabilities" self.action_count = -1 self.tokenizer = tokenizer @@ -1031,6 +1052,14 @@ class KoboldStoryRegister(object): def reset(self, sequence=[]): self.__init__(self.socketio, self.story_settings, self.koboldai_vars, sequence=sequence, tokenizer=self.tokenizer) + def add_wi_to_action(action_id, key, content): + #First check to see if we have the wi_highlighted_text variable + if 'wi_highlighted_text' not in self.actions[action_id]: + self.actions[action_id]['wi_highlighted_text'] = [{"text": self.actions[action_id]['Selected Text'], "WI matches": [], "WI Text": ""}] + + + + def __str__(self): if len(self.actions) > 0: return "".join([x['Selected Text'] for ignore, x in sorted(self.actions.items())]) @@ -1120,7 +1149,12 @@ class KoboldStoryRegister(object): temp[int(item)] = json_data['actions'][item] if "WI Search Text" not in temp[int(item)]: temp[int(item)]["WI Search Text"] = re.sub("[^0-9a-z \'\"]", "", temp[int(item)]['Selected Text']) - process_variable_changes(self.socketio, "story", 'actions', {"id": item, 'action': temp[int(item)]}, None) + data_to_send = [] + if int(item) >= self.action_count-100: + data_to_send.append({"id": item, 'action': temp[int(item)]}) + + process_variable_changes(self.socketio, "story", 'actions', data_to_send, None) + self.actions = temp self.set_game_saved() self.story_settings.save_story() diff --git a/static/koboldai.css b/static/koboldai.css index d9d0aeb1..186f9aaa 100644 --- a/static/koboldai.css +++ b/static/koboldai.css @@ -2354,7 +2354,7 @@ textarea { outline: none; } -/*.pulse { +.pulse { box-shadow: 0 0 0 0 rgba(255, 255, 255, 1); animation: pulse-white 2s infinite; } @@ -2374,7 +2374,32 @@ textarea { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); } -}*/ +} + +@keyframes pulse-text { + 0% { + filter: blur(3px); + -webkit-filter: blur(3px); + } + + 33% { + filter: blur(2px); + -webkit-filter: blur(2px); + } + + 66% { + filter: blur(1px); + -webkit-filter: blur(1px); + } + 100% { + filter: blur(0px); + -webkit-filter: blur(0px); + } +} + +.single_pulse { + animation: pulse-text 2s 1; +} .drag-over { border-top: dashed 3px red; diff --git a/static/koboldai.js b/static/koboldai.js index 272709c2..27d91600 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -26,11 +26,11 @@ socket.on("delete_new_world_info_entry", function(data){document.getElementById( socket.on("delete_world_info_entry", function(data){document.getElementById("world_info_"+data).remove();}); socket.on("delete_world_info_folder", function(data){document.getElementById("world_info_folder_"+data).remove();}); socket.on("error", function(data){show_error_message(data);}); -socket.on('load_cookies', function(data){load_cookies(data)}); +socket.on('load_cookies', function(data){load_cookies(data);}); socket.on('load_tweaks', function(data){load_tweaks(data);}); socket.on("wi_results", updateWISearchListings); socket.on("request_prompt_config", configurePrompt); -socket.on("log_message", function(data){process_log_message(data)}); +socket.on("log_message", function(data){process_log_message(data);}); socket.on("debug_message", function(data){console.log(data);}); socket.on("scratchpad_response", recieveScratchpadResponse); //socket.onAny(function(event_name, data) {console.log({"event": event_name, "class": data.classname, "data": data});}); @@ -60,6 +60,7 @@ var finder_waiting_id = null; var control_held = false; var actions_data = {}; var setup_wi_toggles = []; +var scroll_trigger_element = undefined; const on_colab = $el("#on_colab").textContent == "true"; // name, desc, icon, func @@ -202,11 +203,11 @@ function fix_text(val) { } } -function create_options(data) { +function create_options(action) { //Set all options before the next chunk to hidden var option_container = document.getElementById("Select Options"); var current_chunk = parseInt(document.getElementById("action_count").textContent)+1; - if (current_chunk != data.value.id.toString()) { + if (current_chunk != action.id.toString()) { return; } if (document.getElementById("Select Options Chunk " + current_chunk)) { @@ -218,12 +219,12 @@ function create_options(data) { document.getElementById("Select Options Chunk " + (current_chunk-1)).remove(); } - if (document.getElementById("Select Options Chunk "+data.value.id)) { - var option_chunk = document.getElementById("Select Options Chunk "+data.value.id); + if (document.getElementById("Select Options Chunk "+action.id)) { + var option_chunk = document.getElementById("Select Options Chunk "+action.id); } else { var option_chunk = document.createElement("div"); - option_chunk.id = "Select Options Chunk "+data.value.id; - if (current_chunk != data.value.id) { + option_chunk.id = "Select Options Chunk "+action.id; + if (current_chunk != action.id) { option_chunk.classList.add("hidden"); } option_container.append(option_chunk); @@ -236,7 +237,7 @@ function create_options(data) { table.classList.add("sequences"); //Add Redo options i=0; - for (item of data.value.action.Options) { + for (item of action.action.Options) { if ((item['Previous Selection'])) { var row = document.createElement("div"); row.classList.add("sequence_row"); @@ -244,10 +245,10 @@ function create_options(data) { textcell.textContent = item.text; textcell.classList.add("sequence"); textcell.setAttribute("option_id", i); - textcell.setAttribute("option_chunk", data.value.id); + textcell.setAttribute("option_chunk", action.id); var iconcell = document.createElement("span"); iconcell.setAttribute("option_id", i); - iconcell.setAttribute("option_chunk", data.value.id); + iconcell.setAttribute("option_chunk", action.id); iconcell.classList.add("sequnce_icon"); var icon = document.createElement("span"); icon.id = "Pin_"+i; @@ -256,7 +257,7 @@ function create_options(data) { iconcell.append(icon); delete_icon = $e("span", iconcell, {"classes": ["material-icons-outlined", "cursor", 'delete_option_icon'], "title": "delete option", 'option_id': i, - 'option_chunk': data.value.id, 'textContent': 'delete'}); + 'option_chunk': action.id, 'textContent': 'delete'}); delete_icon.onclick = function () { socket.emit("delete_option", {"chunk": this.getAttribute("option_chunk"), "option": this.getAttribute("option_id")}); }; @@ -271,7 +272,7 @@ function create_options(data) { } //Add general options i=0; - for (item of data.value.action.Options) { + for (item of action.action.Options) { if (!(item.Edited) && !(item['Previous Selection'])) { var row = document.createElement("div"); row.classList.add("sequence_row"); @@ -279,10 +280,10 @@ function create_options(data) { textcell.textContent = item.text; textcell.classList.add("sequence"); textcell.setAttribute("option_id", i); - textcell.setAttribute("option_chunk", data.value.id); + textcell.setAttribute("option_chunk", action.id); var iconcell = document.createElement("span"); iconcell.setAttribute("option_id", i); - iconcell.setAttribute("option_chunk", data.value.id); + iconcell.setAttribute("option_chunk", action.id); iconcell.classList.add("sequnce_icon"); var icon = document.createElement("span"); icon.id = "Pin_"+i; @@ -311,47 +312,61 @@ function create_options(data) { //option_chunk.scrollIntoView(); } -function do_story_text_updates(data) { +function do_story_text_updates(action) { story_area = document.getElementById('Selected Text'); - current_chunk_number = data.value.id; - if (document.getElementById('Selected Text Chunk '+data.value.id)) { - var item = document.getElementById('Selected Text Chunk '+data.value.id); + current_chunk_number = action.id; + if (document.getElementById('Selected Text Chunk '+action.id)) { + var item = document.getElementById('Selected Text Chunk '+action.id); //clear out the item first while (item.firstChild) { item.removeChild(item.firstChild); } span = document.createElement("span"); - span.textContent = data.value.action['Selected Text']; + span.textContent = action.action['Selected Text']; item.append(span); - item.original_text = data.value.action['Selected Text']; - item.setAttribute("WI_Search_Text", data.value.action['WI Search Text']); + item.original_text = action.action['Selected Text']; + item.setAttribute("WI_Search_Text", action.action['WI Search Text']); item.setAttribute("world_info_uids", ""); item.classList.remove("pulse") + item.classList.remove("single_pulse"); + item.classList.add("single_pulse"); //item.scrollIntoView(); if (item.textContent != "") { - assign_world_info_to_action(data.value.id, null); + assign_world_info_to_action(action.id, null); } } else { var span = document.createElement("span"); - span.id = 'Selected Text Chunk '+data.value.id; + span.id = 'Selected Text Chunk '+action.id; span.classList.add("rawtext"); - span.setAttribute("chunk", data.value.id); - span.original_text = data.value.action['Selected Text']; + span.setAttribute("chunk", action.id); + span.original_text = action.action['Selected Text']; new_span = document.createElement("span"); - new_span.textContent = data.value.action['Selected Text']; - span.setAttribute("WI_Search_Text", data.value.action['WI Search Text']); + new_span.textContent = action.action['Selected Text']; + span.setAttribute("WI_Search_Text", action.action['WI Search Text']); span.append(new_span); + //need to find the closest element + next_id = action.id+1; + while (true) { + if (next_id in actions_data) { + story_area.insertBefore(span, document.getElementById('Selected Text Chunk '+next_id)); + break; + } else if (Math.max.apply(null,Object.keys(actions_data)) <= next_id) { + story_area.append(span); + break; + } + next_id += 1; + } + span.classList.add("single_pulse"); - story_area.append(span); - if (data.value.id.toString() == document.getElementById('action_count').textContent) { + if (action.id.toString() == document.getElementById('action_count').textContent) { console.log("Scrolling. Action Count: "+document.getElementById('action_count').textContent); document.getElementById("Selected Text").scrollTop = document.getElementById("Selected Text").scrollHeight; } //clearTimeout(game_text_scroll_timeout); //game_text_scroll_timeout = setTimeout(function() {document.getElementById("Selected Text").scrollTop = document.getElementById("Selected Text").scrollHeight;}, 500); if (span.textContent != "") { - assign_world_info_to_action(data.value.id, null); + assign_world_info_to_action(action.id, null); } //console.log("done"); } @@ -393,23 +408,24 @@ function do_prompt(data) { } -function do_story_text_length_updates(data) { - if (document.getElementById('Selected Text Chunk '+data.value.id)) { - document.getElementById('Selected Text Chunk '+data.value.id).setAttribute("token_length", data.value.action["Selected Text Length"]); +function do_story_text_length_updates(action) { + if (document.getElementById('Selected Text Chunk '+action.id)) { + document.getElementById('Selected Text Chunk '+action.id).setAttribute("token_length", action.action["Selected Text Length"]); } else { - console.log('Selected Text Chunk '+data.value.id); + console.log('Selected Text Chunk '+action.id); + console.log(action); } } -function do_probabilities(data) { +function do_probabilities(action) { //console.log(data); - if (document.getElementById('probabilities_'+data.value.id)) { - prob_area = document.getElementById('probabilities_'+data.value.id) + if (document.getElementById('probabilities_'+action.id)) { + prob_area = document.getElementById('probabilities_'+action.id) } else { probabilities = document.getElementById('probabilities'); prob_area = document.createElement('span'); - prob_area.id = 'probabilities_'+data.value.id; + prob_area.id = 'probabilities_'+action.id; probabilities.append(prob_area); } //Clear @@ -419,8 +435,8 @@ function do_probabilities(data) { //create table table = document.createElement("table"); table.border=1; - if ("Probabilities" in data.value.action) { - for (token of data.value.action.Probabilities) { + if ("Probabilities" in action.action) { + for (token of action.action.Probabilities) { actual_text = document.createElement("td"); actual_text.setAttribute("rowspan", token.length); actual_text.textContent = "Word Goes Here"; @@ -537,15 +553,40 @@ function var_changed(data) { } //Special Case for Actions if ((data.classname == "story") && (data.name == "actions")) { - actions_data[data.value.id] = data.value.action; - do_story_text_updates(data); - create_options(data); - do_story_text_length_updates(data); - do_probabilities(data); - if (data.value.action['In AI Input']) { - document.getElementById('Selected Text Chunk '+data.value.id).classList.add("within_max_length"); + if (Array.isArray(data.value)) { + actions = data.value; } else { - document.getElementById('Selected Text Chunk '+data.value.id).classList.remove("within_max_length"); + actions = [data.value]; + } + for (action of actions) { + if (action.length != 0) { + actions_data[action.id] = action.action; + do_story_text_updates(action); + create_options(action); + do_story_text_length_updates(action); + if ('Probabilities' in action.action) { + do_probabilities(action); + } + if (action.action['In AI Input']) { + document.getElementById('Selected Text Chunk '+action.id).classList.add("within_max_length"); + } else { + document.getElementById('Selected Text Chunk '+action.id).classList.remove("within_max_length"); + } + } + } + //check to see if our new action is before the scroll triggering action + if (actions.length > 0) { + if ((scroll_trigger_element == undefined) || (actions[actions.length-1].id < parseInt(scroll_trigger_element.getAttribute("chunk")))) { + if (scroll_trigger_element != undefined) { + scroll_trigger_element.scrollIntoView(); + } + scroll_trigger_element = document.getElementById("Selected Text Chunk "+actions[actions.length-1].id); + //if we hit the top, unhide the prompt and clear the scroll trigger + if (actions[actions.length-1].id == 0) { + document.getElementById("story_prompt").classList.remove("story_prompt"); + scroll_trigger_element = null; + } + } } //Special Case for Presets @@ -3191,7 +3232,8 @@ function assign_world_info_to_action(action_item, uid) { var worldinfo_to_check = world_info_data; } if (action_item != null) { - var actions = [actions_data[action_item]]; + var actions = {}; + actions[action_item] = actions_data[action_item] } else { var actions = actions_data; } @@ -3234,7 +3276,7 @@ function assign_world_info_to_action(action_item, uid) { function highlight_world_info_text_in_chunk(action_id, wi) { //First let's assign our world info id to the action so we know to count the tokens for the world info let uid = wi['uid']; - action = document.getElementById("Selected Text Chunk "+action_id); + let action = document.getElementById("Selected Text Chunk "+action_id); let words = action.textContent.split(" "); current_ids = action.getAttribute("world_info_uids")?action.getAttribute("world_info_uids").split(','):[]; if (!(current_ids.includes(uid))) { @@ -4741,3 +4783,14 @@ document.addEventListener("keydown", function(event) { break; } }); + +//function to load more actions if nessisary +document.getElementById("Selected Text").onscroll = function(){ + //TOP + if ((scroll_trigger_element != undefined) && (scroll_trigger_element != null)) { + if(scroll_trigger_element.getBoundingClientRect().top >= 0){ + console.log("Asking for more actions"); + socket.emit("get_next_100_actions", parseInt(scroll_trigger_element.getAttribute("chunk"))); + } + } +} \ No newline at end of file diff --git a/templates/index_new.html b/templates/index_new.html index ca639624..b9563989 100644 --- a/templates/index_new.html +++ b/templates/index_new.html @@ -46,7 +46,7 @@

Disconnected

- +