From f7bb578a1409b1f96aff534ff5ed2bd10502296f Mon Sep 17 00:00:00 2001 From: lllyasviel Date: Wed, 20 Dec 2023 19:52:38 -0800 Subject: [PATCH] 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 8d6fe94..43705b4 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 c2c8632..81b942e 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 0000000..6898133 --- /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 b91f68d..83ba9e3 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 5c2efd8..ef90698 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 00b1e44..35566b4 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) \