File size: 5,020 Bytes
704a244 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
"""
Attempting to map Gradio UI elements present in scripts to allow
converting to pyQt elements on the plugin side.
"""
import logging
from typing import List, Sequence, Tuple
import gradio as gr
import modules
from .config import LOGGER_NAME
log = logging.getLogger(LOGGER_NAME)
def inspect_ui(script: modules.scripts.Script, is_img2img: bool):
"""Get metadata about accepted arguments by inspecting GUI. Needs Gradio Blocks context."""
elems = script.ui(is_img2img)
metadata = []
if not isinstance(elems, Sequence):
return metadata
for elem in elems:
data = {
"type": "None",
"label": elem.label,
"val": elem.value,
"is_index": False,
}
if isinstance(elem, gr.HTML):
data.update(val="")
elif isinstance(elem, gr.Markdown):
data.update(val="")
elif isinstance(elem, gr.Slider):
data.update(
type="range",
min=elem.minimum,
max=elem.maximum,
step=elem.step,
)
elif isinstance(elem, gr.Radio):
data.update(
type="combo",
is_index=elem.type == "index",
opts=elem.choices,
)
elif isinstance(elem, gr.Dropdown):
data.update(
type="combo",
is_index=elem.type == "index",
opts=elem.choices,
)
elif isinstance(elem, gr.Textbox):
data.update(
type="text",
)
elif isinstance(elem, gr.Checkbox):
data.update(
type="checkbox",
)
elif isinstance(elem, gr.CheckboxGroup):
data.update(
type="multiselect",
is_index=elem.type == "index",
opts=elem.choices,
)
elif isinstance(elem, gr.File):
data.update(val="") # unsupported
else:
data.update(val="") # unsupported
metadata.append(data)
return metadata
img2img_script_meta = None
txt2img_script_meta = None
def get_scripts_metadata(is_img2img: bool):
"""Get metadata about accepted arguments for scripts."""
# NOTE: inspect_ui is quite slow, so cache this
global txt2img_script_meta, img2img_script_meta
if is_img2img:
runner = modules.scripts.scripts_img2img
else:
runner = modules.scripts.scripts_txt2img
metadata = {"None": []}
if (
is_img2img
and img2img_script_meta
and len(img2img_script_meta) - 1 == len(runner.titles)
):
return img2img_script_meta
elif txt2img_script_meta and len(txt2img_script_meta) - 1 == len(runner.titles):
return txt2img_script_meta
with gr.Blocks(visible=False, analytics_enabled=False):
for name, script in zip(runner.titles, runner.selectable_scripts):
metadata[name] = inspect_ui(script, is_img2img)
if is_img2img:
img2img_script_meta = metadata
else:
txt2img_script_meta = metadata
return metadata
def get_script_info(
script_name: str, is_img2img: bool
) -> Tuple[int, modules.scripts.Script, List[dict]]:
"""Get index of script, script instance and argument metadata by name.
Args:
script_name (str): Exact name of script.
is_img2img (bool): Whether the script is for img2img or txt2img.
Raises:
KeyError: Script cannot be found.
Returns:
Tuple[int, Script, List[dict]]: Index of script, script itself and arguments metadata.
"""
if is_img2img:
runner = modules.scripts.scripts_img2img
else:
runner = modules.scripts.scripts_txt2img
# in API, index 0 means no script, scripts are indexed from 1 onwards
names = ["None"] + runner.titles
if script_name == "None":
return 0, None, []
for i, n in enumerate(names):
if n == script_name:
script = runner.selectable_scripts[i - 1]
return i, script, get_scripts_metadata(is_img2img)[n]
raise KeyError(f"script not found for type {type}: {script_name}")
def process_script_args(
script_ind: int, script: modules.scripts.Script, meta: List[dict], args: list
) -> list:
"""Get the position arguments required."""
if script is None:
return [0] # 0th element selects which script to use. 0 is None.
# convert strings back to indexes
for i, (o, arg) in enumerate(zip(meta, args)):
if o["is_index"]:
if isinstance(arg, list):
args[i] = [o["opts"].index(v) for v in arg]
else:
args[i] = o["opts"].index(arg)
log.info(
f"Script selected: {script.filename}, Args Range: [{script.args_from}:{script.args_to}]"
)
# pad the args like the internal API requires...
args = [script_ind] + [0] * (script.args_from - 1) + args
log.info(f"Script args:\n{args}")
return args
|