add the bitton to paste parameters into UI for txt2img, img2img, and pnginfo tabs
fixed some [send to..] buttons to work properly with all tabs
This commit is contained in:
parent
9c92a1a9aa
commit
39ce23f42d
6 changed files with 236 additions and 40 deletions
|
@ -13,6 +13,8 @@ titles = {
|
|||
"Seed": "A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result",
|
||||
"\u{1f3b2}\ufe0f": "Set seed to -1, which will cause a new random number to be used every time",
|
||||
"\u267b\ufe0f": "Reuse seed from last generation, mostly useful if it was randomed",
|
||||
"\u{1f3a8}": "Add a random artist to the prompt.",
|
||||
"\u2199\ufe0f": "Read generation parameters from prompt into user interface.",
|
||||
|
||||
"Inpaint a part of image": "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt",
|
||||
"SD upscale": "Upscale image normally, split result into tiles, improve each tile using img2img, merge whole image back",
|
||||
|
@ -48,8 +50,6 @@ titles = {
|
|||
"Tiling": "Produce an image that can be tiled.",
|
||||
"Tile overlap": "For SD upscale, how much overlap in pixels should there be between tiles. Tiles overlap so that when they are merged back into one picture, there is no clearly visible seam.",
|
||||
|
||||
"Roll": "Add a random artist to the prompt.",
|
||||
|
||||
"Variation seed": "Seed of a different picture to be mixed into the generation.",
|
||||
"Variation strength": "How strong of a variation to produce. At 0, there will be no effect. At 1, you will get the complete picture with variation seed (except for ancestral samplers, where you will just get something).",
|
||||
"Resize seed from height": "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution",
|
||||
|
|
|
@ -25,13 +25,57 @@ function extract_image_from_gallery(gallery){
|
|||
return gallery[index];
|
||||
}
|
||||
|
||||
function extract_image_from_gallery_img2img(gallery){
|
||||
function args_to_array(args){
|
||||
res = []
|
||||
for(var i=0;i<args.length;i++){
|
||||
res.push(args[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function switch_to_txt2img(){
|
||||
gradioApp().querySelectorAll('button')[0].click();
|
||||
|
||||
return args_to_array(arguments);
|
||||
}
|
||||
|
||||
function switch_to_img2img_img2img(){
|
||||
gradioApp().querySelectorAll('button')[1].click();
|
||||
gradioApp().getElementById('mode_img2img').querySelectorAll('button')[0].click();
|
||||
|
||||
return args_to_array(arguments);
|
||||
}
|
||||
|
||||
function switch_to_img2img_inpaint(){
|
||||
gradioApp().querySelectorAll('button')[1].click();
|
||||
gradioApp().getElementById('mode_img2img').querySelectorAll('button')[1].click();
|
||||
|
||||
return args_to_array(arguments);
|
||||
}
|
||||
|
||||
function switch_to_extras(){
|
||||
gradioApp().querySelectorAll('button')[2].click();
|
||||
|
||||
return args_to_array(arguments);
|
||||
}
|
||||
|
||||
function extract_image_from_gallery_txt2img(gallery){
|
||||
switch_to_txt2img()
|
||||
return extract_image_from_gallery(gallery);
|
||||
}
|
||||
|
||||
function extract_image_from_gallery_img2img(gallery){
|
||||
switch_to_img2img_img2img()
|
||||
return extract_image_from_gallery(gallery);
|
||||
}
|
||||
|
||||
function extract_image_from_gallery_inpaint(gallery){
|
||||
switch_to_img2img_inpaint()
|
||||
return extract_image_from_gallery(gallery);
|
||||
}
|
||||
|
||||
function extract_image_from_gallery_extras(gallery){
|
||||
gradioApp().querySelectorAll('button')[2].click();
|
||||
switch_to_extras()
|
||||
return extract_image_from_gallery(gallery);
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@ def run_pnginfo(image):
|
|||
return '', '', ''
|
||||
|
||||
items = image.info
|
||||
geninfo = ''
|
||||
|
||||
if "exif" in image.info:
|
||||
exif = piexif.load(image.info["exif"])
|
||||
|
@ -111,13 +112,14 @@ def run_pnginfo(image):
|
|||
except ValueError:
|
||||
exif_comment = exif_comment.decode('utf8', errors="ignore")
|
||||
|
||||
|
||||
items['exif comment'] = exif_comment
|
||||
geninfo = exif_comment
|
||||
|
||||
for field in ['jfif', 'jfif_version', 'jfif_unit', 'jfif_density', 'dpi', 'exif',
|
||||
'loop', 'background', 'timestamp', 'duration']:
|
||||
items.pop(field, None)
|
||||
|
||||
geninfo = items.get('parameters', geninfo)
|
||||
|
||||
info = ''
|
||||
for key, text in items.items():
|
||||
|
@ -132,4 +134,4 @@ def run_pnginfo(image):
|
|||
message = "Nothing found in the image."
|
||||
info = f"<div><p>{message}<p></div>"
|
||||
|
||||
return '', '', info
|
||||
return '', geninfo, info
|
||||
|
|
88
modules/generation_parameters_copypaste.py
Normal file
88
modules/generation_parameters_copypaste.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
from collections import namedtuple
|
||||
import re
|
||||
import gradio as gr
|
||||
|
||||
re_param = re.compile(r"\s*([\w ]+):\s*([^,]+)(?:,|$)")
|
||||
re_imagesize = re.compile(r"^(\d+)x(\d+)$")
|
||||
|
||||
|
||||
def parse_generation_parameters(x: str):
|
||||
"""parses generation parameters string, the one you see in text field under the picture in UI:
|
||||
```
|
||||
girl with an artist's beret, determined, blue eyes, desert scene, computer monitors, heavy makeup, by Alphonse Mucha and Charlie Bowater, ((eyeshadow)), (coquettish), detailed, intricate
|
||||
Negative prompt: ugly, fat, obese, chubby, (((deformed))), [blurry], bad anatomy, disfigured, poorly drawn face, mutation, mutated, (extra_limb), (ugly), (poorly drawn hands), messy drawing
|
||||
Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model hash: 45dee52b
|
||||
```
|
||||
|
||||
returns a dict with field values
|
||||
"""
|
||||
|
||||
res = {}
|
||||
|
||||
prompt = ""
|
||||
negative_prompt = ""
|
||||
|
||||
done_with_prompt = False
|
||||
|
||||
*lines, lastline = x.strip().split("\n")
|
||||
for i, line in enumerate(lines):
|
||||
line = line.strip()
|
||||
if line.startswith("Negative prompt:"):
|
||||
done_with_prompt = True
|
||||
line = line[16:].strip()
|
||||
|
||||
if done_with_prompt:
|
||||
negative_prompt += line
|
||||
else:
|
||||
prompt += line
|
||||
|
||||
if len(prompt) > 0:
|
||||
res["Prompt"] = prompt
|
||||
|
||||
if len(negative_prompt) > 0:
|
||||
res["Negative prompt"] = negative_prompt
|
||||
|
||||
for k, v in re_param.findall(lastline):
|
||||
m = re_imagesize.match(v)
|
||||
if m is not None:
|
||||
res[k+"-1"] = m.group(1)
|
||||
res[k+"-2"] = m.group(2)
|
||||
else:
|
||||
res[k] = v
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def connect_paste(button, d, input_comp, js=None):
|
||||
items = []
|
||||
outputs = []
|
||||
|
||||
def paste_func(prompt):
|
||||
params = parse_generation_parameters(prompt)
|
||||
res = []
|
||||
|
||||
for key, output in zip(items, outputs):
|
||||
v = params.get(key, None)
|
||||
|
||||
if v is None:
|
||||
res.append(gr.update())
|
||||
else:
|
||||
try:
|
||||
valtype = type(output.value)
|
||||
val = valtype(v)
|
||||
res.append(gr.update(value=val))
|
||||
except Exception:
|
||||
res.append(gr.update())
|
||||
|
||||
return res
|
||||
|
||||
for k, v in d.items():
|
||||
items.append(k)
|
||||
outputs.append(v)
|
||||
|
||||
button.click(
|
||||
fn=paste_func,
|
||||
_js=js,
|
||||
inputs=[input_comp],
|
||||
outputs=outputs,
|
||||
)
|
111
modules/ui.py
111
modules/ui.py
|
@ -27,6 +27,7 @@ import modules.scripts
|
|||
import modules.gfpgan_model
|
||||
import modules.codeformer_model
|
||||
import modules.styles
|
||||
import modules.generation_parameters_copypaste
|
||||
|
||||
# this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI
|
||||
mimetypes.init()
|
||||
|
@ -57,6 +58,8 @@ css_hide_progressbar = """
|
|||
# Important that they exactly match script.js for tooltip to work.
|
||||
random_symbol = '\U0001f3b2\ufe0f' # 🎲️
|
||||
reuse_symbol = '\u267b\ufe0f' # ♻️
|
||||
art_symbol = '\U0001f3a8' # 🎨
|
||||
paste_symbol = '\u2199\ufe0f' # ↙
|
||||
|
||||
|
||||
def plaintext_to_html(text):
|
||||
|
@ -336,8 +339,10 @@ def create_toprow(is_img2img):
|
|||
with gr.Column(scale=80):
|
||||
with gr.Row():
|
||||
prompt = gr.Textbox(label="Prompt", elem_id="prompt", show_label=False, placeholder="Prompt", lines=2)
|
||||
roll = gr.Button('Roll', elem_id="roll", visible=len(shared.artist_db.artists) > 0)
|
||||
|
||||
with gr.Column(scale=1, elem_id="roll_col"):
|
||||
roll = gr.Button(value=art_symbol, elem_id="roll", visible=len(shared.artist_db.artists) > 0)
|
||||
paste = gr.Button(value=paste_symbol, elem_id="paste")
|
||||
|
||||
with gr.Column(scale=10, elem_id="style_pos_col"):
|
||||
prompt_style = gr.Dropdown(label="Style 1", elem_id=f"{id_part}_style_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())), visible=len(shared.prompt_styles.styles) > 1)
|
||||
|
@ -368,7 +373,7 @@ def create_toprow(is_img2img):
|
|||
prompt_style_apply = gr.Button('Apply style', elem_id="style_apply")
|
||||
save_style = gr.Button('Create style', elem_id="style_create")
|
||||
|
||||
return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, prompt_style_apply, save_style
|
||||
return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, prompt_style_apply, save_style, paste
|
||||
|
||||
|
||||
def setup_progressbar(progressbar, preview, id_part):
|
||||
|
@ -391,7 +396,7 @@ def setup_progressbar(progressbar, preview, id_part):
|
|||
|
||||
def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
||||
with gr.Blocks(analytics_enabled=False) as txt2img_interface:
|
||||
txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, txt2img_prompt_style_apply, txt2img_save_style = create_toprow(is_img2img=False)
|
||||
txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, txt2img_prompt_style_apply, txt2img_save_style, paste = create_toprow(is_img2img=False)
|
||||
dummy_component = gr.Label(visible=False)
|
||||
|
||||
with gr.Row(elem_id='txt2img_progress_row'):
|
||||
|
@ -517,8 +522,27 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
|||
]
|
||||
)
|
||||
|
||||
txt2img_paste_fields = {
|
||||
"Prompt": txt2img_prompt,
|
||||
"Negative prompt": txt2img_negative_prompt,
|
||||
"Steps": steps,
|
||||
"Sampler": sampler_index,
|
||||
"Face restoration": restore_faces,
|
||||
"CFG scale": cfg_scale,
|
||||
"Seed": seed,
|
||||
"Size-1": width,
|
||||
"Size-2": height,
|
||||
"Batch size": batch_size,
|
||||
"Variation seed": subseed,
|
||||
"Variation seed strength": subseed_strength,
|
||||
"Seed resize from-1": seed_resize_from_w,
|
||||
"Seed resize from-2": seed_resize_from_h,
|
||||
"Denoising strength": denoising_strength,
|
||||
}
|
||||
modules.generation_parameters_copypaste.connect_paste(paste, txt2img_paste_fields, txt2img_prompt)
|
||||
|
||||
with gr.Blocks(analytics_enabled=False) as img2img_interface:
|
||||
img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_prompt_style_apply, img2img_save_style = create_toprow(is_img2img=True)
|
||||
img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_prompt_style_apply, img2img_save_style, paste = create_toprow(is_img2img=True)
|
||||
|
||||
with gr.Row(elem_id='img2img_progress_row'):
|
||||
with gr.Column(scale=1):
|
||||
|
@ -533,10 +557,10 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
|||
with gr.Column(variant='panel'):
|
||||
|
||||
with gr.Tabs(elem_id="mode_img2img") as tabs_img2img_mode:
|
||||
with gr.TabItem('img2img'):
|
||||
with gr.TabItem('img2img', id='img2img'):
|
||||
init_img = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil")
|
||||
|
||||
with gr.TabItem('Inpaint'):
|
||||
with gr.TabItem('Inpaint', id='inpaint'):
|
||||
init_img_with_mask = gr.Image(label="Image for inpainting with mask", show_label=False, elem_id="img2maskimg", source="upload", interactive=True, type="pil", tool="sketch", image_mode="RGBA")
|
||||
|
||||
init_img_inpaint = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil", visible=False)
|
||||
|
@ -554,7 +578,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
|||
inpaint_full_res = gr.Checkbox(label='Inpaint at full resolution', value=False)
|
||||
inpaint_full_res_padding = gr.Slider(label='Inpaint at full resolution padding, pixels', minimum=0, maximum=256, step=4, value=32)
|
||||
|
||||
with gr.TabItem('Batch img2img'):
|
||||
with gr.TabItem('Batch img2img', id='batch'):
|
||||
gr.HTML("<p class=\"text-gray-500\">Process images in a directory on the same machine where the server is running.</p>")
|
||||
img2img_batch_input_dir = gr.Textbox(label="Input directory")
|
||||
img2img_batch_output_dir = gr.Textbox(label="Output directory")
|
||||
|
@ -717,12 +741,31 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
|||
outputs=[prompt, negative_prompt, style1, style2],
|
||||
)
|
||||
|
||||
img2img_paste_fields = {
|
||||
"Prompt": img2img_prompt,
|
||||
"Negative prompt": img2img_negative_prompt,
|
||||
"Steps": steps,
|
||||
"Sampler": sampler_index,
|
||||
"Face restoration": restore_faces,
|
||||
"CFG scale": cfg_scale,
|
||||
"Seed": seed,
|
||||
"Size-1": width,
|
||||
"Size-2": height,
|
||||
"Batch size": batch_size,
|
||||
"Variation seed": subseed,
|
||||
"Variation seed strength": subseed_strength,
|
||||
"Seed resize from-1": seed_resize_from_w,
|
||||
"Seed resize from-2": seed_resize_from_h,
|
||||
"Denoising strength": denoising_strength,
|
||||
}
|
||||
modules.generation_parameters_copypaste.connect_paste(paste, img2img_paste_fields, img2img_prompt)
|
||||
|
||||
with gr.Blocks(analytics_enabled=False) as extras_interface:
|
||||
with gr.Row().style(equal_height=False):
|
||||
with gr.Column(variant='panel'):
|
||||
with gr.Tabs(elem_id="mode_extras"):
|
||||
with gr.TabItem('Single Image'):
|
||||
image = gr.Image(label="Source", source="upload", interactive=True, type="pil")
|
||||
extras_image = gr.Image(label="Source", source="upload", interactive=True, type="pil")
|
||||
|
||||
with gr.TabItem('Batch Process'):
|
||||
image_batch = gr.File(label="Batch Process", file_count="multiple", interactive=True, type="file")
|
||||
|
@ -757,7 +800,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
|||
_js="get_extras_tab_index",
|
||||
inputs=[
|
||||
dummy_component,
|
||||
image,
|
||||
extras_image,
|
||||
image_batch,
|
||||
gfpgan_visibility,
|
||||
codeformer_visibility,
|
||||
|
@ -788,20 +831,25 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
|||
outputs=[init_img_with_mask],
|
||||
)
|
||||
|
||||
pnginfo_interface = gr.Interface(
|
||||
wrap_gradio_call(run_pnginfo),
|
||||
inputs=[
|
||||
gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil"),
|
||||
],
|
||||
outputs=[
|
||||
gr.HTML(),
|
||||
gr.HTML(),
|
||||
gr.HTML(),
|
||||
],
|
||||
allow_flagging="never",
|
||||
analytics_enabled=False,
|
||||
live=True,
|
||||
)
|
||||
with gr.Blocks(analytics_enabled=False) as pnginfo_interface:
|
||||
with gr.Row().style(equal_height=False):
|
||||
with gr.Column(variant='panel'):
|
||||
image = gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil")
|
||||
|
||||
with gr.Column(variant='panel'):
|
||||
html = gr.HTML()
|
||||
generation_info = gr.Textbox(visible=False)
|
||||
html2 = gr.HTML()
|
||||
|
||||
with gr.Row():
|
||||
pnginfo_send_to_txt2img = gr.Button('Send to txt2img')
|
||||
pnginfo_send_to_img2img = gr.Button('Send to img2img')
|
||||
|
||||
image.change(
|
||||
fn=wrap_gradio_call(run_pnginfo),
|
||||
inputs=[image],
|
||||
outputs=[html, generation_info, html2],
|
||||
)
|
||||
|
||||
def create_setting_component(key):
|
||||
def fun():
|
||||
|
@ -936,29 +984,29 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
|||
)
|
||||
|
||||
send_to_img2img.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
fn=lambda x: (image_from_url_text(x)),
|
||||
_js="extract_image_from_gallery_img2img",
|
||||
inputs=[txt2img_gallery],
|
||||
outputs=[init_img],
|
||||
)
|
||||
|
||||
send_to_inpaint.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery_img2img",
|
||||
fn=lambda x: (image_from_url_text(x)),
|
||||
_js="extract_image_from_gallery_inpaint",
|
||||
inputs=[txt2img_gallery],
|
||||
outputs=[init_img_with_mask],
|
||||
)
|
||||
|
||||
img2img_send_to_img2img.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery",
|
||||
_js="extract_image_from_gallery_img2img",
|
||||
inputs=[img2img_gallery],
|
||||
outputs=[init_img],
|
||||
)
|
||||
|
||||
img2img_send_to_inpaint.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery",
|
||||
_js="extract_image_from_gallery_inpaint",
|
||||
inputs=[img2img_gallery],
|
||||
outputs=[init_img_with_mask],
|
||||
)
|
||||
|
@ -967,16 +1015,19 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo):
|
|||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery_extras",
|
||||
inputs=[txt2img_gallery],
|
||||
outputs=[image],
|
||||
outputs=[extras_image],
|
||||
)
|
||||
|
||||
img2img_send_to_extras.click(
|
||||
fn=lambda x: image_from_url_text(x),
|
||||
_js="extract_image_from_gallery_extras",
|
||||
inputs=[img2img_gallery],
|
||||
outputs=[image],
|
||||
outputs=[extras_image],
|
||||
)
|
||||
|
||||
modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_txt2img, txt2img_paste_fields, generation_info, 'switch_to_txt2img')
|
||||
modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_img2img, img2img_paste_fields, generation_info, 'switch_to_img2img_img2img')
|
||||
|
||||
ui_config_file = cmd_opts.ui_config_file
|
||||
ui_settings = {}
|
||||
settings_count = len(ui_settings)
|
||||
|
|
19
style.css
19
style.css
|
@ -74,10 +74,21 @@
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
#roll{
|
||||
min-width: 1em;
|
||||
max-width: 4em;
|
||||
margin: 0.5em;
|
||||
#roll_col{
|
||||
min-width: unset !important;
|
||||
flex-grow: 0 !important;
|
||||
padding: 0.4em 0;
|
||||
}
|
||||
|
||||
#roll, #paste{
|
||||
min-width: 2em;
|
||||
min-height: 2em;
|
||||
max-width: 2em;
|
||||
max-height: 2em;
|
||||
flex-grow: 0;
|
||||
padding-left: 0.25em;
|
||||
padding-right: 0.25em;
|
||||
margin: 0.1em 0;
|
||||
}
|
||||
|
||||
#style_apply, #style_create, #interrogate{
|
||||
|
|
Loading…
Reference in a new issue