From 44385730f683c3b087d502c186a558a12f0ad9cf Mon Sep 17 00:00:00 2001 From: somebody Date: Thu, 24 Nov 2022 23:17:35 -0600 Subject: [PATCH 1/7] Allow logging to server log from show_error_notification --- aiserver.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aiserver.py b/aiserver.py index 7221a3da..d3f0c139 100644 --- a/aiserver.py +++ b/aiserver.py @@ -768,7 +768,10 @@ api_v1 = KoboldAPISpec( tags=tags, ) -def show_error_notification(title: str, text: str) -> None: +def show_error_notification(title: str, text: str, do_log: bool = False) -> None: + if do_log: + logger.error(f"{title}: {text}") + if has_request_context(): socketio.emit("show_error_notification", {"title": title, "text": text}, broadcast=True, room="UI_2") else: From 3f0511d7bdd69c995e72643698a2f67de4a88d0f Mon Sep 17 00:00:00 2001 From: somebody Date: Thu, 24 Nov 2022 23:18:24 -0600 Subject: [PATCH 2/7] Don't add commas to join prompts when one is empty --- aiserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiserver.py b/aiserver.py index d3f0c139..301df9cd 100644 --- a/aiserver.py +++ b/aiserver.py @@ -9372,7 +9372,7 @@ def text2img_api(prompt, #"override_settings": {}, #"sampler_index": "Euler" final_imgen_params = { - "prompt": "{}, {}".format(prompt, art_guide), + "prompt": ", ".join(filter(bool, [prompt, art_guide])), "n_iter": 1, "width": 512, "height": 512, From a48d31c746313b74a4b9739fb20b482ce8b93fc3 Mon Sep 17 00:00:00 2001 From: somebody Date: Thu, 24 Nov 2022 23:19:07 -0600 Subject: [PATCH 3/7] Changes on sd webui api stuff - Strip url of trailing slashes, this caused issues when your api url ended with a slash (such as the default! at least i think) - Notify the user if they didn't call sd webui with the --api argument, which is required to use the api - Don't try to write to non-existant art directory, just send b64 image like the diffusers function does it. In the future we probably want to save these, but it would be in standardized manner most likely tied to story files somehow --- aiserver.py | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/aiserver.py b/aiserver.py index 301df9cd..6fa2307e 100644 --- a/aiserver.py +++ b/aiserver.py @@ -9381,33 +9381,33 @@ def text2img_api(prompt, "negative_prompt": "{}".format(koboldai_vars.img_gen_negative_prompt), "sampler_index": "Euler a" } - apiaddress = '{}/sdapi/v1/txt2img'.format(koboldai_vars.img_gen_api_url) + apiaddress = '{}/sdapi/v1/txt2img'.format(koboldai_vars.img_gen_api_url.rstrip("/")) payload_json = json.dumps(final_imgen_params) logger.debug(final_imgen_params) - #print("payload_json contains " + payload_json) - submit_req = requests.post(url=f'{apiaddress}', data=payload_json).json() - if submit_req: - results = submit_req - for i in results['images']: - final_src_img = Image.open(BytesIO(base64.b64decode(i.split(",",1)[0]))) - buffer = BytesIO() - final_src_img.save(buffer, format="Webp", quality=95) - b64img = base64.b64encode(buffer.getvalue()).decode("utf8") - base64_bytes = b64img.encode('utf-8') - img_bytes = base64.b64decode(base64_bytes) - img = Image.open(BytesIO(img_bytes)) - dt_string = datetime.datetime.now().strftime("%H%M%S%d%m%Y") - final_filename = "stories/art/{}_{}".format(dt_string,filename) - pnginfo = PngImagePlugin.PngInfo() - prompttext = results.get('info').split("\",")[0].split("\"")[3] - pnginfo.add_text("parameters","prompttext") - img.save(final_filename, pnginfo=pnginfo) - logger.debug("Saved Image") - koboldai_vars.generating_image = False - return(b64img) - else: + submit_req = requests.post(url=apiaddress, data=payload_json) + + if submit_req.status_code == 404: + show_error_notification( + "SD Web API Failure", + f"The SD Web UI was not called with --api. Unable to connect.", + do_log=True + ) + return None + elif not submit_req.ok: + show_error_notification("SD Web API Failure", f"HTTP Code {submit_req.status_code} -- See console for details") + logger.error(f"SD Web API Failure: HTTP Code {submit_req.status_code}, Body:\n{submit_req.text}") koboldai_vars.generating_image = False - logger.error(submit_req.text) + return None + + results = submit_req.json() + + try: + base64_image = results["images"][0] + except (IndexError, KeyError): + show_error_notification("SD Web API Failure", "SD Web API returned no images", do_log=True) + return None + + return base64_image #@logger.catch def get_items_locations_from_text(text): From ec20b3193143d8c5c47b9b78fde9a4e33eea5560 Mon Sep 17 00:00:00 2001 From: somebody Date: Thu, 24 Nov 2022 23:34:48 -0600 Subject: [PATCH 4/7] Remove reset switch for sd web api Automatically recover from errors --- aiserver.py | 7 +++++-- gensettings.py | 17 ----------------- koboldai_settings.py | 3 ++- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/aiserver.py b/aiserver.py index 6fa2307e..b3e0710b 100644 --- a/aiserver.py +++ b/aiserver.py @@ -9384,7 +9384,11 @@ def text2img_api(prompt, apiaddress = '{}/sdapi/v1/txt2img'.format(koboldai_vars.img_gen_api_url.rstrip("/")) payload_json = json.dumps(final_imgen_params) logger.debug(final_imgen_params) - submit_req = requests.post(url=apiaddress, data=payload_json) + + try: + submit_req = requests.post(url=apiaddress, data=payload_json) + finally: + koboldai_vars.generating_image = False if submit_req.status_code == 404: show_error_notification( @@ -9396,7 +9400,6 @@ def text2img_api(prompt, elif not submit_req.ok: show_error_notification("SD Web API Failure", f"HTTP Code {submit_req.status_code} -- See console for details") logger.error(f"SD Web API Failure: HTTP Code {submit_req.status_code}, Body:\n{submit_req.text}") - koboldai_vars.generating_image = False return None results = submit_req.json() diff --git a/gensettings.py b/gensettings.py index 7ca496c7..6af24f21 100644 --- a/gensettings.py +++ b/gensettings.py @@ -670,23 +670,6 @@ gensettingstf = [ "ui_level": 2 }, { - "UI_V2_Only": True, - "uitype": "toggle", - "unit": "bool", - "label": "Reset Image Generating", - "id": "generating_image", - "min": 0, - "max": 1, - "step": 1, - "default": 0, - "tooltip": "Use to reset image gen flag in case of error.", - "menu_path": "Interface", - "sub_path": "Images", - "classname": "system", - "name": "generating_image", - "ui_level": 2 - }, - { "UI_V2_Only": True, "uitype": "toggle", "unit": "bool", diff --git a/koboldai_settings.py b/koboldai_settings.py index e057698e..a28fbcba 100644 --- a/koboldai_settings.py +++ b/koboldai_settings.py @@ -1060,7 +1060,8 @@ class system_settings(settings): no_save_variables = ['socketio', 'lua_state', 'lua_logname', 'lua_koboldbridge', 'lua_kobold', 'lua_koboldcore', 'sp', 'sp_length', '_horde_pid', 'horde_share', 'aibusy', 'serverstarted', 'inference_config', 'image_pipeline', 'summarizer', - 'summary_tokenizer', 'use_colab_tpu', 'noai', 'disable_set_aibusy', 'cloudflare_link', 'tts_model'] + 'summary_tokenizer', 'use_colab_tpu', 'noai', 'disable_set_aibusy', 'cloudflare_link', 'tts_model', + 'generating_image'] settings_name = "system" def __init__(self, socketio, koboldai_var): self.socketio = socketio From 9ca741b09a9abc92f5f3264d4ed4471407f8faf6 Mon Sep 17 00:00:00 2001 From: somebody Date: Thu, 24 Nov 2022 23:36:04 -0600 Subject: [PATCH 5/7] Add loading thing for image gen --- static/koboldai.css | 33 ++++++++++++++++++++++++++++++++- static/koboldai.js | 14 +++++++++++--- templates/settings flyout.html | 8 ++++++-- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/static/koboldai.css b/static/koboldai.css index be6fdf74..a534b688 100644 --- a/static/koboldai.css +++ b/static/koboldai.css @@ -2988,8 +2988,39 @@ input[type='range'] { pointer-events:none; } +#action\ image { + width: 100%; + aspect-ratio: 1/1; + position: relative; +} + +#image-loading { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + top: 0px; + left: 0px; + width: 100%; + height: 100% !important; + aspect-ratio: 1/1; + background-color: rgba(0, 0, 0, 0.6); + + /* Defer pointer events to the image in case a user wants to quickly + save / view an image after asking for a new image */ + pointer-events: none; +} + +.spinner { + animation: spin 1s linear infinite; + opacity: 0.7; +} + +@keyframes spin { 100% { transform: rotate(360deg) } } + + .action_image { - width: var(--flyout_menu_width); + width: 100%; } /*Tooltip based on attribute diff --git a/static/koboldai.js b/static/koboldai.js index c2805a15..4a8b42d8 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -790,9 +790,12 @@ function var_changed(data) { //Special Case for story picture } else if (data.classname == "story" && data.name == "picture") { image_area = document.getElementById("action image"); - while (image_area.firstChild) { - image_area.removeChild(image_area.firstChild); - } + + let maybeImage = image_area.getElementsByClassName("action_image")[0]; + if (maybeImage) maybeImage.remove(); + + $el("#image-loading").classList.add("hidden"); + if (data.value != "") { var image = new Image(); image.src = 'data:image/png;base64,'+data.value; @@ -5991,6 +5994,11 @@ $el("#aidgpromptnum").addEventListener("keydown", function(event) { event.preventDefault(); }); +$el("#generate-image-button").addEventListener("click", function() { + $el("#image-loading").classList.remove("hidden"); + socket.emit("generate_image", {}); +}); + /* -- Shiny New Chat -- */ function addMessage(author, content, actionId, afterMsgEl=null, time=null) { if (!time) time = Number(new Date()); diff --git a/templates/settings flyout.html b/templates/settings flyout.html index 3ddf3c9a..8dcfcf52 100644 --- a/templates/settings flyout.html +++ b/templates/settings flyout.html @@ -112,8 +112,12 @@ Download debug dump
- -
+ +
+ +