From 107bbfa2919ed084cc79cc5f62bc7cfd93d27770 Mon Sep 17 00:00:00 2001 From: Robert Vining Date: Tue, 1 Nov 2022 18:01:20 +1000 Subject: [PATCH 1/3] Added new function text2img_api() - sends prompt to locally hosted stable-diffusion-webui API and retrieves image result. info from SD API is embedded in png file as it is saved. image files are named with the current date at generation and saved in /stories/art/ Modified UI_2_generate_image() to call text2img_api() instead of text2img_horde Signed-off-by: Robert Vining --- aiserver.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/aiserver.py b/aiserver.py index 422cbed9..5abec854 100644 --- a/aiserver.py +++ b/aiserver.py @@ -81,7 +81,7 @@ import transformers.generation_utils # Text2img import base64 -from PIL import Image, ImageFont, ImageDraw, ImageFilter, ImageOps +from PIL import Image, ImageFont, ImageDraw, ImageFilter, ImageOps, PngImagePlugin from io import BytesIO global tpu_mtj_backend @@ -9098,7 +9098,7 @@ def UI_2_generate_image(data): #If we don't have a GPU, use horde if we're allowed to start_time = time.time() if ((not koboldai_vars.hascuda or not os.path.exists("models/stable-diffusion-v1-4")) and koboldai_vars.img_gen_priority != 0) or koboldai_vars.img_gen_priority == 3: - b64_data = text2img_horde(", ".join(keys), art_guide = art_guide) + b64_data = text2img_api(", ".join(keys), art_guide = art_guide) else: import psutil #We aren't being forced to use horde, so now let's figure out if we should use local @@ -9108,9 +9108,9 @@ def UI_2_generate_image(data): elif torch.cuda.get_device_properties(0).total_memory > 6000000000 and koboldai_vars.img_gen_priority <= 1: #We could do it locally by swapping the model out print("Could do local or online") - b64_data = text2img_horde(", ".join(keys), art_guide = art_guide) + b64_data = text2img_api(", ".join(keys), art_guide = art_guide) elif koboldai_vars.img_gen_priority != 0: - b64_data = text2img_horde(", ".join(keys), art_guide = art_guide) + b64_data = text2img_api(", ".join(keys), art_guide = art_guide) logger.debug("Time to Generate Image {}".format(time.time()-start_time)) koboldai_vars.picture = b64_data koboldai_vars.picture_prompt = ", ".join(keys) @@ -9136,7 +9136,7 @@ def text2img_local(prompt, art_guide="", filename="new.png"): def get_image(pipe, prompt, num_inference_steps): from torch import autocast with autocast("cuda"): - return pipe(prompt, num_inference_steps=num_inference_steps)["sample"][0] + return pipe(prompt, num_inference_steps=num_inference_steps).images[0] image = tpool.execute(get_image, pipe, prompt, num_inference_steps=35) buffered = BytesIO() image.save(buffered, format="JPEG") @@ -9195,6 +9195,54 @@ def text2img_horde(prompt, koboldai_vars.generating_image = False logger.error(submit_req.text) +#@logger.catch +def text2img_api(prompt, + art_guide = 'fantasy illustration, artstation, by Hugin Miyama by Taiki Kawakami, cinematic lighting', + filename = "story_art.png"): + logger.debug("Generating Image using external API") + koboldai_vars.generating_image = True + final_imgen_params = { + "prompt": "{}, {}".format(prompt, art_guide), + "n": 1, + "width": 512, + "height": 512, + "steps": 50, + "cfg_scale": 14, + "negative_prompt": " lowres, bad anatomy, bad hands out of frame, two heads, totem pole, several faces, extra fingers, mutated hands, (poorly drawn hands:1.21), (poorly drawn face:1.21), (mutation:1.331), (deformed:1.331), (ugly:1.21), blurry, (bad anatomy:1.21), (bad proportions:1.331), (extra limbs:1.21), glitchy, ((clip through table)), adherent bodies, slimy bodies, (badly visible legs), captions, words", + } + + final_submit_dict = { + "prompt": "{}, {}".format(prompt, art_guide), + "params": final_imgen_params, + } + apiaddress = 'http://127.0.0.1:7860/sdapi/v1/txt2img' + payload_json = json.dumps(final_imgen_params) + logger.debug(final_submit_dict) + 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)[1]))) + 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)) + #dtnow = datetime.datetime.now() + #dt_string = dtnow().strftime("%H%M%S%d%m%Y") + dt_string = datetime.datetime.now().strftime("%H%M%S%d%m%Y") + final_filename = "stories/art/{}_{}".format(dt_string,filename) + pnginfo = PngImagePlugin.PngInfo() + pnginfo.add_text("parameters", str(results['info'])) + img.save(final_filename, pnginfo=pnginfo) + logger.debug("Saved Image") + koboldai_vars.generating_image = False + return(b64img) + else: + koboldai_vars.generating_image = False + logger.error(submit_req.text) + #@logger.catch def get_items_locations_from_text(text): # load model and tokenizer From 0bb6e0afae21b59023111d75418311bcb57798ed Mon Sep 17 00:00:00 2001 From: Robert Vining Date: Tue, 1 Nov 2022 23:24:19 +1000 Subject: [PATCH 2/3] - Updated UI_2_generate_image()to reference new option in the Image Generation dropdown menu. - Using Local SD-WebUI API option will send a post request to stable-diffusion-webui running with the --api switch on http://127.0.0.1:7860/sdapi/v1/txt2img Signed-off-by: Robert Vining --- aiserver.py | 85 ++++++++++++++++++++++++++++++++++++-------------- gensettings.py | 2 +- 2 files changed, 62 insertions(+), 25 deletions(-) diff --git a/aiserver.py b/aiserver.py index 5abec854..d6675ebb 100644 --- a/aiserver.py +++ b/aiserver.py @@ -9097,20 +9097,24 @@ def UI_2_generate_image(data): #If we don't have a GPU, use horde if we're allowed to start_time = time.time() - if ((not koboldai_vars.hascuda or not os.path.exists("models/stable-diffusion-v1-4")) and koboldai_vars.img_gen_priority != 0) or koboldai_vars.img_gen_priority == 3: + # Check if stable-diffusion-webui API option selected and use that if found. + if koboldai_vars.img_gen_priority == 4: b64_data = text2img_api(", ".join(keys), art_guide = art_guide) else: - import psutil - #We aren't being forced to use horde, so now let's figure out if we should use local - if torch.cuda.get_device_properties(0).total_memory - torch.cuda.memory_reserved(0) >= 6000000000: - #He have enough vram, just do it locally - b64_data = text2img_local(", ".join(keys), art_guide = art_guide) - elif torch.cuda.get_device_properties(0).total_memory > 6000000000 and koboldai_vars.img_gen_priority <= 1: - #We could do it locally by swapping the model out - print("Could do local or online") - b64_data = text2img_api(", ".join(keys), art_guide = art_guide) - elif koboldai_vars.img_gen_priority != 0: - b64_data = text2img_api(", ".join(keys), art_guide = art_guide) + if ((not koboldai_vars.hascuda or not os.path.exists("models/stable-diffusion-v1-4")) and koboldai_vars.img_gen_priority != 0) or koboldai_vars.img_gen_priority == 3: + b64_data = text2img_horde(", ".join(keys), art_guide = art_guide) + else: + import psutil + #We aren't being forced to use horde, so now let's figure out if we should use local + if torch.cuda.get_device_properties(0).total_memory - torch.cuda.memory_reserved(0) >= 6000000000: + #He have enough vram, just do it locally + b64_data = text2img_local(", ".join(keys), art_guide = art_guide) + elif torch.cuda.get_device_properties(0).total_memory > 6000000000 and koboldai_vars.img_gen_priority <= 1: + #We could do it locally by swapping the model out + print("Could do local or online") + b64_data = text2img_horde(", ".join(keys), art_guide = art_guide) + elif koboldai_vars.img_gen_priority != 0: + b64_data = text2img_horde(", ".join(keys), art_guide = art_guide) logger.debug("Time to Generate Image {}".format(time.time()-start_time)) koboldai_vars.picture = b64_data koboldai_vars.picture_prompt = ", ".join(keys) @@ -9157,8 +9161,8 @@ def text2img_local(prompt, art_guide="", filename="new.png"): return img_str @logger.catch -def text2img_horde(prompt, - art_guide = 'fantasy illustration, artstation, by jason felix by steve argyle by tyler jacobson by peter mohrbacher, cinematic lighting', +def text2img_horde(prompt, + art_guide = 'fantasy illustration, artstation, by jason felix by steve argyle by tyler jacobson by peter mohrbacher, cinematic lighting', filename = "story_art.png"): logger.debug("Generating Image using Horde") koboldai_vars.generating_image = True @@ -9195,27 +9199,61 @@ def text2img_horde(prompt, koboldai_vars.generating_image = False logger.error(submit_req.text) -#@logger.catch -def text2img_api(prompt, - art_guide = 'fantasy illustration, artstation, by Hugin Miyama by Taiki Kawakami, cinematic lighting', +@logger.catch +def text2img_api(prompt, + #art_guide = 'fantasy illustration, artstation, by Hugin Miyama by Taiki Kawakami, cinematic lighting', + art_guide = 'fantasy illustration, artstation, by jason felix by steve argyle by tyler jacobson by peter mohrbacher, cinematic lighting', filename = "story_art.png"): - logger.debug("Generating Image using external API") + logger.debug("Generating Image using Local SD-WebUI API") koboldai_vars.generating_image = True + #Add items that you want the AI to avoid in your image. + negprompt = 'lowres, bad anatomy, bad hands out of frame, two heads, totem pole, several faces, extra fingers, mutated hands, (poorly drawn hands:1.21), (poorly drawn face:1.21), (mutation:1.331), (deformed:1.331), (ugly:1.21), blurry, (bad anatomy:1.21), (bad proportions:1.331), (extra limbs:1.21), glitchy, ((clip through table)), adherent bodies, slimy bodies, (badly visible legs), captions, words' + #The following list are valid properties with their defaults, to add/modify in final_imgen_params. Will refactor configuring values into UI element in future. + #"enable_hr": false, + #"denoising_strength": 0, + #"firstphase_width": 0, + #"firstphase_height": 0, + #"prompt": "", + #"styles": [ + # "string" + #], + #"seed": -1, + #"subseed": -1, + #"subseed_strength": 0, + #"seed_resize_from_h": -1, + #"seed_resize_from_w": -1, + #"batch_size": 1, + #"n_iter": 1, + #"steps": 50, + #"cfg_scale": 7, + #"width": 512, + #"height": 512, + #"restore_faces": false, + #"tiling": false, + #"negative_prompt": "string", + #"eta": 0, + #"s_churn": 0, + #"s_tmax": 0, + #"s_tmin": 0, + #"s_noise": 1, + #"override_settings": {}, + #"sampler_index": "Euler" final_imgen_params = { "prompt": "{}, {}".format(prompt, art_guide), "n": 1, "width": 512, "height": 512, - "steps": 50, - "cfg_scale": 14, - "negative_prompt": " lowres, bad anatomy, bad hands out of frame, two heads, totem pole, several faces, extra fingers, mutated hands, (poorly drawn hands:1.21), (poorly drawn face:1.21), (mutation:1.331), (deformed:1.331), (ugly:1.21), blurry, (bad anatomy:1.21), (bad proportions:1.331), (extra limbs:1.21), glitchy, ((clip through table)), adherent bodies, slimy bodies, (badly visible legs), captions, words", + "steps": 40, + "cfg_scale": 10, + "negative_prompt": "{}".format(negprompt), + "sampler_index": "Euler a" } final_submit_dict = { "prompt": "{}, {}".format(prompt, art_guide), "params": final_imgen_params, } - apiaddress = 'http://127.0.0.1:7860/sdapi/v1/txt2img' + apiaddress = 'http://127.0.0.1:7860/sdapi/v1/txt2img' payload_json = json.dumps(final_imgen_params) logger.debug(final_submit_dict) submit_req = requests.post(url=f'{apiaddress}', data=payload_json).json() @@ -9229,13 +9267,12 @@ def text2img_api(prompt, base64_bytes = b64img.encode('utf-8') img_bytes = base64.b64decode(base64_bytes) img = Image.open(BytesIO(img_bytes)) - #dtnow = datetime.datetime.now() - #dt_string = dtnow().strftime("%H%M%S%d%m%Y") dt_string = datetime.datetime.now().strftime("%H%M%S%d%m%Y") final_filename = "stories/art/{}_{}".format(dt_string,filename) pnginfo = PngImagePlugin.PngInfo() pnginfo.add_text("parameters", str(results['info'])) img.save(final_filename, pnginfo=pnginfo) + #img.save(final_filename) logger.debug("Saved Image") koboldai_vars.generating_image = False return(b64img) diff --git a/gensettings.py b/gensettings.py index dc428fc5..b41a7712 100644 --- a/gensettings.py +++ b/gensettings.py @@ -551,7 +551,7 @@ gensettingstf = [ "sub_path": "Images", "classname": "user", "name": "img_gen_priority", - 'children': [{'text': 'Use Local Only', 'value': 0}, {'text':'Prefer Local','value':1}, {'text':'Prefer Horde', 'value':2}, {'text':'Use Horde Only', 'value':3}] + 'children': [{'text': 'Use Local Only', 'value': 0}, {'text':'Prefer Local','value':1}, {'text':'Prefer Horde', 'value':2}, {'text':'Use Horde Only', 'value':3}, {'text':'Use Local SD-WebUI API', 'value':4}] }, { "UI_V2_Only": True, From 09e1bb83669fa51897a3d199c7aa20bd197eaeb7 Mon Sep 17 00:00:00 2001 From: ebolam Date: Tue, 1 Nov 2022 15:03:47 -0400 Subject: [PATCH 3/3] Add back in horde generation if statement --- aiserver.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aiserver.py b/aiserver.py index fbd4689e..39544baa 100644 --- a/aiserver.py +++ b/aiserver.py @@ -9127,6 +9127,8 @@ def UI_2_generate_image(data): # Check if stable-diffusion-webui API option selected and use that if found. if koboldai_vars.img_gen_priority == 4: b64_data = text2img_api(", ".join(keys), art_guide = art_guide) + elif ((not koboldai_vars.hascuda or not os.path.exists("models/stable-diffusion-v1-4")) and koboldai_vars.img_gen_priority != 0) or koboldai_vars.img_gen_priority == 3: + b64_data = text2img_horde(", ".join(keys), art_guide = art_guide) else: if ((not koboldai_vars.hascuda or not os.path.exists("models/stable-diffusion-v1-4")) and koboldai_vars.img_gen_priority != 0) or koboldai_vars.img_gen_priority == 3: b64_data = text2img_horde(", ".join(keys), art_guide = art_guide)