From f7bb578a1409b1f96aff534ff5ed2bd10502296f Mon Sep 17 00:00:00 2001 From: lllyasviel Date: Wed, 20 Dec 2023 19:52:38 -0800 Subject: [PATCH 1/5] 2.1.854 * Add a button to copy parameters to clipboard in log. * Allow users to load parameters directly by pasting parameters to prompt. --- fooocus_version.py | 2 +- modules/async_worker.py | 8 +-- modules/meta_parser.py | 144 ++++++++++++++++++++++++++++++++++++++ modules/private_logger.py | 23 +++++- update_log.md | 5 ++ webui.py | 48 ++++++++++++- 6 files changed, 222 insertions(+), 8 deletions(-) create mode 100644 modules/meta_parser.py diff --git a/fooocus_version.py b/fooocus_version.py index 8d6fe946..43705b4a 100644 --- a/fooocus_version.py +++ b/fooocus_version.py @@ -1 +1 @@ -version = '2.1.853' +version = '2.1.854' diff --git a/modules/async_worker.py b/modules/async_worker.py index c2c8632d..81b942e9 100644 --- a/modules/async_worker.py +++ b/modules/async_worker.py @@ -397,8 +397,8 @@ def worker(): uc=None, positive_top_k=len(positive_basic_workloads), negative_top_k=len(negative_basic_workloads), - log_positive_prompt='; '.join([task_prompt] + task_extra_positive_prompts), - log_negative_prompt='; '.join([task_negative_prompt] + task_extra_negative_prompts), + log_positive_prompt='\n'.join([task_prompt] + task_extra_positive_prompts), + log_negative_prompt='\n'.join([task_negative_prompt] + task_extra_negative_prompts), )) if use_expansion: @@ -777,9 +777,9 @@ def worker(): ('Scheduler', scheduler_name), ('Seed', task['task_seed']), ] - for n, w in loras: + for li, (n, w) in enumerate(loras): if n != 'None': - d.append((f'LoRA', f'{n} : {w}')) + d.append((f'LoRA {li + 1}', f'{n} : {w}')) d.append(('Version', 'v' + fooocus_version.version)) log(x, d) diff --git a/modules/meta_parser.py b/modules/meta_parser.py new file mode 100644 index 00000000..6898133d --- /dev/null +++ b/modules/meta_parser.py @@ -0,0 +1,144 @@ +import json +import gradio as gr +import modules.config + + +def load_parameter_button_click(raw_prompt_txt): + loaded_parameter_dict = json.loads(raw_prompt_txt) + assert isinstance(loaded_parameter_dict, dict) + + results = [True] + + try: + h = loaded_parameter_dict.get('Prompt', None) + assert isinstance(h, str) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Negative Prompt', None) + assert isinstance(h, str) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Styles', None) + h = eval(h) + assert isinstance(h, list) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Performance', None) + assert isinstance(h, str) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Resolution', None) + width, height = eval(h) + formatted = modules.config.add_ratio(f'{width}*{height}') + if formatted in modules.config.available_aspect_ratios: + results.append(formatted) + results.append(-1) + results.append(-1) + else: + results.append(gr.update()) + results.append(width) + results.append(height) + except: + results.append(gr.update()) + results.append(gr.update()) + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Sharpness', None) + assert h is not None + h = float(h) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Guidance Scale', None) + assert h is not None + h = float(h) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('ADM Guidance', None) + p, n, e = eval(h) + results.append(float(p)) + results.append(float(n)) + results.append(float(e)) + except: + results.append(gr.update()) + results.append(gr.update()) + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Base Model', None) + assert isinstance(h, str) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Refiner Model', None) + assert isinstance(h, str) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Refiner Switch', None) + assert h is not None + h = float(h) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Sampler', None) + assert isinstance(h, str) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Scheduler', None) + assert isinstance(h, str) + results.append(h) + except: + results.append(gr.update()) + + try: + h = loaded_parameter_dict.get('Seed', None) + assert h is not None + h = int(h) + results.append(False) + results.append(h) + except: + results.append(gr.update()) + results.append(gr.update()) + + results.append(gr.update(visible=True)) + results.append(gr.update(visible=False)) + + for i in range(1, 6): + try: + n, w = loaded_parameter_dict.get(f'LoRA {i}').split(' : ') + w = float(w) + results.append(n) + results.append(w) + except: + results.append(gr.update()) + results.append(gr.update()) + + return results diff --git a/modules/private_logger.py b/modules/private_logger.py index b91f68d3..83ba9e36 100644 --- a/modules/private_logger.py +++ b/modules/private_logger.py @@ -1,6 +1,8 @@ import os import args_manager import modules.config +import json +import urllib.parse from PIL import Image from modules.util import generate_temp_filename @@ -36,10 +38,22 @@ def log(img, dic): ".image-container img { height: auto; max-width: 512px; display: block; padding-right:10px; } " ".image-container div { text-align: center; padding: 4px; } " "hr { border-color: gray; } " + "button { background-color: black; color: white; border: 1px solid grey; border-radius: 5px; padding: 5px 10px; text-align: center; display: inline-block; font-size: 16px; cursor: pointer; }" + "button:hover {background-color: grey; color: black;}" "" ) - begin_part = f"Fooocus Log {date_string}{css_styles}

Fooocus Log {date_string} (private)

\n

All images are clean, without any hidden data/meta, and safe to share with others.

\n\n" + js = ( + "" + ) + + begin_part = f"Fooocus Log {date_string}{css_styles}{js}

Fooocus Log {date_string} (private)

\n

All images are clean, without any hidden data/meta, and safe to share with others.

\n\n" end_part = f'\n' middle_part = log_cache.get(html_name, "") @@ -57,8 +71,13 @@ def log(img, dic): item += f"
{only_name}
" item += "" for key, value in dic: - item += f"\n" + value_txt = str(value).replace('\n', '
') + item += f"\n" item += "
{key}{value}
{key}{value_txt}
" + + js_txt = urllib.parse.quote(json.dumps({k: v for k, v in dic}, indent=0), safe='') + item += f"
" + item += "" item += "\n\n" diff --git a/update_log.md b/update_log.md index 5c2efd87..ef906987 100644 --- a/update_log.md +++ b/update_log.md @@ -1,3 +1,8 @@ +# 2.1.854 + +* Add a button to copy parameters to clipboard in log. +* Allow users to load parameters directly by pasting parameters to prompt. + # 2.1.853 * Add Marc K3nt3L's styles. Thanks [Marc K3nt3L](https://github.com/K3nt3L)! diff --git a/webui.py b/webui.py index 00b1e44e..35566b49 100644 --- a/webui.py +++ b/webui.py @@ -1,6 +1,7 @@ import gradio as gr import random import os +import json import time import shared import modules.config @@ -12,6 +13,7 @@ import modules.flags as flags import modules.gradio_hijack as grh import modules.advanced_parameters as advanced_parameters import modules.style_sorter as style_sorter +import modules.meta_parser import args_manager import copy @@ -100,7 +102,7 @@ with shared.gradio_root: elem_id='final_gallery') with gr.Row(elem_classes='type_row'): with gr.Column(scale=17): - prompt = gr.Textbox(show_label=False, placeholder="Type prompt here.", elem_id='positive_prompt', + prompt = gr.Textbox(show_label=False, placeholder="Type prompt here or paste parameters.", elem_id='positive_prompt', container=False, autofocus=True, elem_classes='type_row', lines=1024) default_prompt = modules.config.default_prompt @@ -109,6 +111,7 @@ with shared.gradio_root: with gr.Column(scale=3, min_width=0): generate_button = gr.Button(label="Generate", value="Generate", elem_classes='type_row', elem_id='generate_button', visible=True) + load_parameter_button = gr.Button(label="Load Parameters", value="Load Parameters", elem_classes='type_row', elem_id='load_parameter_button', visible=False) skip_button = gr.Button(label="Skip", value="Skip", elem_classes='type_row_half', visible=False) stop_button = gr.Button(label="Stop", value="Stop", elem_classes='type_row_half', elem_id='stop_button', visible=False) @@ -510,6 +513,49 @@ with shared.gradio_root: ctrls += [outpaint_selections, inpaint_input_image, inpaint_additional_prompt] ctrls += ip_ctrls + def parse_meta(raw_prompt_txt): + loaded_json = None + try: + if '{' in raw_prompt_txt: + if '}' in raw_prompt_txt: + if ':' in raw_prompt_txt: + loaded_json = json.loads(raw_prompt_txt) + assert isinstance(loaded_json, dict) + except: + loaded_json = None + + if loaded_json is None: + return gr.update(), gr.update(visible=True), gr.update(visible=False) + + return json.dumps(loaded_json), gr.update(visible=False), gr.update(visible=True) + + prompt.input(parse_meta, inputs=prompt, outputs=[prompt, generate_button, load_parameter_button], queue=False, show_progress=False) + + load_parameter_button.click(modules.meta_parser.load_parameter_button_click, inputs=prompt, outputs=[ + advanced_checkbox, + prompt, + negative_prompt, + style_selections, + performance_selection, + aspect_ratios_selection, + overwrite_width, + overwrite_height, + sharpness, + guidance_scale, + adm_scaler_positive, + adm_scaler_negative, + adm_scaler_end, + base_model, + refiner_model, + refiner_switch, + sampler_name, + scheduler_name, + seed_random, + image_seed, + generate_button, + load_parameter_button + ] + lora_ctrls, queue=False, show_progress=False) + generate_button.click(lambda: (gr.update(visible=True, interactive=True), gr.update(visible=True, interactive=True), gr.update(visible=False), []), outputs=[stop_button, skip_button, generate_button, gallery]) \ .then(fn=refresh_seed, inputs=[seed_random, image_seed], outputs=image_seed) \ .then(advanced_parameters.set_all_advanced_parameters, inputs=adps) \ From 81107298a87c3c1f8743c32ed1431083366e2d39 Mon Sep 17 00:00:00 2001 From: lllyasviel Date: Wed, 20 Dec 2023 19:58:53 -0800 Subject: [PATCH 2/5] minor fix (#1532) --- modules/meta_parser.py | 2 +- webui.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/meta_parser.py b/modules/meta_parser.py index 6898133d..78d73978 100644 --- a/modules/meta_parser.py +++ b/modules/meta_parser.py @@ -7,7 +7,7 @@ def load_parameter_button_click(raw_prompt_txt): loaded_parameter_dict = json.loads(raw_prompt_txt) assert isinstance(loaded_parameter_dict, dict) - results = [True] + results = [True, 1] try: h = loaded_parameter_dict.get('Prompt', None) diff --git a/webui.py b/webui.py index 35566b49..a5138abf 100644 --- a/webui.py +++ b/webui.py @@ -533,6 +533,7 @@ with shared.gradio_root: load_parameter_button.click(modules.meta_parser.load_parameter_button_click, inputs=prompt, outputs=[ advanced_checkbox, + image_number, prompt, negative_prompt, style_selections, From b0df0d57f62636fd8670d8f64482b3cde2aca05c Mon Sep 17 00:00:00 2001 From: lllyasviel Date: Wed, 20 Dec 2023 22:32:44 -0800 Subject: [PATCH 3/5] Update readme.md (#1533) --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index b970ee12..6b458e74 100644 --- a/readme.md +++ b/readme.md @@ -28,6 +28,8 @@ Fooocus has simplified the installation. Between pressing "download" and generat `[1]` David Holz, 2019. +**Recently many fake websites exist on Google when you search “fooocus”. Do not trust those – here is the only official source of Fooocus.** + ## [Installing Fooocus](#download) # Moving from Midjourney to Fooocus From 1f9a072d66e08d5f0aa73f7660ed017257ed6e73 Mon Sep 17 00:00:00 2001 From: lllyasviel Date: Thu, 21 Dec 2023 17:42:45 -0800 Subject: [PATCH 4/5] Announcement --- update_log.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/update_log.md b/update_log.md index ef906987..216a2bc4 100644 --- a/update_log.md +++ b/update_log.md @@ -1,3 +1,5 @@ +**(2023 Dec 21) Hi all, the feature updating of Fooocus will be paused for about two or three weeks because we have some other workloads. See you soon and we will come back in mid or late Jan. However, you may still see updates if other collaborators are fixing bugs or solving problems.** + # 2.1.854 * Add a button to copy parameters to clipboard in log. From 7b5bced6c2e98efa5c013624f6466ed0ba76970c Mon Sep 17 00:00:00 2001 From: lllyasviel Date: Fri, 22 Dec 2023 00:20:09 -0800 Subject: [PATCH 5/5] small url fix (#1551) --- fooocus_version.py | 2 +- modules/async_worker.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fooocus_version.py b/fooocus_version.py index 43705b4a..2511cfc7 100644 --- a/fooocus_version.py +++ b/fooocus_version.py @@ -1 +1 @@ -version = '2.1.854' +version = '2.1.855' diff --git a/modules/async_worker.py b/modules/async_worker.py index 81b942e9..fab2508e 100644 --- a/modules/async_worker.py +++ b/modules/async_worker.py @@ -277,9 +277,10 @@ def worker(): inpaint_image = HWC3(inpaint_image) if isinstance(inpaint_image, np.ndarray) and isinstance(inpaint_mask, np.ndarray) \ and (np.any(inpaint_mask > 127) or len(outpaint_selections) > 0): + progressbar(async_task, 1, 'Downloading upscale models ...') + modules.config.downloading_upscale_model() if inpaint_parameterized: progressbar(async_task, 1, 'Downloading inpainter ...') - modules.config.downloading_upscale_model() inpaint_head_model_path, inpaint_patch_model_path = modules.config.downloading_inpaint_models( advanced_parameters.inpaint_engine) base_model_additional_loras += [(inpaint_patch_model_path, 1.0)]