|
import ast |
|
import importlib |
|
import os |
|
import subprocess |
|
import sys |
|
|
|
import gradio as gr |
|
|
|
import scripts.shared as shared |
|
from scripts.shared import ROOT_DIR |
|
|
|
python = sys.executable |
|
|
|
|
|
def path_to_module(filepath): |
|
return ( |
|
os.path.relpath(filepath, ROOT_DIR).replace(os.path.sep, ".").replace(".py", "") |
|
) |
|
|
|
|
|
def which(program): |
|
def is_exe(fpath): |
|
return os.path.isfile(fpath) and os.access(fpath, os.X_OK) |
|
|
|
fpath, _ = os.path.split(program) |
|
if fpath: |
|
if is_exe(program): |
|
return program |
|
else: |
|
for path in os.environ["PATH"].split(os.pathsep): |
|
path = path.strip('"') |
|
exe_file = os.path.join(path, program) |
|
if is_exe(exe_file): |
|
return exe_file |
|
|
|
return None |
|
|
|
|
|
def literal_eval(v, module=None): |
|
if v == "str": |
|
return str |
|
elif v == "int": |
|
return int |
|
elif v == "float": |
|
return float |
|
elif v == list: |
|
return list |
|
else: |
|
if module: |
|
try: |
|
m = importlib.import_module(module) |
|
if hasattr(m, v): |
|
return getattr(m, v) |
|
except: |
|
() |
|
|
|
return ast.literal_eval(v) |
|
|
|
|
|
def compile_arg_parser(txt, module_path=None): |
|
in_parser = False |
|
parsers = {} |
|
args = [] |
|
arg = "" |
|
in_list = False |
|
in_str = None |
|
|
|
def compile(arg): |
|
arg = arg.strip() |
|
matches = arg.split("=") |
|
|
|
if len(matches) > 1: |
|
k = "".join(matches[:1]) |
|
v = literal_eval("".join(matches[1:]), module_path) |
|
return (k, v) |
|
else: |
|
return literal_eval(arg, module_path) |
|
|
|
for line in txt.split("\n"): |
|
line = line.split("#")[0] |
|
|
|
if "parser.add_argument(" in line: |
|
in_parser = True |
|
line = line.replace("parser.add_argument(", "") |
|
|
|
if not in_parser: |
|
continue |
|
|
|
for c in line: |
|
|
|
if in_str is None and c == ")": |
|
if arg.strip(): |
|
args.append(compile(arg)) |
|
in_parser = False |
|
[dest, *others] = args |
|
parsers[dest] = {"dest": dest.replace("--", ""), **dict(others)} |
|
arg = "" |
|
args = [] |
|
break |
|
|
|
if c == "[": |
|
in_list = True |
|
elif c == "]": |
|
in_list = False |
|
if c == '"' or c == "'": |
|
if in_str is not None and in_str == c: |
|
in_str = None |
|
elif in_str is None: |
|
in_str = c |
|
|
|
if c == "," and not in_list and in_str is None: |
|
args.append(compile(arg)) |
|
arg = "" |
|
continue |
|
|
|
arg += c |
|
|
|
if arg.strip(): |
|
args.append(compile(arg)) |
|
return parsers |
|
|
|
|
|
def load_args_template(*filename): |
|
repo_dir = os.path.join(ROOT_DIR, "kohya_ss") |
|
filepath = os.path.join(repo_dir, *filename) |
|
with open(filepath, mode="r", encoding="utf-8_sig") as f: |
|
lines = f.readlines() |
|
add = False |
|
txt = "" |
|
for line in lines: |
|
if add == True: |
|
txt += line |
|
if "def setup_parser()" in line: |
|
add = True |
|
continue |
|
return compile_arg_parser(txt, path_to_module(filepath)), filepath |
|
|
|
|
|
def check_key(d, k): |
|
return k in d and d[k] is not None |
|
|
|
|
|
def get_arg_type(d): |
|
if check_key(d, "choices"): |
|
return list |
|
if check_key(d, "type"): |
|
return d["type"] |
|
if check_key(d, "action") and ( |
|
d["action"] == "store_true" or d["action"] == "store_false" |
|
): |
|
return bool |
|
if check_key(d, "const") and type(d["const"]) == bool: |
|
return bool |
|
return str |
|
|
|
|
|
def options_to_gradio(options, out, overrides={}): |
|
for _, item in options.items(): |
|
item = item.__dict__ if hasattr(item, "__dict__") else item |
|
key = item["dest"] |
|
if key == "help": |
|
continue |
|
override = overrides[key] if key in overrides else {} |
|
component = None |
|
|
|
help = item["help"] if "help" in item else "" |
|
id = f"kohya_sd_webui__{shared.current_tab.replace('.', '_')}_{key}" |
|
type = override["type"] if "type" in override else get_arg_type(item) |
|
if type == list: |
|
choices = [ |
|
c if c is not None else "None" |
|
for c in ( |
|
override["choices"] if "choices" in override else item["choices"] |
|
) |
|
] |
|
component = gr.Radio( |
|
choices=choices, |
|
value=item["default"] if check_key(item, "default") else choices[0], |
|
label=key, |
|
elem_id=id, |
|
interactive=True, |
|
) |
|
elif type == bool: |
|
component = gr.Checkbox( |
|
value=item["default"] if check_key(item, "default") else False, |
|
label=key, |
|
elem_id=id, |
|
interactive=True, |
|
) |
|
else: |
|
component = gr.Textbox( |
|
value=item["default"] if check_key(item, "default") else "", |
|
label=key, |
|
elem_id=id, |
|
interactive=True, |
|
).style() |
|
|
|
shared.help_title_map[id] = help |
|
out[key] = component |
|
|
|
|
|
def args_to_gradio(args, out, overrides={}): |
|
options_to_gradio(args.__dict__["_option_string_actions"], out, overrides) |
|
|
|
|
|
def gradio_to_args(arguments, options, args, strarg=False): |
|
def find_arg(key): |
|
for k, arg in arguments.items(): |
|
arg = arg.__dict__ if hasattr(arg, "__dict__") else arg |
|
if arg["dest"] == key: |
|
return k, arg |
|
return None, None |
|
|
|
def get_value(key): |
|
item = args[options[key]] |
|
raw_key, arg = find_arg(key) |
|
arg_type = get_arg_type(arg) |
|
multiple = "nargs" in arg and arg["nargs"] == "*" |
|
|
|
def set_type(x): |
|
if x is None or x == "None": |
|
return None |
|
elif arg_type is None: |
|
return x |
|
elif arg_type == list: |
|
return x |
|
return arg_type(x) |
|
|
|
if multiple and item is None or item == "": |
|
return raw_key, None |
|
|
|
return raw_key, ( |
|
[set_type(x) for x in item.split(" ")] if multiple else set_type(item) |
|
) |
|
|
|
if strarg: |
|
main = [] |
|
optional = {} |
|
|
|
for k in options: |
|
key, v = get_value(k) |
|
if key.startswith("--"): |
|
key = k.replace("--", "") |
|
optional[key] = v |
|
else: |
|
main.append(v) |
|
|
|
main = [x for x in main if x is not None] |
|
|
|
return main, optional |
|
else: |
|
result = {} |
|
for k in options: |
|
_, v = get_value(k) |
|
result[k] = v |
|
return result |
|
|
|
|
|
def make_args(d): |
|
arguments = [] |
|
for k, v in d.items(): |
|
if type(v) == bool: |
|
arguments.append(f"--{k}" if v else "") |
|
elif type(v) == list and len(v) > 0: |
|
arguments.extend([f"--{k}", *v]) |
|
elif type(v) == str and v: |
|
arguments.extend([f"--{k}", f"{v}"]) |
|
elif v: |
|
arguments.extend([f"--{k}", f"{v}"]) |
|
return arguments |
|
|
|
|
|
def run_python(script, templates, options, args): |
|
main, optional = gradio_to_args(templates, options, args, strarg=True) |
|
args = [x for x in [*main, *make_args(optional)] if x] |
|
proc_args = [python, "-u", script, *args] |
|
print("Start process: ", " ".join(proc_args)) |
|
|
|
ps = subprocess.Popen( |
|
proc_args, |
|
stdout=subprocess.PIPE, |
|
stderr=subprocess.STDOUT, |
|
cwd=os.path.join(ROOT_DIR, "kohya_ss"), |
|
) |
|
return ps |
|
|