update for commandline args for btch prompts to parse string properly

This commit is contained in:
AUTOMATIC 2022-10-15 12:00:31 +03:00
parent 58e62312c3
commit 7d6042b908

View File

@ -1,7 +1,9 @@
import copy
import math import math
import os import os
import sys import sys
import traceback import traceback
import shlex
import modules.scripts as scripts import modules.scripts as scripts
import gradio as gr import gradio as gr
@ -10,36 +12,23 @@ from modules.processing import Processed, process_images
from PIL import Image from PIL import Image
from modules.shared import opts, cmd_opts, state from modules.shared import opts, cmd_opts, state
class Script(scripts.Script):
def title(self):
return "Prompts from file or textbox"
def ui(self, is_img2img): def process_string_tag(tag):
# This checkbox would look nicer as two tabs, but there are two problems: return tag
# 1) There is a bug in Gradio 3.3 that prevents visibility from working on Tabs
# 2) Even with Gradio 3.3.1, returning a control (like Tabs) that can't be used as input
# causes a AttributeError: 'Tabs' object has no attribute 'preprocess' assert,
# due to the way Script assumes all controls returned can be used as inputs.
# Therefore, there's no good way to use grouping components right now,
# so we will use a checkbox! :)
checkbox_txt = gr.Checkbox(label="Show Textbox", value=False)
file = gr.File(label="File with inputs", type='bytes')
prompt_txt = gr.TextArea(label="Prompts")
checkbox_txt.change(fn=lambda x: [gr.File.update(visible = not x), gr.TextArea.update(visible = x)], inputs=[checkbox_txt], outputs=[file, prompt_txt])
return [checkbox_txt, file, prompt_txt]
def process_string_tag(self, tag):
return tag[1:-2]
def process_int_tag(self, tag): def process_int_tag(tag):
return int(tag) return int(tag)
def process_float_tag(self, tag):
def process_float_tag(tag):
return float(tag) return float(tag)
def process_boolean_tag(self, tag):
def process_boolean_tag(tag):
return True if (tag == "true") else False return True if (tag == "true") else False
prompt_tags = { prompt_tags = {
"sd_model": None, "sd_model": None,
"outpath_samples": process_string_tag, "outpath_samples": process_string_tag,
@ -66,49 +55,96 @@ class Script(scripts.Script):
"do_not_save_grid": process_boolean_tag "do_not_save_grid": process_boolean_tag
} }
def cmdargs(line):
args = shlex.split(line)
pos = 0
res = {}
while pos < len(args):
arg = args[pos]
assert arg.startswith("--"), f'must start with "--": {arg}'
tag = arg[2:]
func = prompt_tags.get(tag, None)
assert func, f'unknown commandline option: {arg}'
assert pos+1 < len(args), f'missing argument for command line option {arg}'
val = args[pos+1]
res[tag] = func(val)
pos += 2
return res
class Script(scripts.Script):
def title(self):
return "Prompts from file or textbox"
def ui(self, is_img2img):
# This checkbox would look nicer as two tabs, but there are two problems:
# 1) There is a bug in Gradio 3.3 that prevents visibility from working on Tabs
# 2) Even with Gradio 3.3.1, returning a control (like Tabs) that can't be used as input
# causes a AttributeError: 'Tabs' object has no attribute 'preprocess' assert,
# due to the way Script assumes all controls returned can be used as inputs.
# Therefore, there's no good way to use grouping components right now,
# so we will use a checkbox! :)
checkbox_txt = gr.Checkbox(label="Show Textbox", value=False)
file = gr.File(label="File with inputs", type='bytes')
prompt_txt = gr.TextArea(label="Prompts")
checkbox_txt.change(fn=lambda x: [gr.File.update(visible = not x), gr.TextArea.update(visible = x)], inputs=[checkbox_txt], outputs=[file, prompt_txt])
return [checkbox_txt, file, prompt_txt]
def on_show(self, checkbox_txt, file, prompt_txt): def on_show(self, checkbox_txt, file, prompt_txt):
return [ gr.Checkbox.update(visible = True), gr.File.update(visible = not checkbox_txt), gr.TextArea.update(visible = checkbox_txt) ] return [ gr.Checkbox.update(visible = True), gr.File.update(visible = not checkbox_txt), gr.TextArea.update(visible = checkbox_txt) ]
def run(self, p, checkbox_txt, data: bytes, prompt_txt: str): def run(self, p, checkbox_txt, data: bytes, prompt_txt: str):
if (checkbox_txt): if checkbox_txt:
lines = [x.strip() for x in prompt_txt.splitlines()] lines = [x.strip() for x in prompt_txt.splitlines()]
else: else:
lines = [x.strip() for x in data.decode('utf8', errors='ignore').split("\n")] lines = [x.strip() for x in data.decode('utf8', errors='ignore').split("\n")]
lines = [x for x in lines if len(x) > 0] lines = [x for x in lines if len(x) > 0]
img_count = len(lines) * p.n_iter
batch_count = math.ceil(img_count / p.batch_size)
loop_count = math.ceil(batch_count / p.n_iter)
# These numbers no longer accurately reflect the total images and number of batches
print(f"Will process {img_count} images in {batch_count} batches.")
p.do_not_save_grid = True p.do_not_save_grid = True
state.job_count = batch_count job_count = 0
jobs = []
for line in lines:
if "--" in line:
try:
args = cmdargs(line)
except Exception:
print(f"Error parsing line [line] as commandline:", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr)
args = {"prompt": line}
else:
args = {"prompt": line}
n_iter = args.get("n_iter", 1)
if n_iter != 1:
job_count += n_iter
else:
job_count += 1
jobs.append(args)
print(f"Will process {len(lines)} lines in {job_count} jobs.")
state.job_count = job_count
images = [] images = []
for loop_no in range(loop_count): for n, args in enumerate(jobs):
state.job = f"{loop_no + 1} out of {loop_count}" state.job = f"{state.job_no + 1} out of {state.job_count}"
# The following line may need revising to remove batch_size references
current_line = lines[loop_no*p.batch_size:(loop_no+1)*p.batch_size] * p.n_iter
# If the current line has no tags, parse the whole line as a prompt, else parse each tag copy_p = copy.copy(p)
if(current_line[0][:2] != "--"): for k, v in args.items():
p.prompt = current_line setattr(copy_p, k, v)
else:
tokenized_line = current_line[0].split("--")
for tag in tokenized_line: proc = process_images(copy_p)
tag_split = tag.split(" ", 1)
if(tag_split[0] != ''):
value_func = self.prompt_tags.get(tag_split[0], None)
if(value_func != None):
value = value_func(self, tag_split[1])
setattr(p, tag_split[0], value)
else:
print(f"Unknown option \"{tag_split}\"")
proc = process_images(p)
images += proc.images images += proc.images
return Processed(p, images, p.seed, "") return Processed(p, images, p.seed, "")