* Aspect ratios now show aspect ratios.
* Added style search.
* Added style sorting/ordering/favorites.
This commit is contained in:
lllyasviel 2023-11-14 14:06:12 -08:00 committed by GitHub
parent 375b30f375
commit cec0c2a8df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 147 additions and 15 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ __pycache__
*.patch *.patch
*.backup *.backup
*.corrupted *.corrupted
sorted_styles.json
/language/default.json /language/default.json
lena.png lena.png
lena_result.png lena_result.png

View File

@ -73,6 +73,10 @@ function processNode(node) {
}); });
} }
function refresh_style_localization() {
processNode(document.querySelector('.style_selections'));
}
function localizeWholePage() { function localizeWholePage() {
processNode(gradioApp()); processNode(gradioApp());

View File

@ -7,7 +7,7 @@ function refresh_grid() {
if (gridContainer) if (final_gallery) { if (gridContainer) if (final_gallery) {
let rect = final_gallery.getBoundingClientRect(); let rect = final_gallery.getBoundingClientRect();
let cols = Math.ceil((rect.width - 16.0) / rect.height); let cols = Math.ceil((rect.width - 16.0) / rect.height);
if(cols < 2) cols = 2; if (cols < 2) cols = 2;
gridContainer.style.setProperty('--grid-cols', cols); gridContainer.style.setProperty('--grid-cols', cols);
} }
} }
@ -56,3 +56,27 @@ window.addEventListener('resize', (e) => {
onUiLoaded(async () => { onUiLoaded(async () => {
resized(); resized();
}); });
function on_style_selection_blur() {
let target = document.querySelector("#gradio_receiver_style_selections textarea");
target.value = "on_style_selection_blur " + Math.random();
let e = new Event("input", {bubbles: true})
Object.defineProperty(e, "target", {value: target})
target.dispatchEvent(e);
}
onUiLoaded(async () => {
let spans = document.querySelectorAll('.aspect_ratios span');
spans.forEach(function (span) {
span.innerHTML = span.innerHTML.replace(/&lt;/g, '<').replace(/&gt;/g, '>');
});
document.querySelector('.style_selections').addEventListener('focusout', function (event) {
setTimeout(() => {
if (!this.contains(document.activeElement)) {
on_style_selection_blur();
}
}, 200);
});
});

View File

@ -209,7 +209,7 @@ def worker():
tiled = False tiled = False
inpaint_worker.current_task = None inpaint_worker.current_task = None
width, height = aspect_ratios_selection.split('×') width, height = aspect_ratios_selection.replace('×', ' ').split(' ')[:2]
width, height = int(width), int(height) width, height = int(width), int(height)
skip_prompt_processing = False skip_prompt_processing = False

View File

@ -1,5 +1,6 @@
import os import os
import json import json
import math
import args_manager import args_manager
import modules.flags import modules.flags
import modules.sdxl_styles import modules.sdxl_styles
@ -247,6 +248,17 @@ default_aspect_ratio = get_config_item_or_set_default(
validator=lambda x: x in available_aspect_ratios validator=lambda x: x in available_aspect_ratios
) )
def add_ratio(x):
a, b = x.replace('*', ' ').split(' ')[:2]
a, b = int(a), int(b)
g = math.gcd(a, b)
return f'{a}×{b} <span style="color: grey;"> \U00002223 {a // g}:{b // g}</span>'
default_aspect_ratio = add_ratio(default_aspect_ratio)
available_aspect_ratios = [add_ratio(x) for x in available_aspect_ratios]
with open(config_path, "w", encoding="utf-8") as json_file: with open(config_path, "w", encoding="utf-8") as json_file:
json.dump({k: config_dict[k] for k in always_save_keys}, json_file, indent=4) json.dump({k: config_dict[k] for k in always_save_keys}, json_file, indent=4)
@ -264,9 +276,6 @@ os.makedirs(path_outputs, exist_ok=True)
model_filenames = [] model_filenames = []
lora_filenames = [] lora_filenames = []
available_aspect_ratios = [x.replace('*', '×') for x in available_aspect_ratios]
default_aspect_ratio = default_aspect_ratio.replace('*', '×')
def get_model_filenames(folder_path, name_filter=None): def get_model_filenames(folder_path, name_filter=None):
return get_files_from_folder(folder_path, ['.pth', '.ckpt', '.bin', '.safetensors', '.fooocus.patch'], name_filter) return get_files_from_folder(folder_path, ['.pth', '.ckpt', '.bin', '.safetensors', '.fooocus.patch'], name_filter)

View File

@ -100,6 +100,18 @@ progress::after {
overflow: auto !important; overflow: auto !important;
} }
.aspect_ratios label {
width: 140px !important;
}
.aspect_ratios label span {
white-space: nowrap !important;
}
.aspect_ratios label input {
margin-left: -5px !important;
}
''' '''
progress_html = ''' progress_html = '''
<div class="loader-container"> <div class="loader-container">

View File

@ -2,29 +2,30 @@ import json
import os import os
current_translation = {}
localization_root = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'language') localization_root = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'language')
def localization_js(filename): def localization_js(filename):
data = {} global current_translation
if isinstance(filename, str): if isinstance(filename, str):
full_name = os.path.abspath(os.path.join(localization_root, filename + '.json')) full_name = os.path.abspath(os.path.join(localization_root, filename + '.json'))
if os.path.exists(full_name): if os.path.exists(full_name):
try: try:
with open(full_name, encoding='utf-8') as f: with open(full_name, encoding='utf-8') as f:
data = json.load(f) current_translation = json.load(f)
assert isinstance(data, dict) assert isinstance(current_translation, dict)
for k, v in data.items(): for k, v in current_translation.items():
assert isinstance(k, str) assert isinstance(k, str)
assert isinstance(v, str) assert isinstance(v, str)
except Exception as e: except Exception as e:
print(str(e)) print(str(e))
print(f'Failed to load localization file {full_name}') print(f'Failed to load localization file {full_name}')
# data = {k: 'XXX' for k in data.keys()} # use this to see if all texts are covered # current_translation = {k: 'XXX' for k in current_translation.keys()} # use this to see if all texts are covered
return f"window.localization = {json.dumps(data)}" return f"window.localization = {json.dumps(current_translation)}"
def dump_english_config(components): def dump_english_config(components):

54
modules/style_sorter.py Normal file
View File

@ -0,0 +1,54 @@
import os
import gradio as gr
import modules.localization as localization
import json
all_styles = []
def try_load_sorted_styles(style_names, default_selected):
global all_styles
all_styles = style_names
try:
if os.path.exists('sorted_styles.json'):
with open('sorted_styles.json', 'rt', encoding='utf-8') as fp:
sorted_styles = json.load(fp)
if len(sorted_styles) == len(all_styles):
if all(x in all_styles for x in sorted_styles):
if all(x in sorted_styles for x in all_styles):
all_styles = sorted_styles
except Exception as e:
print('Load style sorting failed.')
print(e)
unselected = [y for y in all_styles if y not in default_selected]
all_styles = default_selected + unselected
return all_styles
def sort_styles(selected):
unselected = [y for y in all_styles if y not in selected]
sorted_styles = selected + unselected
try:
with open('sorted_styles.json', 'wt', encoding='utf-8') as fp:
json.dump(sorted_styles, fp, indent=4)
except Exception as e:
print('Write style sorting failed.')
print(e)
return gr.CheckboxGroup.update(choices=sorted_styles)
def localization_key(x):
return x + localization.current_translation.get(x, '')
def search_styles(selected, query):
unselected = [y for y in all_styles if y not in selected]
matched = [y for y in unselected if query.lower() in localization_key(y).lower()] if len(query) > 0 else []
unmatched = [y for y in unselected if y not in matched]
sorted_styles = matched + selected + unmatched
return gr.CheckboxGroup.update(choices=sorted_styles)

View File

@ -11,7 +11,9 @@ import modules.constants as constants
import modules.flags as flags import modules.flags as flags
import modules.gradio_hijack as grh import modules.gradio_hijack as grh
import modules.advanced_parameters as advanced_parameters import modules.advanced_parameters as advanced_parameters
import modules.style_sorter as style_sorter
import args_manager import args_manager
import copy
from modules.sdxl_styles import legal_style_names from modules.sdxl_styles import legal_style_names
from modules.private_logger import get_current_html_path from modules.private_logger import get_current_html_path
@ -193,7 +195,8 @@ with shared.gradio_root:
choices=['Speed', 'Quality', 'Extreme Speed'], choices=['Speed', 'Quality', 'Extreme Speed'],
value='Speed') value='Speed')
aspect_ratios_selection = gr.Radio(label='Aspect Ratios', choices=modules.config.available_aspect_ratios, aspect_ratios_selection = gr.Radio(label='Aspect Ratios', choices=modules.config.available_aspect_ratios,
value=modules.config.default_aspect_ratio, info='width × height') value=modules.config.default_aspect_ratio, info='width × height',
elem_classes='aspect_ratios')
image_number = gr.Slider(label='Image Number', minimum=1, maximum=32, step=1, value=modules.config.default_image_number) image_number = gr.Slider(label='Image Number', minimum=1, maximum=32, step=1, value=modules.config.default_image_number)
negative_prompt = gr.Textbox(label='Negative Prompt', show_label=True, placeholder="Type prompt here.", negative_prompt = gr.Textbox(label='Negative Prompt', show_label=True, placeholder="Type prompt here.",
info='Describing what you do not want to see.', lines=2, info='Describing what you do not want to see.', lines=2,
@ -222,10 +225,34 @@ with shared.gradio_root:
gr.HTML(f'<a href="/file={get_current_html_path()}" target="_blank">\U0001F4DA History Log</a>') gr.HTML(f'<a href="/file={get_current_html_path()}" target="_blank">\U0001F4DA History Log</a>')
with gr.Tab(label='Style'): with gr.Tab(label='Style'):
initial_style_sorting = style_sorter.try_load_sorted_styles(
style_names=legal_style_names, default_selected=modules.config.default_styles)
style_search_bar = gr.Textbox(show_label=False, container=False,
placeholder="\U0001F50E Type here to search styles ...",
value="",
label='Search Styles')
style_selections = gr.CheckboxGroup(show_label=False, container=False, style_selections = gr.CheckboxGroup(show_label=False, container=False,
choices=legal_style_names, choices=initial_style_sorting,
value=modules.config.default_styles, value=copy.deepcopy(modules.config.default_styles),
label='Image Style') label='Selected Styles',
elem_classes=['style_selections'])
gradio_receiver_style_selections = gr.Textbox(elem_id='gradio_receiver_style_selections', visible=False)
style_search_bar.change(style_sorter.search_styles,
inputs=[style_selections, style_search_bar],
outputs=style_selections,
queue=False,
show_progress=False).then(
lambda: None, _js='()=>{refresh_style_localization();}')
gradio_receiver_style_selections.input(style_sorter.sort_styles,
inputs=style_selections,
outputs=style_selections,
queue=False,
show_progress=False).then(
lambda: None, _js='()=>{refresh_style_localization();}')
with gr.Tab(label='Model'): with gr.Tab(label='Model'):
with gr.Row(): with gr.Row():
base_model = gr.Dropdown(label='Base Model (SDXL only)', choices=modules.config.model_filenames, value=modules.config.default_base_model_name, show_label=True) base_model = gr.Dropdown(label='Base Model (SDXL only)', choices=modules.config.model_filenames, value=modules.config.default_base_model_name, show_label=True)