From 035b875e1a3ce4a925aaba3dd55baea21e765e7f Mon Sep 17 00:00:00 2001 From: Dynamic Date: Thu, 27 Oct 2022 20:14:51 +0900 Subject: [PATCH 01/11] Edit CODEOWNERS for ko_KR.json permissions --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index 935fedcf..fa7b93c7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1,2 @@ * @AUTOMATIC1111 +localizations/ko_KR.json @36DB \ No newline at end of file From 9b50d9bbbfa61828c318373d5a7f0a6c1f3e273c Mon Sep 17 00:00:00 2001 From: Dynamic Date: Thu, 27 Oct 2022 20:16:51 +0900 Subject: [PATCH 02/11] Update CODEOWNERS file --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index fa7b93c7..19e49bf5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1,3 @@ * @AUTOMATIC1111 +[Localization] localizations/ko_KR.json @36DB \ No newline at end of file From 6a0eebfbee40c4c120c480ca229357cd3a9e69f3 Mon Sep 17 00:00:00 2001 From: Dynamic Date: Thu, 27 Oct 2022 20:21:15 +0900 Subject: [PATCH 03/11] Update 2 cause I'm an idiot --- CODEOWNERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 19e49bf5..d42e6412 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,4 @@ * @AUTOMATIC1111 + [Localization] -localizations/ko_KR.json @36DB \ No newline at end of file +/localizations/* @36DB \ No newline at end of file From 34c953381192a2c0167fc1385f91b57b18a603c1 Mon Sep 17 00:00:00 2001 From: Dynamic Date: Thu, 27 Oct 2022 20:23:33 +0900 Subject: [PATCH 04/11] Apparently brackets don't work, gitlab docs fooled me --- CODEOWNERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index d42e6412..12e87aae 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,4 +1,3 @@ * @AUTOMATIC1111 -[Localization] -/localizations/* @36DB \ No newline at end of file +/localizations/ko_KR.json @36DB \ No newline at end of file From 35c45df28b303a05d56a13cb56d4046f08cf8c25 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 29 Oct 2022 10:56:19 +0300 Subject: [PATCH 05/11] =?UTF-8?q?fix=20broken=20=E2=86=99=20button,=20fix?= =?UTF-8?q?=20field=20paste=20ignoring=20most=20of=20useful=20fields=20for?= =?UTF-8?q?=20for=20#3768?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/generation_parameters_copypaste.py | 38 +++++++++++++------ modules/ui.py | 43 ++++++++-------------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index d590e9ee..bbaad42e 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -6,7 +6,7 @@ import gradio as gr from modules.shared import script_path from modules import shared import tempfile -from PIL import Image, PngImagePlugin +from PIL import Image re_param_code = r'\s*([\w ]+):\s*("(?:\\|\"|[^\"])+"|[^,]*)(?:,|$)' re_param = re.compile(re_param_code) @@ -61,6 +61,24 @@ def add_paste_fields(tabname, init_img, fields): modules.ui.img2img_paste_fields = fields +def integrate_settings_paste_fields(component_dict): + from modules import ui + + settings_map = { + 'sd_hypernetwork': 'Hypernet', + 'CLIP_stop_at_last_layers': 'Clip skip', + 'sd_model_checkpoint': 'Model hash', + } + settings_paste_fields = [ + (component_dict[k], lambda d, k=k, v=v: ui.apply_setting(k, d.get(v, None))) + for k, v in settings_map.items() + ] + + for tabname, info in paste_fields.items(): + if info["fields"] is not None: + info["fields"] += settings_paste_fields + + def create_buttons(tabs_list): buttons = {} for tab in tabs_list: @@ -87,24 +105,22 @@ def run_bind(): ) else: button.click( - fn=lambda x:x, + fn=lambda x: x, inputs=[send_image], outputs=[paste_fields[tab]["init_img"]], ) if send_generate_info and paste_fields[tab]["fields"] is not None: - paste_field_names = ['Prompt', 'Negative prompt', 'Steps', 'Face restoration', 'Size-1', 'Size-2'] - if shared.opts.send_seed: - paste_field_names += ["Seed"] if send_generate_info in paste_fields: - button.click( - fn=lambda *x:x, - inputs=[field for field,name in paste_fields[send_generate_info]["fields"] if name in paste_field_names], - outputs=[field for field,name in paste_fields[tab]["fields"] if name in paste_field_names], - ) + paste_field_names = ['Prompt', 'Negative prompt', 'Steps', 'Face restoration', 'Size-1', 'Size-2'] + (["Seed"] if shared.opts.send_seed else []) + button.click( + fn=lambda *x: x, + inputs=[field for field, name in paste_fields[send_generate_info]["fields"] if name in paste_field_names], + outputs=[field for field, name in paste_fields[tab]["fields"] if name in paste_field_names], + ) else: - connect_paste(button, [(field, name) for field, name in paste_fields[tab]["fields"] if name in paste_field_names], send_generate_info) + connect_paste(button, paste_fields[tab]["fields"], send_generate_info) button.click( fn=None, diff --git a/modules/ui.py b/modules/ui.py index 3c34eca0..5055ca64 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -589,6 +589,7 @@ def create_refresh_button(refresh_component, refresh_method, refreshed_args, ele ) return refresh_button + def create_output_panel(tabname, outdir): def open_folder(f): if not os.path.exists(f): @@ -716,6 +717,7 @@ def create_ui(wrap_gradio_gpu_call): custom_inputs = modules.scripts.scripts_txt2img.setup_ui(is_img2img=False) txt2img_gallery, generation_info, html_info = create_output_panel("txt2img", opts.outdir_txt2img_samples) + parameters_copypaste.bind_buttons({"txt2img": txt2img_paste}, None, txt2img_prompt) connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False) connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True) @@ -784,7 +786,7 @@ def create_ui(wrap_gradio_gpu_call): ] ) - parameters_copypaste.add_paste_fields("txt2img", None, [ + txt2img_paste_fields = [ (txt2img_prompt, "Prompt"), (txt2img_negative_prompt, "Negative prompt"), (steps, "Steps"), @@ -805,7 +807,8 @@ def create_ui(wrap_gradio_gpu_call): (firstphase_width, "First pass size-1"), (firstphase_height, "First pass size-2"), *modules.scripts.scripts_txt2img.infotext_fields - ]) + ] + parameters_copypaste.add_paste_fields("txt2img", None, txt2img_paste_fields) txt2img_preview_params = [ txt2img_prompt, @@ -893,6 +896,7 @@ def create_ui(wrap_gradio_gpu_call): custom_inputs = modules.scripts.scripts_img2img.setup_ui(is_img2img=True) img2img_gallery, generation_info, html_info = create_output_panel("img2img", opts.outdir_img2img_samples) + parameters_copypaste.bind_buttons({"img2img": img2img_paste}, None, img2img_prompt) connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False) connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True) @@ -1038,7 +1042,6 @@ def create_ui(wrap_gradio_gpu_call): parameters_copypaste.add_paste_fields("img2img", init_img, img2img_paste_fields) parameters_copypaste.add_paste_fields("inpaint", init_img_with_mask, img2img_paste_fields) - with gr.Blocks(analytics_enabled=False) as extras_interface: with gr.Row().style(equal_height=False): with gr.Column(variant='panel'): @@ -1050,12 +1053,8 @@ def create_ui(wrap_gradio_gpu_call): image_batch = gr.File(label="Batch Process", file_count="multiple", interactive=True, type="file") with gr.TabItem('Batch from Directory'): - extras_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs, - placeholder="A directory on the same machine where the server is running." - ) - extras_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs, - placeholder="Leave blank to save images to the default path." - ) + extras_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs, placeholder="A directory on the same machine where the server is running.") + extras_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs, placeholder="Leave blank to save images to the default path.") show_extras_results = gr.Checkbox(label='Show result images', value=True) with gr.Tabs(elem_id="extras_resize_mode"): @@ -1087,7 +1086,6 @@ def create_ui(wrap_gradio_gpu_call): submit = gr.Button('Generate', elem_id="extras_generate", variant='primary') - result_images, html_info_x, html_info = create_output_panel("extras", opts.outdir_extras_samples) submit.click( @@ -1121,7 +1119,6 @@ def create_ui(wrap_gradio_gpu_call): ) parameters_copypaste.add_paste_fields("extras", extras_image, None) - extras_image.change( fn=modules.extras.clear_cache, inputs=[], outputs=[] @@ -1587,9 +1584,6 @@ def create_ui(wrap_gradio_gpu_call): if column is not None: column.__exit__() - - - interfaces = [ (txt2img_interface, "txt2img", "txt2img"), (img2img_interface, "img2img", "img2img"), @@ -1599,10 +1593,6 @@ def create_ui(wrap_gradio_gpu_call): (train_interface, "Train", "ti"), ] - interfaces += script_callbacks.ui_tabs_callback() - - interfaces += [(settings_interface, "Settings", "settings")] - css = "" for cssfile in modules.scripts.list_files_with_name("style.css"): @@ -1619,6 +1609,9 @@ def create_ui(wrap_gradio_gpu_call): if not cmd_opts.no_progressbar_hiding: css += css_hide_progressbar + interfaces += script_callbacks.ui_tabs_callback() + interfaces += [(settings_interface, "Settings", "settings")] + with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo: with gr.Row(elem_id="quicksettings"): for i, k, item in quicksettings_list: @@ -1627,6 +1620,9 @@ def create_ui(wrap_gradio_gpu_call): settings_interface.gradio_ref = demo + parameters_copypaste.integrate_settings_paste_fields(component_dict) + parameters_copypaste.run_bind() + with gr.Tabs(elem_id="tabs") as tabs: for interface, label, ifid in interfaces: with gr.TabItem(label, id=ifid, elem_id='tab_' + ifid): @@ -1681,15 +1677,6 @@ def create_ui(wrap_gradio_gpu_call): ] ) - - settings_map = { - 'sd_hypernetwork': 'Hypernet', - 'CLIP_stop_at_last_layers': 'Clip skip', - 'sd_model_checkpoint': 'Model hash', - } - - parameters_copypaste.run_bind() - ui_config_file = cmd_opts.ui_config_file ui_settings = {} settings_count = len(ui_settings) @@ -1708,7 +1695,7 @@ def create_ui(wrap_gradio_gpu_call): def apply_field(obj, field, condition=None, init_field=None): key = path + "/" + field - if getattr(obj,'custom_script_source',None) is not None: + if getattr(obj, 'custom_script_source', None) is not None: key = 'customscript/' + obj.custom_script_source + '/' + key if getattr(obj, 'do_not_save_to_config', False): From 6515dedf57db6a46c7a85b0b7a1eee0daad90123 Mon Sep 17 00:00:00 2001 From: Mackerel Date: Mon, 24 Oct 2022 10:13:25 -0400 Subject: [PATCH 06/11] webui.sh: no automatic git pull --- webui.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/webui.sh b/webui.sh index a9f85d89..cc06f344 100755 --- a/webui.sh +++ b/webui.sh @@ -102,15 +102,14 @@ then exit 1 fi -printf "\n%s\n" "${delimiter}" -printf "Clone or update stable-diffusion-webui" -printf "\n%s\n" "${delimiter}" cd "${install_dir}"/ || { printf "\e[1m\e[31mERROR: Can't cd to %s/, aborting...\e[0m" "${install_dir}"; exit 1; } if [[ -d "${clone_dir}" ]] then cd "${clone_dir}"/ || { printf "\e[1m\e[31mERROR: Can't cd to %s/%s/, aborting...\e[0m" "${install_dir}" "${clone_dir}"; exit 1; } - "${GIT}" pull else + printf "\n%s\n" "${delimiter}" + printf "Clone stable-diffusion-webui" + printf "\n%s\n" "${delimiter}" "${GIT}" clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git "${clone_dir}" cd "${clone_dir}"/ || { printf "\e[1m\e[31mERROR: Can't cd to %s/%s/, aborting...\e[0m" "${install_dir}" "${clone_dir}"; exit 1; } fi From 4609b83cd496013a05e77c42af031d89f07785a9 Mon Sep 17 00:00:00 2001 From: Bruno Seoane Date: Sat, 29 Oct 2022 16:09:19 -0300 Subject: [PATCH 07/11] Add PNG Info endpoint --- modules/api/api.py | 12 +++++++++--- modules/api/models.py | 9 ++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/modules/api/api.py b/modules/api/api.py index 49c213ea..8fcd068d 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -5,7 +5,7 @@ import modules.shared as shared from modules.api.models import * from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images from modules.sd_samplers import all_samplers -from modules.extras import run_extras +from modules.extras import run_extras, run_pnginfo def upscaler_to_index(name: str): try: @@ -32,6 +32,7 @@ class Api: self.app.add_api_route("/sdapi/v1/img2img", self.img2imgapi, methods=["POST"], response_model=ImageToImageResponse) self.app.add_api_route("/sdapi/v1/extra-single-image", self.extras_single_image_api, methods=["POST"], response_model=ExtrasSingleImageResponse) self.app.add_api_route("/sdapi/v1/extra-batch-images", self.extras_batch_images_api, methods=["POST"], response_model=ExtrasBatchImagesResponse) + self.app.add_api_route("/sdapi/v1/png-info", self.pnginfoapi, methods=["POST"], response_model=PNGInfoResponse) def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI): sampler_index = sampler_to_index(txt2imgreq.sampler_index) @@ -125,8 +126,13 @@ class Api: return ExtrasBatchImagesResponse(images=list(map(encode_pil_to_base64, result[0])), html_info=result[1]) - def pnginfoapi(self): - raise NotImplementedError + def pnginfoapi(self, req:PNGInfoRequest): + if(not req.image.strip()): + return PNGInfoResponse(info="") + + result = run_pnginfo(decode_base64_to_image(req.image.strip())) + + return PNGInfoResponse(info=result[1]) def launch(self, server_name, port): self.app.include_router(self.router) diff --git a/modules/api/models.py b/modules/api/models.py index dd122321..58e8e58b 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -1,4 +1,5 @@ import inspect +from click import prompt from pydantic import BaseModel, Field, create_model from typing import Any, Optional from typing_extensions import Literal @@ -148,4 +149,10 @@ class ExtrasBatchImagesRequest(ExtrasBaseRequest): imageList: list[FileData] = Field(title="Images", description="List of images to work on. Must be Base64 strings") class ExtrasBatchImagesResponse(ExtraBaseResponse): - images: list[str] = Field(title="Images", description="The generated images in base64 format.") \ No newline at end of file + images: list[str] = Field(title="Images", description="The generated images in base64 format.") + +class PNGInfoRequest(BaseModel): + image: str = Field(title="Image", description="The base64 encoded PNG image") + +class PNGInfoResponse(BaseModel): + info: str = Field(title="Image info", description="A string with all the info the image had") \ No newline at end of file From 83a1f44ae26cb89492064bb8be0321b14a75efe4 Mon Sep 17 00:00:00 2001 From: Bruno Seoane Date: Sat, 29 Oct 2022 16:10:00 -0300 Subject: [PATCH 08/11] Fix space --- modules/api/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/api/api.py b/modules/api/api.py index 8fcd068d..d0f488ca 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -126,7 +126,7 @@ class Api: return ExtrasBatchImagesResponse(images=list(map(encode_pil_to_base64, result[0])), html_info=result[1]) - def pnginfoapi(self, req:PNGInfoRequest): + def pnginfoapi(self, req: PNGInfoRequest): if(not req.image.strip()): return PNGInfoResponse(info="") From 9bb6b6509aff8c1e6546d5a798ef9e9922758dc4 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 29 Oct 2022 22:20:02 +0300 Subject: [PATCH 09/11] add postprocess call for scripts --- modules/processing.py | 12 +++++++++--- modules/scripts.py | 24 +++++++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 548eec29..50343846 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -478,7 +478,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: model_hijack.embedding_db.load_textual_inversion_embeddings() if p.scripts is not None: - p.scripts.run_alwayson_scripts(p) + p.scripts.process(p) infotexts = [] output_images = [] @@ -501,7 +501,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: seeds = p.all_seeds[n * p.batch_size:(n + 1) * p.batch_size] subseeds = p.all_subseeds[n * p.batch_size:(n + 1) * p.batch_size] - if (len(prompts) == 0): + if len(prompts) == 0: break with devices.autocast(): @@ -590,7 +590,13 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: images.save_image(grid, p.outpath_grids, "grid", p.all_seeds[0], p.all_prompts[0], opts.grid_format, info=infotext(), short_filename=not opts.grid_extended_filename, p=p, grid=True) devices.torch_gc() - return Processed(p, output_images, p.all_seeds[0], infotext() + "".join(["\n\n" + x for x in comments]), subseed=p.all_subseeds[0], all_prompts=p.all_prompts, all_seeds=p.all_seeds, all_subseeds=p.all_subseeds, index_of_first_image=index_of_first_image, infotexts=infotexts) + + res = Processed(p, output_images, p.all_seeds[0], infotext() + "".join(["\n\n" + x for x in comments]), subseed=p.all_subseeds[0], all_prompts=p.all_prompts, all_seeds=p.all_seeds, all_subseeds=p.all_subseeds, index_of_first_image=index_of_first_image, infotexts=infotexts) + + if p.scripts is not None: + p.scripts.postprocess(p, res) + + return res class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): diff --git a/modules/scripts.py b/modules/scripts.py index a7f36012..96e44bfd 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -64,7 +64,16 @@ class Script: def process(self, p, *args): """ This function is called before processing begins for AlwaysVisible scripts. - scripts. You can modify the processing object (p) here, inject hooks, etc. + You can modify the processing object (p) here, inject hooks, etc. + args contains all values returned by components from ui() + """ + + pass + + def postprocess(self, p, processed, *args): + """ + This function is called after processing ends for AlwaysVisible scripts. + args contains all values returned by components from ui() """ pass @@ -289,13 +298,22 @@ class ScriptRunner: return processed - def run_alwayson_scripts(self, p): + def process(self, p): for script in self.alwayson_scripts: try: script_args = p.script_args[script.args_from:script.args_to] script.process(p, *script_args) except Exception: - print(f"Error running alwayson script: {script.filename}", file=sys.stderr) + print(f"Error running process: {script.filename}", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + + def postprocess(self, p, processed): + for script in self.alwayson_scripts: + try: + script_args = p.script_args[script.args_from:script.args_to] + script.postprocess(p, processed, *script_args) + except Exception: + print(f"Error running postprocess: {script.filename}", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) def reload_sources(self, cache): From 4cb5983c308cb8a4940b00babc2cf6fc9261692f Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 29 Oct 2022 22:38:50 +0300 Subject: [PATCH 10/11] rename french translation to be in line with others --- localizations/{fr-FR.json => fr_FR.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename localizations/{fr-FR.json => fr_FR.json} (100%) diff --git a/localizations/fr-FR.json b/localizations/fr_FR.json similarity index 100% rename from localizations/fr-FR.json rename to localizations/fr_FR.json From d699720254365069866eafcdc519743664075a6d Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 29 Oct 2022 22:39:10 +0300 Subject: [PATCH 11/11] add translators to codeowners with their respective translation files --- CODEOWNERS | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 12e87aae..a48d8012 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,13 @@ * @AUTOMATIC1111 - -/localizations/ko_KR.json @36DB \ No newline at end of file +/localizations/ar_AR.json @xmodar @blackneoo +/localizations/de_DE.json @LunixWasTaken +/localizations/es_ES.json @innovaciones +/localizations/fr_FR.json @tumbly +/localizations/it_IT.json @EugenioBuffo +/localizations/ja_JP.json @yuuki76 +/localizations/ko_KR.json @36DB +/localizations/pt_BR.json @M-art-ucci +/localizations/ru_RU.json @kabachuha +/localizations/tr_TR.json @camenduru +/localizations/zh_CN.json @dtlnor @bgluminous +/localizations/zh_TW.json @benlisquare