From 98105c729b18c41c2f9b7c66bb1bc542453010bc Mon Sep 17 00:00:00 2001 From: somebody Date: Thu, 15 Sep 2022 19:04:02 -0500 Subject: [PATCH 1/5] Work on import overhaul --- aiserver.py | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 1 deletion(-) diff --git a/aiserver.py b/aiserver.py index 4a8c98fc..37e505af 100644 --- a/aiserver.py +++ b/aiserver.py @@ -6,6 +6,7 @@ #==================================================================# # External packages +from dataclasses import dataclass import eventlet eventlet.monkey_patch(all=True, thread=False, os=False) import os @@ -239,6 +240,182 @@ class Send_to_socketio(object): def flush(self): pass + +@dataclass +class ImportBuffer: + # Singleton!!! + prompt: Optional[str] = None + memory: Optional[str] = None + authors_note: Optional[str] = None + world_infos: Optional[dict] = None + + @dataclass + class PromptPlaceholder: + id: str + order: Optional[int] = None + default: Optional[str] = None + title: Optional[str] = None + description: Optional[str] = None + value: Optional[str] = None + + def to_json(self) -> dict: + return {key: getattr(self, key) for key in [ + "id", + "order", + "default", + "title", + "description" + ]} + + def request_client_configuration(self, placeholders: list[PromptPlaceholder]) -> None: + emit("request_prompt_config", [x.to_json() for x in placeholders], broadcast=False, room="UI_2") + + def extract_placeholders(self, text: str) -> list[PromptPlaceholder]: + placeholders = [] + + for match in re.finditer(r"\${(.*?)}", text): + ph_text = match.group(1) + + try: + ph_order, ph_text = ph_text.split("#") + except ValueError: + ph_order = None + + if "[" not in ph_text: + ph_id = ph_text + + # Apparently, none of these characters are supported: + # "${}[]#:@^|", however I have found some prompts using these, + # so they will be allowed. + for char in "${}[]": + if char in ph_text: + print("[eph] Weird char") + print(f"{char=}") + print(f"{ph_id=}") + return + + placeholders.append(self.PromptPlaceholder( + id=ph_id, + order=int(ph_order) if ph_order else None, + )) + continue + + ph_id, _ = ph_text.split("[") + ph_text = ph_text.replace(ph_id, "", 1) + + # Match won't match it for some reason (???), so we use finditer and next() + try: + default_match = next(re.finditer(r"\[(.*?)\]", ph_text)) + except StopIteration: + print("[eph] Weird brackets") + return placeholders + + ph_default = default_match.group(1) + ph_text = ph_text.replace(default_match.group(0), "") + + try: + ph_title, ph_desc = ph_text.split(":") + except ValueError: + ph_title = ph_text or None + ph_desc=None + + placeholders.append(self.PromptPlaceholder( + id=ph_id, + order=int(ph_order) if ph_order else None, + default=ph_default, + title=ph_title, + description=ph_desc + )) + return placeholders + + def _replace_placeholders(self, text: str, ph_ids: dict): + for ph_id, value in ph_ids.items(): + pattern = "\${(?:\d#)?{}.*}".format(ph_id) + for ph_text in re.findall(pattern, text): + text = text.replace(ph_text, value) + return text + + def replace_placeholders(self, ph_ids: dict): + self.prompt = self._replace_placeholders(self.prompt, ph_ids) + self.memory = self._replace_placeholders(self.memory, ph_ids) + self.authors_note = self._replace_placeholders(self.authors_note, ph_ids) + + for i in range(len(self.world_infos)): + for key in ["content", "comment"]: + self.world_infos[i][key] = self._replace_placeholders(self.world_infos[i][key]) + + def from_club(self, club_id): + # Maybe it is a better to parse the NAI Scenario (if available), it has more data + r = requests.get(f"https://aetherroom.club/api/{club_id}") + + if not r.ok: + # TODO: Show error message on client + print(f"[import] Got {r.status_code} on request to club :^(") + return + + j = r.json() + + self.prompt = j["promptContent"] + self.memory = j["memory"] + self.authors_note = j["authorsNote"] + + self.world_infos = [] + + for wi in j["worldInfos"]: + self.world_infos.append({ + "key_list": wi["keysList"], + "keysecondary": [], + "content": wi["entry"], + "comment": "", + "folder": wi.get("folder", None), + "num": 0, + "init": True, + "selective": wi.get("selective", False), + "constant": wi.get("constant", False), + "uid": None, + }) + + placeholders = self.extract_placeholders(self.prompt) + if not placeholders: + self.commit() + else: + self.request_client_configuration(placeholders) + + def commit(self): + # Push buffer story to actual story + exitModes() + + koboldai_vars.create_story("") + koboldai_vars.gamestarted = True + koboldai_vars.prompt = self.prompt + koboldai_vars.memory = self.memory or "" + koboldai_vars.authornote = self.authors_note or "" + + # ???: Was this supposed to increment? + num = 0 + for wi in self.world_infos: + # koboldai_vars.worldinfo += self.world_infos + + koboldai_vars.worldinfo_v2.add_item( + wi["key_list"][0], + wi["key_list"], + wi.get("keysecondary", []), + wi.get("folder", "root"), + wi.get("constant", False), + wi["content"], + wi.get("comment", "") + ) + + # Reset current save + koboldai_vars.savedir = getcwd()+"\\stories" + + # Refresh game screen + koboldai_vars.laststory = None + setgamesaved(False) + sendwi() + refresh_story() + +import_buffer = ImportBuffer() # Set logging level to reduce chatter from Flask import logging @@ -7131,6 +7308,11 @@ def get_files_sorted(path, sort, desc=False): return [key[0] for key in sorted(data.items(), key=lambda kv: (kv[1], kv[0]), reverse=desc)] +@socketio.on("configure_prompt") +def UI_2_configure_prompt(data): + import_buffer.replace_placeholders(data) + import_buffer.commit() + #==================================================================# # Event triggered when browser SocketIO detects a variable change #==================================================================# @@ -7789,7 +7971,8 @@ def UI_2_unload_userscripts(data): def UI_2_load_aidg_club(data): if koboldai_vars.debug: print("Load aidg.club: {}".format(data)) - importAidgRequest(data) + import_buffer.from_club(data) + # importAidgRequest(data) #==================================================================# From 111fa70a203bc8de621f78b36ede0273f35788a9 Mon Sep 17 00:00:00 2001 From: somebody Date: Thu, 15 Sep 2022 19:28:08 -0500 Subject: [PATCH 2/5] Start work on prompt config ui --- static/koboldai.css | 63 ++++++++++++++++++++++++++++++++++++++++++- templates/popups.html | 33 ++++++++++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/static/koboldai.css b/static/koboldai.css index 1e6ac338..0c39595b 100644 --- a/static/koboldai.css +++ b/static/koboldai.css @@ -1854,7 +1854,8 @@ body { /* Finder */ #finder-container, -#debug-file-container { +#debug-file-container, +#prompt-config-container { display: flex; justify-content: center; align-items: center; @@ -2060,6 +2061,66 @@ body { background-color: rgb(158, 2, 2); } +/* Prompt Config */ +#prompt-config { + display: flex; + flex-direction: column; + position: relative; + background-color: var(--popup_background_color); + width: 25%; + height: 75%; +} + +#prompt-config-header { + /* HACK: Need to add (or use) a theme color for this! */ + background-color: #212a33; + padding: 7px; +} + +#prompt-config-header > h3 { + margin-top: 5px; + margin-bottom: 5px; +} + +#prompt-config-placeholders { + display: flex; + flex-direction: column; + row-gap: 16px; + overflow-y: scroll; + padding: 7px; + padding-left: 14px +} + +.prompt-config-title { + display: block; + font-size: 20px; + font-weight: bold; +} + +.prompt-config-value { + padding: 7px; +} + +#prompt-config-done { + display: flex; + justify-content: center; + align-items: center; + + width: 100px; + height: 32px; + + position: absolute; + + right: 10px; + bottom: 10px; + + + cursor: pointer; + color: var(--button_text); + background-color: var(--button_background); + border-radius: var(--radius_settings_button); +} + /*---------------------------------- Global ------------------------------------------------*/ .hidden { display: none; diff --git a/templates/popups.html b/templates/popups.html index 4a0a353a..e8fefbfd 100644 --- a/templates/popups.html +++ b/templates/popups.html @@ -192,4 +192,35 @@ - \ No newline at end of file + + + +
+
+
+

Prompt Configuration

+ This prompt has placeholders you need to fill in before starting. +
+ + +
+
+ Name + What is your name? + +
+
+ +
Done
+
+
+ + \ No newline at end of file From c6d3c834839f863ece20a9a3fa00d097c2711b62 Mon Sep 17 00:00:00 2001 From: somebody Date: Thu, 15 Sep 2022 21:28:25 -0500 Subject: [PATCH 3/5] JS work on new club loading --- aiserver.py | 16 ++++++++++++++- static/koboldai.js | 47 +++++++++++++++++++++++++++++++++++++++++++ templates/popups.html | 25 ++++------------------- 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/aiserver.py b/aiserver.py index 37e505af..58fdf2e7 100644 --- a/aiserver.py +++ b/aiserver.py @@ -247,6 +247,7 @@ class ImportBuffer: prompt: Optional[str] = None memory: Optional[str] = None authors_note: Optional[str] = None + notes: Optional[str] = None world_infos: Optional[dict] = None @dataclass @@ -284,6 +285,10 @@ class ImportBuffer: if "[" not in ph_text: ph_id = ph_text + # Already have it! + if any([x.id == ph_id for x in placeholders]): + continue + # Apparently, none of these characters are supported: # "${}[]#:@^|", however I have found some prompts using these, # so they will be allowed. @@ -303,6 +308,10 @@ class ImportBuffer: ph_id, _ = ph_text.split("[") ph_text = ph_text.replace(ph_id, "", 1) + # Already have it! + if any([x.id == ph_id for x in placeholders]): + continue + # Match won't match it for some reason (???), so we use finditer and next() try: default_match = next(re.finditer(r"\[(.*?)\]", ph_text)) @@ -330,12 +339,15 @@ class ImportBuffer: def _replace_placeholders(self, text: str, ph_ids: dict): for ph_id, value in ph_ids.items(): - pattern = "\${(?:\d#)?{}.*}".format(ph_id) + print(f"iterating upon {ph_id=}") + pattern = "\${(?:\d#)?%s.*?}" % ph_id for ph_text in re.findall(pattern, text): + print(f"instance of {ph_id} in text, replaceing with {value}") text = text.replace(ph_text, value) return text def replace_placeholders(self, ph_ids: dict): + print(f"Replacing with {ph_ids}") self.prompt = self._replace_placeholders(self.prompt, ph_ids) self.memory = self._replace_placeholders(self.memory, ph_ids) self.authors_note = self._replace_placeholders(self.authors_note, ph_ids) @@ -358,6 +370,7 @@ class ImportBuffer: self.prompt = j["promptContent"] self.memory = j["memory"] self.authors_note = j["authorsNote"] + self.notes = j["description"] self.world_infos = [] @@ -390,6 +403,7 @@ class ImportBuffer: koboldai_vars.prompt = self.prompt koboldai_vars.memory = self.memory or "" koboldai_vars.authornote = self.authors_note or "" + koboldai_vars.notes = self.notes # ???: Was this supposed to increment? num = 0 diff --git a/static/koboldai.js b/static/koboldai.js index 15f838a3..c60a9a50 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -28,6 +28,7 @@ socket.on("error", function(data){show_error_message(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.onAny(function(event_name, data) {console.log({"event": event_name, "class": data.classname, "data": data});}); var presets = {}; @@ -3432,6 +3433,52 @@ async function downloadDebugFile(redact=true) { downloadString(JSON.stringify(debug_info, null, 4), "kobold_debug.json"); } +function configurePrompt(placeholderData) { + console.log(placeholderData); + const container = document.querySelector("#prompt-config-container"); + container.classList.remove("hidden"); + + const placeholders = document.querySelector("#prompt-config-placeholders"); + + for (const phData of placeholderData) { + let placeholder = $e("div", placeholders, {classes: ["prompt-config-ph"]}); + + + // ${character.name} is an AI Dungeon thing, although I believe NAI + // supports it as well. Many prompts use it. I think this is the only + // hardcoded thing like this. + let titleText = phData.title || phData.id; + if (titleText === "character.name") titleText = "Character Name"; + + let title = $e("span", placeholder, {classes: ["prompt-config-title"], innerText: titleText}); + + if (phData.description) $e("span", placeholder, { + classes: ["prompt-config-desc", "help_text"], + innerText: phData.description + }); + + let input = $e("input", placeholder, { + classes: ["prompt-config-value"], + value: phData.default || "", + placeholder: phData.default || "", + "placeholder-id": phData.id + }); + } +} + +function sendPromptConfiguration() { + let data = {}; + for (const configInput of document.querySelectorAll(".prompt-config-value")) { + data[configInput.getAttribute("placeholder-id")] = configInput.value; + } + + socket.emit("configure_prompt", data); + + document.querySelector("#popup").classList.add("hidden"); + document.querySelector("#prompt-config-container").classList.add("hidden"); + $(".prompt-config-ph").remove(); +} + function loadNAILorebook(data, filename) { let lorebookVersion = data.lorebookVersion; let wi_data = {folders: {[filename]: []}, entries: {}}; diff --git a/templates/popups.html b/templates/popups.html index e8fefbfd..e8d5c3e1 100644 --- a/templates/popups.html +++ b/templates/popups.html @@ -195,7 +195,7 @@ -
+ - - \ No newline at end of file +
\ No newline at end of file From b7dc60bff8c816300736c22b7a7e0a7c396a1f62 Mon Sep 17 00:00:00 2001 From: somebody Date: Thu, 15 Sep 2022 21:28:44 -0500 Subject: [PATCH 4/5] Fix typo in create_story --- koboldai_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koboldai_settings.py b/koboldai_settings.py index 30a1b74b..f64f2429 100644 --- a/koboldai_settings.py +++ b/koboldai_settings.py @@ -90,7 +90,7 @@ class koboldai_vars(object): else: self._story_settings[story_name] = story_settings(self.socketio) if json_data is not None: - self.load_story(sotry_name, json_data) + self.load_story(story_name, json_data) self._story_settings['default'].send_to_ui() def story_list(self): From 73b1e551fa210e05375364fbee49d3bb3fb15f8d Mon Sep 17 00:00:00 2001 From: somebody Date: Thu, 15 Sep 2022 22:13:54 -0500 Subject: [PATCH 5/5] Polish and bugfixes on import variables --- aiserver.py | 5 +---- static/koboldai.js | 1 - templates/popups.html | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/aiserver.py b/aiserver.py index 58fdf2e7..732f67a2 100644 --- a/aiserver.py +++ b/aiserver.py @@ -339,15 +339,12 @@ class ImportBuffer: def _replace_placeholders(self, text: str, ph_ids: dict): for ph_id, value in ph_ids.items(): - print(f"iterating upon {ph_id=}") - pattern = "\${(?:\d#)?%s.*?}" % ph_id + pattern = "\${(?:\d#)?%s.*?}" % re.escape(ph_id) for ph_text in re.findall(pattern, text): - print(f"instance of {ph_id} in text, replaceing with {value}") text = text.replace(ph_text, value) return text def replace_placeholders(self, ph_ids: dict): - print(f"Replacing with {ph_ids}") self.prompt = self._replace_placeholders(self.prompt, ph_ids) self.memory = self._replace_placeholders(self.memory, ph_ids) self.authors_note = self._replace_placeholders(self.authors_note, ph_ids) diff --git a/static/koboldai.js b/static/koboldai.js index c60a9a50..079ee749 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -3474,7 +3474,6 @@ function sendPromptConfiguration() { socket.emit("configure_prompt", data); - document.querySelector("#popup").classList.add("hidden"); document.querySelector("#prompt-config-container").classList.add("hidden"); $(".prompt-config-ph").remove(); } diff --git a/templates/popups.html b/templates/popups.html index e8d5c3e1..2ea3b71b 100644 --- a/templates/popups.html +++ b/templates/popups.html @@ -113,7 +113,7 @@