| 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 | |