Transformers
Inference Endpoints
vorstcavry commited on
Commit
4cc80ac
1 Parent(s): 57ad0b4

Upload 3 files

Browse files
Files changed (3) hide show
  1. extra_options_section.py +48 -0
  2. prompt-bracket-checker.js +42 -0
  3. scripts.py +680 -0
extra_options_section.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from modules import scripts, shared, ui_components, ui_settings
3
+ from modules.ui_components import FormColumn
4
+
5
+
6
+ class ExtraOptionsSection(scripts.Script):
7
+ section = "extra_options"
8
+
9
+ def __init__(self):
10
+ self.comps = None
11
+ self.setting_names = None
12
+
13
+ def title(self):
14
+ return "Extra options"
15
+
16
+ def show(self, is_img2img):
17
+ return scripts.AlwaysVisible
18
+
19
+ def ui(self, is_img2img):
20
+ self.comps = []
21
+ self.setting_names = []
22
+
23
+ with gr.Blocks() as interface:
24
+ with gr.Accordion("Options", open=False) if shared.opts.extra_options_accordion and shared.opts.extra_options else gr.Group(), gr.Row():
25
+ for setting_name in shared.opts.extra_options:
26
+ with FormColumn():
27
+ comp = ui_settings.create_setting_component(setting_name)
28
+
29
+ self.comps.append(comp)
30
+ self.setting_names.append(setting_name)
31
+
32
+ def get_settings_values():
33
+ return [ui_settings.get_value_for_setting(key) for key in self.setting_names]
34
+
35
+ interface.load(fn=get_settings_values, inputs=[], outputs=self.comps, queue=False, show_progress=False)
36
+
37
+ return self.comps
38
+
39
+ def before_process(self, p, *args):
40
+ for name, value in zip(self.setting_names, args):
41
+ if name not in p.override_settings:
42
+ p.override_settings[name] = value
43
+
44
+
45
+ shared.options_templates.update(shared.options_section(('ui', "User interface"), {
46
+ "extra_options": shared.OptionInfo([], "Options in main UI", ui_components.DropdownMulti, lambda: {"choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that also appear in txt2img/img2img interfaces").needs_restart(),
47
+ "extra_options_accordion": shared.OptionInfo(False, "Place options in main UI into an accordion")
48
+ }))
prompt-bracket-checker.js ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Stable Diffusion WebUI - Bracket checker
2
+ // By Hingashi no Florin/Bwin4L & @akx
3
+ // Counts open and closed brackets (round, square, curly) in the prompt and negative prompt text boxes in the txt2img and img2img tabs.
4
+ // If there's a mismatch, the keyword counter turns red and if you hover on it, a tooltip tells you what's wrong.
5
+
6
+ function checkBrackets(textArea, counterElt) {
7
+ var counts = {};
8
+ (textArea.value.match(/[(){}[\]]/g) || []).forEach(bracket => {
9
+ counts[bracket] = (counts[bracket] || 0) + 1;
10
+ });
11
+ var errors = [];
12
+
13
+ function checkPair(open, close, kind) {
14
+ if (counts[open] !== counts[close]) {
15
+ errors.push(
16
+ `${open}...${close} - Detected ${counts[open] || 0} opening and ${counts[close] || 0} closing ${kind}.`
17
+ );
18
+ }
19
+ }
20
+
21
+ checkPair('(', ')', 'round brackets');
22
+ checkPair('[', ']', 'square brackets');
23
+ checkPair('{', '}', 'curly brackets');
24
+ counterElt.title = errors.join('\n');
25
+ counterElt.classList.toggle('error', errors.length !== 0);
26
+ }
27
+
28
+ function setupBracketChecking(id_prompt, id_counter) {
29
+ var textarea = gradioApp().querySelector("#" + id_prompt + " > label > textarea");
30
+ var counter = gradioApp().getElementById(id_counter);
31
+
32
+ if (textarea && counter) {
33
+ textarea.addEventListener("input", () => checkBrackets(textarea, counter));
34
+ }
35
+ }
36
+
37
+ onUiLoaded(function() {
38
+ setupBracketChecking('txt2img_prompt', 'txt2img_token_counter');
39
+ setupBracketChecking('txt2img_neg_prompt', 'txt2img_negative_token_counter');
40
+ setupBracketChecking('img2img_prompt', 'img2img_token_counter');
41
+ setupBracketChecking('img2img_neg_prompt', 'img2img_negative_token_counter');
42
+ });
scripts.py ADDED
@@ -0,0 +1,680 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import sys
4
+ import inspect
5
+ from collections import namedtuple
6
+
7
+ import gradio as gr
8
+
9
+ from modules import shared, paths, script_callbacks, extensions, script_loading, scripts_postprocessing, errors, timer
10
+
11
+ AlwaysVisible = object()
12
+
13
+
14
+ class PostprocessImageArgs:
15
+ def __init__(self, image):
16
+ self.image = image
17
+
18
+
19
+ class PostprocessBatchListArgs:
20
+ def __init__(self, images):
21
+ self.images = images
22
+
23
+
24
+ class Script:
25
+ name = None
26
+ """script's internal name derived from title"""
27
+
28
+ section = None
29
+ """name of UI section that the script's controls will be placed into"""
30
+
31
+ filename = None
32
+ args_from = None
33
+ args_to = None
34
+ alwayson = False
35
+
36
+ is_txt2img = False
37
+ is_img2img = False
38
+
39
+ group = None
40
+ """A gr.Group component that has all script's UI inside it"""
41
+
42
+ infotext_fields = None
43
+ """if set in ui(), this is a list of pairs of gradio component + text; the text will be used when
44
+ parsing infotext to set the value for the component; see ui.py's txt2img_paste_fields for an example
45
+ """
46
+
47
+ paste_field_names = None
48
+ """if set in ui(), this is a list of names of infotext fields; the fields will be sent through the
49
+ various "Send to <X>" buttons when clicked
50
+ """
51
+
52
+ api_info = None
53
+ """Generated value of type modules.api.models.ScriptInfo with information about the script for API"""
54
+
55
+ def title(self):
56
+ """this function should return the title of the script. This is what will be displayed in the dropdown menu."""
57
+
58
+ raise NotImplementedError()
59
+
60
+ def ui(self, is_img2img):
61
+ """this function should create gradio UI elements. See https://gradio.app/docs/#components
62
+ The return value should be an array of all components that are used in processing.
63
+ Values of those returned components will be passed to run() and process() functions.
64
+ """
65
+
66
+ pass
67
+
68
+ def show(self, is_img2img):
69
+ """
70
+ is_img2img is True if this function is called for the img2img interface, and Fasle otherwise
71
+
72
+ This function should return:
73
+ - False if the script should not be shown in UI at all
74
+ - True if the script should be shown in UI if it's selected in the scripts dropdown
75
+ - script.AlwaysVisible if the script should be shown in UI at all times
76
+ """
77
+
78
+ return True
79
+
80
+ def run(self, p, *args):
81
+ """
82
+ This function is called if the script has been selected in the script dropdown.
83
+ It must do all processing and return the Processed object with results, same as
84
+ one returned by processing.process_images.
85
+
86
+ Usually the processing is done by calling the processing.process_images function.
87
+
88
+ args contains all values returned by components from ui()
89
+ """
90
+
91
+ pass
92
+
93
+ def before_process(self, p, *args):
94
+ """
95
+ This function is called very early before processing begins for AlwaysVisible scripts.
96
+ You can modify the processing object (p) here, inject hooks, etc.
97
+ args contains all values returned by components from ui()
98
+ """
99
+
100
+ pass
101
+
102
+ def process(self, p, *args):
103
+ """
104
+ This function is called before processing begins for AlwaysVisible scripts.
105
+ You can modify the processing object (p) here, inject hooks, etc.
106
+ args contains all values returned by components from ui()
107
+ """
108
+
109
+ pass
110
+
111
+ def before_process_batch(self, p, *args, **kwargs):
112
+ """
113
+ Called before extra networks are parsed from the prompt, so you can add
114
+ new extra network keywords to the prompt with this callback.
115
+
116
+ **kwargs will have those items:
117
+ - batch_number - index of current batch, from 0 to number of batches-1
118
+ - prompts - list of prompts for current batch; you can change contents of this list but changing the number of entries will likely break things
119
+ - seeds - list of seeds for current batch
120
+ - subseeds - list of subseeds for current batch
121
+ """
122
+
123
+ pass
124
+
125
+ def after_extra_networks_activate(self, p, *args, **kwargs):
126
+ """
127
+ Called after extra networks activation, before conds calculation
128
+ allow modification of the network after extra networks activation been applied
129
+ won't be call if p.disable_extra_networks
130
+
131
+ **kwargs will have those items:
132
+ - batch_number - index of current batch, from 0 to number of batches-1
133
+ - prompts - list of prompts for current batch; you can change contents of this list but changing the number of entries will likely break things
134
+ - seeds - list of seeds for current batch
135
+ - subseeds - list of subseeds for current batch
136
+ - extra_network_data - list of ExtraNetworkParams for current stage
137
+ """
138
+ pass
139
+
140
+ def process_batch(self, p, *args, **kwargs):
141
+ """
142
+ Same as process(), but called for every batch.
143
+
144
+ **kwargs will have those items:
145
+ - batch_number - index of current batch, from 0 to number of batches-1
146
+ - prompts - list of prompts for current batch; you can change contents of this list but changing the number of entries will likely break things
147
+ - seeds - list of seeds for current batch
148
+ - subseeds - list of subseeds for current batch
149
+ """
150
+
151
+ pass
152
+
153
+ def postprocess_batch(self, p, *args, **kwargs):
154
+ """
155
+ Same as process_batch(), but called for every batch after it has been generated.
156
+
157
+ **kwargs will have same items as process_batch, and also:
158
+ - batch_number - index of current batch, from 0 to number of batches-1
159
+ - images - torch tensor with all generated images, with values ranging from 0 to 1;
160
+ """
161
+
162
+ pass
163
+
164
+ def postprocess_batch_list(self, p, pp: PostprocessBatchListArgs, *args, **kwargs):
165
+ """
166
+ Same as postprocess_batch(), but receives batch images as a list of 3D tensors instead of a 4D tensor.
167
+ This is useful when you want to update the entire batch instead of individual images.
168
+
169
+ You can modify the postprocessing object (pp) to update the images in the batch, remove images, add images, etc.
170
+ If the number of images is different from the batch size when returning,
171
+ then the script has the responsibility to also update the following attributes in the processing object (p):
172
+ - p.prompts
173
+ - p.negative_prompts
174
+ - p.seeds
175
+ - p.subseeds
176
+
177
+ **kwargs will have same items as process_batch, and also:
178
+ - batch_number - index of current batch, from 0 to number of batches-1
179
+ """
180
+
181
+ pass
182
+
183
+ def postprocess_image(self, p, pp: PostprocessImageArgs, *args):
184
+ """
185
+ Called for every image after it has been generated.
186
+ """
187
+
188
+ pass
189
+
190
+ def postprocess(self, p, processed, *args):
191
+ """
192
+ This function is called after processing ends for AlwaysVisible scripts.
193
+ args contains all values returned by components from ui()
194
+ """
195
+
196
+ pass
197
+
198
+ def before_component(self, component, **kwargs):
199
+ """
200
+ Called before a component is created.
201
+ Use elem_id/label fields of kwargs to figure out which component it is.
202
+ This can be useful to inject your own components somewhere in the middle of vanilla UI.
203
+ You can return created components in the ui() function to add them to the list of arguments for your processing functions
204
+ """
205
+
206
+ pass
207
+
208
+ def after_component(self, component, **kwargs):
209
+ """
210
+ Called after a component is created. Same as above.
211
+ """
212
+
213
+ pass
214
+
215
+ def describe(self):
216
+ """unused"""
217
+ return ""
218
+
219
+ def elem_id(self, item_id):
220
+ """helper function to generate id for a HTML element, constructs final id out of script name, tab and user-supplied item_id"""
221
+
222
+ need_tabname = self.show(True) == self.show(False)
223
+ tabkind = 'img2img' if self.is_img2img else 'txt2txt'
224
+ tabname = f"{tabkind}_" if need_tabname else ""
225
+ title = re.sub(r'[^a-z_0-9]', '', re.sub(r'\s', '_', self.title().lower()))
226
+
227
+ return f'script_{tabname}{title}_{item_id}'
228
+
229
+ def before_hr(self, p, *args):
230
+ """
231
+ This function is called before hires fix start.
232
+ """
233
+ pass
234
+
235
+ current_basedir = paths.script_path
236
+
237
+
238
+ def basedir():
239
+ """returns the base directory for the current script. For scripts in the main scripts directory,
240
+ this is the main directory (where webui.py resides), and for scripts in extensions directory
241
+ (ie extensions/aesthetic/script/aesthetic.py), this is extension's directory (extensions/aesthetic)
242
+ """
243
+ return current_basedir
244
+
245
+
246
+ ScriptFile = namedtuple("ScriptFile", ["basedir", "filename", "path"])
247
+
248
+ scripts_data = []
249
+ postprocessing_scripts_data = []
250
+ ScriptClassData = namedtuple("ScriptClassData", ["script_class", "path", "basedir", "module"])
251
+
252
+
253
+ def list_scripts(scriptdirname, extension):
254
+ scripts_list = []
255
+
256
+ basedir = os.path.join(paths.script_path, scriptdirname)
257
+ if os.path.exists(basedir):
258
+ for filename in sorted(os.listdir(basedir)):
259
+ scripts_list.append(ScriptFile(paths.script_path, filename, os.path.join(basedir, filename)))
260
+
261
+ for ext in extensions.active():
262
+ scripts_list += ext.list_files(scriptdirname, extension)
263
+
264
+ scripts_list = [x for x in scripts_list if os.path.splitext(x.path)[1].lower() == extension and os.path.isfile(x.path)]
265
+
266
+ return scripts_list
267
+
268
+
269
+ def list_files_with_name(filename):
270
+ res = []
271
+
272
+ dirs = [paths.script_path] + [ext.path for ext in extensions.active()]
273
+
274
+ for dirpath in dirs:
275
+ if not os.path.isdir(dirpath):
276
+ continue
277
+
278
+ path = os.path.join(dirpath, filename)
279
+ if os.path.isfile(path):
280
+ res.append(path)
281
+
282
+ return res
283
+
284
+
285
+ def load_scripts():
286
+ global current_basedir
287
+ scripts_data.clear()
288
+ postprocessing_scripts_data.clear()
289
+ script_callbacks.clear_callbacks()
290
+
291
+ scripts_list = list_scripts("scripts", ".py")
292
+
293
+ syspath = sys.path
294
+
295
+ def register_scripts_from_module(module):
296
+ for script_class in module.__dict__.values():
297
+ if not inspect.isclass(script_class):
298
+ continue
299
+
300
+ if issubclass(script_class, Script):
301
+ scripts_data.append(ScriptClassData(script_class, scriptfile.path, scriptfile.basedir, module))
302
+ elif issubclass(script_class, scripts_postprocessing.ScriptPostprocessing):
303
+ postprocessing_scripts_data.append(ScriptClassData(script_class, scriptfile.path, scriptfile.basedir, module))
304
+
305
+ def orderby(basedir):
306
+ # 1st webui, 2nd extensions-builtin, 3rd extensions
307
+ priority = {os.path.join(paths.script_path, "extensions-builtin"):1, paths.script_path:0}
308
+ for key in priority:
309
+ if basedir.startswith(key):
310
+ return priority[key]
311
+ return 9999
312
+
313
+ for scriptfile in sorted(scripts_list, key=lambda x: [orderby(x.basedir), x]):
314
+ try:
315
+ if scriptfile.basedir != paths.script_path:
316
+ sys.path = [scriptfile.basedir] + sys.path
317
+ current_basedir = scriptfile.basedir
318
+
319
+ script_module = script_loading.load_module(scriptfile.path)
320
+ register_scripts_from_module(script_module)
321
+
322
+ except Exception:
323
+ errors.report(f"Error loading script: {scriptfile.filename}", exc_info=True)
324
+
325
+ finally:
326
+ sys.path = syspath
327
+ current_basedir = paths.script_path
328
+ timer.startup_timer.record(scriptfile.filename)
329
+
330
+ global scripts_txt2img, scripts_img2img, scripts_postproc
331
+
332
+ scripts_txt2img = ScriptRunner()
333
+ scripts_img2img = ScriptRunner()
334
+ scripts_postproc = scripts_postprocessing.ScriptPostprocessingRunner()
335
+
336
+
337
+ def wrap_call(func, filename, funcname, *args, default=None, **kwargs):
338
+ try:
339
+ return func(*args, **kwargs)
340
+ except Exception:
341
+ errors.report(f"Error calling: {filename}/{funcname}", exc_info=True)
342
+
343
+ return default
344
+
345
+
346
+ class ScriptRunner:
347
+ def __init__(self):
348
+ self.scripts = []
349
+ self.selectable_scripts = []
350
+ self.alwayson_scripts = []
351
+ self.titles = []
352
+ self.infotext_fields = []
353
+ self.paste_field_names = []
354
+ self.inputs = [None]
355
+
356
+ def initialize_scripts(self, is_img2img):
357
+ from modules import scripts_auto_postprocessing
358
+
359
+ self.scripts.clear()
360
+ self.alwayson_scripts.clear()
361
+ self.selectable_scripts.clear()
362
+
363
+ auto_processing_scripts = scripts_auto_postprocessing.create_auto_preprocessing_script_data()
364
+
365
+ for script_data in auto_processing_scripts + scripts_data:
366
+ script = script_data.script_class()
367
+ script.filename = script_data.path
368
+ script.is_txt2img = not is_img2img
369
+ script.is_img2img = is_img2img
370
+
371
+ visibility = script.show(script.is_img2img)
372
+
373
+ if visibility == AlwaysVisible:
374
+ self.scripts.append(script)
375
+ self.alwayson_scripts.append(script)
376
+ script.alwayson = True
377
+
378
+ elif visibility:
379
+ self.scripts.append(script)
380
+ self.selectable_scripts.append(script)
381
+
382
+ def create_script_ui(self, script):
383
+ import modules.api.models as api_models
384
+
385
+ script.args_from = len(self.inputs)
386
+ script.args_to = len(self.inputs)
387
+
388
+ controls = wrap_call(script.ui, script.filename, "ui", script.is_img2img)
389
+
390
+ if controls is None:
391
+ return
392
+
393
+ script.name = wrap_call(script.title, script.filename, "title", default=script.filename).lower()
394
+ api_args = []
395
+
396
+ for control in controls:
397
+ control.custom_script_source = os.path.basename(script.filename)
398
+
399
+ arg_info = api_models.ScriptArg(label=control.label or "")
400
+
401
+ for field in ("value", "minimum", "maximum", "step", "choices"):
402
+ v = getattr(control, field, None)
403
+ if v is not None:
404
+ setattr(arg_info, field, v)
405
+
406
+ api_args.append(arg_info)
407
+
408
+ script.api_info = api_models.ScriptInfo(
409
+ name=script.name,
410
+ is_img2img=script.is_img2img,
411
+ is_alwayson=script.alwayson,
412
+ args=api_args,
413
+ )
414
+
415
+ if script.infotext_fields is not None:
416
+ self.infotext_fields += script.infotext_fields
417
+
418
+ if script.paste_field_names is not None:
419
+ self.paste_field_names += script.paste_field_names
420
+
421
+ self.inputs += controls
422
+ script.args_to = len(self.inputs)
423
+
424
+ def setup_ui_for_section(self, section, scriptlist=None):
425
+ if scriptlist is None:
426
+ scriptlist = self.alwayson_scripts
427
+
428
+ for script in scriptlist:
429
+ if script.alwayson and script.section != section:
430
+ continue
431
+
432
+ with gr.Group(visible=script.alwayson) as group:
433
+ self.create_script_ui(script)
434
+
435
+ script.group = group
436
+
437
+ def prepare_ui(self):
438
+ self.inputs = [None]
439
+
440
+ def setup_ui(self):
441
+ self.titles = [wrap_call(script.title, script.filename, "title") or f"{script.filename} [error]" for script in self.selectable_scripts]
442
+
443
+ self.setup_ui_for_section(None)
444
+
445
+ dropdown = gr.Dropdown(label="Script", elem_id="script_list", choices=["None"] + self.titles, value="None", type="index")
446
+ self.inputs[0] = dropdown
447
+
448
+ self.setup_ui_for_section(None, self.selectable_scripts)
449
+
450
+
451
+ def select_script(script_index):
452
+ selected_script = self.selectable_scripts[script_index - 1] if script_index>0 else None
453
+
454
+ return [gr.update(visible=selected_script == s) for s in self.selectable_scripts]
455
+
456
+ def init_field(title):
457
+ """called when an initial value is set from ui-config.json to show script's UI components"""
458
+
459
+ if title == 'None':
460
+ return
461
+
462
+ script_index = self.titles.index(title)
463
+ self.selectable_scripts[script_index].group.visible = True
464
+
465
+ dropdown.init_field = init_field
466
+
467
+ dropdown.change(
468
+ fn=select_script,
469
+ inputs=[dropdown],
470
+ outputs=[script.group for script in self.selectable_scripts]
471
+ )
472
+
473
+ self.script_load_ctr = 0
474
+
475
+ def onload_script_visibility(params):
476
+ title = params.get('Script', None)
477
+ if title:
478
+ title_index = self.titles.index(title)
479
+ visibility = title_index == self.script_load_ctr
480
+ self.script_load_ctr = (self.script_load_ctr + 1) % len(self.titles)
481
+ return gr.update(visible=visibility)
482
+ else:
483
+ return gr.update(visible=False)
484
+
485
+ self.infotext_fields.append((dropdown, lambda x: gr.update(value=x.get('Script', 'None'))))
486
+ self.infotext_fields.extend([(script.group, onload_script_visibility) for script in self.selectable_scripts])
487
+
488
+ return self.inputs
489
+
490
+ def run(self, p, *args):
491
+ script_index = args[0]
492
+
493
+ if script_index == 0:
494
+ return None
495
+
496
+ script = self.selectable_scripts[script_index-1]
497
+
498
+ if script is None:
499
+ return None
500
+
501
+ script_args = args[script.args_from:script.args_to]
502
+ processed = script.run(p, *script_args)
503
+
504
+ shared.total_tqdm.clear()
505
+
506
+ return processed
507
+
508
+ def before_process(self, p):
509
+ for script in self.alwayson_scripts:
510
+ try:
511
+ script_args = p.script_args[script.args_from:script.args_to]
512
+ script.before_process(p, *script_args)
513
+ except Exception:
514
+ errors.report(f"Error running before_process: {script.filename}", exc_info=True)
515
+
516
+ def process(self, p):
517
+ for script in self.alwayson_scripts:
518
+ try:
519
+ script_args = p.script_args[script.args_from:script.args_to]
520
+ script.process(p, *script_args)
521
+ except Exception:
522
+ errors.report(f"Error running process: {script.filename}", exc_info=True)
523
+
524
+ def before_process_batch(self, p, **kwargs):
525
+ for script in self.alwayson_scripts:
526
+ try:
527
+ script_args = p.script_args[script.args_from:script.args_to]
528
+ script.before_process_batch(p, *script_args, **kwargs)
529
+ except Exception:
530
+ errors.report(f"Error running before_process_batch: {script.filename}", exc_info=True)
531
+
532
+ def after_extra_networks_activate(self, p, **kwargs):
533
+ for script in self.alwayson_scripts:
534
+ try:
535
+ script_args = p.script_args[script.args_from:script.args_to]
536
+ script.after_extra_networks_activate(p, *script_args, **kwargs)
537
+ except Exception:
538
+ errors.report(f"Error running after_extra_networks_activate: {script.filename}", exc_info=True)
539
+
540
+ def process_batch(self, p, **kwargs):
541
+ for script in self.alwayson_scripts:
542
+ try:
543
+ script_args = p.script_args[script.args_from:script.args_to]
544
+ script.process_batch(p, *script_args, **kwargs)
545
+ except Exception:
546
+ errors.report(f"Error running process_batch: {script.filename}", exc_info=True)
547
+
548
+ def postprocess(self, p, processed):
549
+ for script in self.alwayson_scripts:
550
+ try:
551
+ script_args = p.script_args[script.args_from:script.args_to]
552
+ script.postprocess(p, processed, *script_args)
553
+ except Exception:
554
+ errors.report(f"Error running postprocess: {script.filename}", exc_info=True)
555
+
556
+ def postprocess_batch(self, p, images, **kwargs):
557
+ for script in self.alwayson_scripts:
558
+ try:
559
+ script_args = p.script_args[script.args_from:script.args_to]
560
+ script.postprocess_batch(p, *script_args, images=images, **kwargs)
561
+ except Exception:
562
+ errors.report(f"Error running postprocess_batch: {script.filename}", exc_info=True)
563
+
564
+ def postprocess_batch_list(self, p, pp: PostprocessBatchListArgs, **kwargs):
565
+ for script in self.alwayson_scripts:
566
+ try:
567
+ script_args = p.script_args[script.args_from:script.args_to]
568
+ script.postprocess_batch_list(p, pp, *script_args, **kwargs)
569
+ except Exception:
570
+ errors.report(f"Error running postprocess_batch_list: {script.filename}", exc_info=True)
571
+
572
+ def postprocess_image(self, p, pp: PostprocessImageArgs):
573
+ for script in self.alwayson_scripts:
574
+ try:
575
+ script_args = p.script_args[script.args_from:script.args_to]
576
+ script.postprocess_image(p, pp, *script_args)
577
+ except Exception:
578
+ errors.report(f"Error running postprocess_image: {script.filename}", exc_info=True)
579
+
580
+ def before_component(self, component, **kwargs):
581
+ for script in self.scripts:
582
+ try:
583
+ script.before_component(component, **kwargs)
584
+ except Exception:
585
+ errors.report(f"Error running before_component: {script.filename}", exc_info=True)
586
+
587
+ def after_component(self, component, **kwargs):
588
+ for script in self.scripts:
589
+ try:
590
+ script.after_component(component, **kwargs)
591
+ except Exception:
592
+ errors.report(f"Error running after_component: {script.filename}", exc_info=True)
593
+
594
+ def reload_sources(self, cache):
595
+ for si, script in list(enumerate(self.scripts)):
596
+ args_from = script.args_from
597
+ args_to = script.args_to
598
+ filename = script.filename
599
+
600
+ module = cache.get(filename, None)
601
+ if module is None:
602
+ module = script_loading.load_module(script.filename)
603
+ cache[filename] = module
604
+
605
+ for script_class in module.__dict__.values():
606
+ if type(script_class) == type and issubclass(script_class, Script):
607
+ self.scripts[si] = script_class()
608
+ self.scripts[si].filename = filename
609
+ self.scripts[si].args_from = args_from
610
+ self.scripts[si].args_to = args_to
611
+
612
+
613
+ def before_hr(self, p):
614
+ for script in self.alwayson_scripts:
615
+ try:
616
+ script_args = p.script_args[script.args_from:script.args_to]
617
+ script.before_hr(p, *script_args)
618
+ except Exception:
619
+ errors.report(f"Error running before_hr: {script.filename}", exc_info=True)
620
+
621
+
622
+ scripts_txt2img: ScriptRunner = None
623
+ scripts_img2img: ScriptRunner = None
624
+ scripts_postproc: scripts_postprocessing.ScriptPostprocessingRunner = None
625
+ scripts_current: ScriptRunner = None
626
+
627
+
628
+ def reload_script_body_only():
629
+ cache = {}
630
+ scripts_txt2img.reload_sources(cache)
631
+ scripts_img2img.reload_sources(cache)
632
+
633
+
634
+ reload_scripts = load_scripts # compatibility alias
635
+
636
+
637
+ def add_classes_to_gradio_component(comp):
638
+ """
639
+ this adds gradio-* to the component for css styling (ie gradio-button to gr.Button), as well as some others
640
+ """
641
+
642
+ comp.elem_classes = [f"gradio-{comp.get_block_name()}", *(comp.elem_classes or [])]
643
+
644
+ if getattr(comp, 'multiselect', False):
645
+ comp.elem_classes.append('multiselect')
646
+
647
+
648
+
649
+ def IOComponent_init(self, *args, **kwargs):
650
+ if scripts_current is not None:
651
+ scripts_current.before_component(self, **kwargs)
652
+
653
+ script_callbacks.before_component_callback(self, **kwargs)
654
+
655
+ res = original_IOComponent_init(self, *args, **kwargs)
656
+
657
+ add_classes_to_gradio_component(self)
658
+
659
+ script_callbacks.after_component_callback(self, **kwargs)
660
+
661
+ if scripts_current is not None:
662
+ scripts_current.after_component(self, **kwargs)
663
+
664
+ return res
665
+
666
+
667
+ original_IOComponent_init = gr.components.IOComponent.__init__
668
+ gr.components.IOComponent.__init__ = IOComponent_init
669
+
670
+
671
+ def BlockContext_init(self, *args, **kwargs):
672
+ res = original_BlockContext_init(self, *args, **kwargs)
673
+
674
+ add_classes_to_gradio_component(self)
675
+
676
+ return res
677
+
678
+
679
+ original_BlockContext_init = gr.blocks.BlockContext.__init__
680
+ gr.blocks.BlockContext.__init__ = BlockContext_init