ui.py 98 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962
  1. import html
  2. import json
  3. import math
  4. import mimetypes
  5. import os
  6. import platform
  7. import random
  8. import sys
  9. import tempfile
  10. import time
  11. import traceback
  12. from functools import partial, reduce
  13. import warnings
  14. import gradio as gr
  15. import gradio.routes
  16. import gradio.utils
  17. import numpy as np
  18. from PIL import Image, PngImagePlugin
  19. from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call
  20. from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, postprocessing, ui_components, ui_common, ui_postprocessing, progress
  21. from modules.ui_components import FormRow, FormColumn, FormGroup, ToolButton, FormHTML
  22. from modules.paths import script_path, data_path
  23. from modules.shared import opts, cmd_opts, restricted_opts
  24. import modules.codeformer_model
  25. import modules.generation_parameters_copypaste as parameters_copypaste
  26. import modules.gfpgan_model
  27. import modules.hypernetworks.ui
  28. import modules.scripts
  29. import modules.shared as shared
  30. import modules.styles
  31. import modules.textual_inversion.ui
  32. from modules import prompt_parser
  33. from modules.images import save_image
  34. from modules.sd_hijack import model_hijack
  35. from modules.sd_samplers import samplers, samplers_for_img2img
  36. from modules.textual_inversion import textual_inversion
  37. import modules.hypernetworks.ui
  38. from modules.generation_parameters_copypaste import image_from_url_text
  39. import modules.extras
  40. warnings.filterwarnings("default" if opts.show_warnings else "ignore", category=UserWarning)
  41. # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI
  42. mimetypes.init()
  43. mimetypes.add_type('application/javascript', '.js')
  44. if not cmd_opts.share and not cmd_opts.listen:
  45. # fix gradio phoning home
  46. gradio.utils.version_check = lambda: None
  47. gradio.utils.get_local_ip_address = lambda: '127.0.0.1'
  48. if cmd_opts.ngrok is not None:
  49. import modules.ngrok as ngrok
  50. print('ngrok authtoken detected, trying to connect...')
  51. ngrok.connect(
  52. cmd_opts.ngrok,
  53. cmd_opts.port if cmd_opts.port is not None else 7860,
  54. cmd_opts.ngrok_options
  55. )
  56. def gr_show(visible=True):
  57. return {"visible": visible, "__type__": "update"}
  58. sample_img2img = "assets/stable-samples/img2img/sketch-mountains-input.jpg"
  59. sample_img2img = sample_img2img if os.path.exists(sample_img2img) else None
  60. # Using constants for these since the variation selector isn't visible.
  61. # Important that they exactly match script.js for tooltip to work.
  62. random_symbol = '\U0001f3b2\ufe0f' # 🎲️
  63. reuse_symbol = '\u267b\ufe0f' # ♻️
  64. paste_symbol = '\u2199\ufe0f' # ↙
  65. refresh_symbol = '\U0001f504' # 🔄
  66. save_style_symbol = '\U0001f4be' # 💾
  67. apply_style_symbol = '\U0001f4cb' # 📋
  68. clear_prompt_symbol = '\U0001f5d1\ufe0f' # 🗑️
  69. extra_networks_symbol = '\U0001F3B4' # 🎴
  70. switch_values_symbol = '\U000021C5' # ⇅
  71. restore_progress_symbol = '\U0001F300' # 🌀
  72. def plaintext_to_html(text):
  73. return ui_common.plaintext_to_html(text)
  74. def send_gradio_gallery_to_image(x):
  75. if len(x) == 0:
  76. return None
  77. return image_from_url_text(x[0])
  78. def visit(x, func, path=""):
  79. if hasattr(x, 'children'):
  80. if isinstance(x, gr.Tabs) and x.elem_id is not None:
  81. # Tabs element can't have a label, have to use elem_id instead
  82. func(f"{path}/Tabs@{x.elem_id}", x)
  83. for c in x.children:
  84. visit(c, func, path)
  85. elif x.label is not None:
  86. func(f"{path}/{x.label}", x)
  87. def add_style(name: str, prompt: str, negative_prompt: str):
  88. if name is None:
  89. return [gr_show() for x in range(4)]
  90. style = modules.styles.PromptStyle(name, prompt, negative_prompt)
  91. shared.prompt_styles.styles[style.name] = style
  92. # Save all loaded prompt styles: this allows us to update the storage format in the future more easily, because we
  93. # reserialize all styles every time we save them
  94. shared.prompt_styles.save_styles(shared.styles_filename)
  95. return [gr.Dropdown.update(visible=True, choices=list(shared.prompt_styles.styles)) for _ in range(2)]
  96. def calc_resolution_hires(enable, width, height, hr_scale, hr_resize_x, hr_resize_y):
  97. from modules import processing, devices
  98. if not enable:
  99. return ""
  100. p = processing.StableDiffusionProcessingTxt2Img(width=width, height=height, enable_hr=True, hr_scale=hr_scale, hr_resize_x=hr_resize_x, hr_resize_y=hr_resize_y)
  101. with devices.autocast():
  102. p.init([""], [0], [0])
  103. return f"resize: from <span class='resolution'>{p.width}x{p.height}</span> to <span class='resolution'>{p.hr_resize_x or p.hr_upscale_to_x}x{p.hr_resize_y or p.hr_upscale_to_y}</span>"
  104. def resize_from_to_html(width, height, scale_by):
  105. target_width = int(width * scale_by)
  106. target_height = int(height * scale_by)
  107. if not target_width or not target_height:
  108. return "no image selected"
  109. return f"resize: from <span class='resolution'>{width}x{height}</span> to <span class='resolution'>{target_width}x{target_height}</span>"
  110. def apply_styles(prompt, prompt_neg, styles):
  111. prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, styles)
  112. prompt_neg = shared.prompt_styles.apply_negative_styles_to_prompt(prompt_neg, styles)
  113. return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=prompt_neg), gr.Dropdown.update(value=[])]
  114. def process_interrogate(interrogation_function, mode, ii_input_dir, ii_output_dir, *ii_singles):
  115. if mode in {0, 1, 3, 4}:
  116. return [interrogation_function(ii_singles[mode]), None]
  117. elif mode == 2:
  118. return [interrogation_function(ii_singles[mode]["image"]), None]
  119. elif mode == 5:
  120. assert not shared.cmd_opts.hide_ui_dir_config, "Launched with --hide-ui-dir-config, batch img2img disabled"
  121. images = shared.listfiles(ii_input_dir)
  122. print(f"Will process {len(images)} images.")
  123. if ii_output_dir != "":
  124. os.makedirs(ii_output_dir, exist_ok=True)
  125. else:
  126. ii_output_dir = ii_input_dir
  127. for image in images:
  128. img = Image.open(image)
  129. filename = os.path.basename(image)
  130. left, _ = os.path.splitext(filename)
  131. print(interrogation_function(img), file=open(os.path.join(ii_output_dir, f"{left}.txt"), 'a'))
  132. return [gr.update(), None]
  133. def interrogate(image):
  134. prompt = shared.interrogator.interrogate(image.convert("RGB"))
  135. return gr.update() if prompt is None else prompt
  136. def interrogate_deepbooru(image):
  137. prompt = deepbooru.model.tag(image)
  138. return gr.update() if prompt is None else prompt
  139. def create_seed_inputs(target_interface):
  140. with FormRow(elem_id=f"{target_interface}_seed_row", variant="compact"):
  141. seed = (gr.Textbox if cmd_opts.use_textbox_seed else gr.Number)(label='Seed', value=-1, elem_id=f"{target_interface}_seed")
  142. seed.style(container=False)
  143. random_seed = ToolButton(random_symbol, elem_id=f"{target_interface}_random_seed", label='Random seed')
  144. reuse_seed = ToolButton(reuse_symbol, elem_id=f"{target_interface}_reuse_seed", label='Reuse seed')
  145. seed_checkbox = gr.Checkbox(label='Extra', elem_id=f"{target_interface}_subseed_show", value=False)
  146. # Components to show/hide based on the 'Extra' checkbox
  147. seed_extras = []
  148. with FormRow(visible=False, elem_id=f"{target_interface}_subseed_row") as seed_extra_row_1:
  149. seed_extras.append(seed_extra_row_1)
  150. subseed = gr.Number(label='Variation seed', value=-1, elem_id=f"{target_interface}_subseed")
  151. subseed.style(container=False)
  152. random_subseed = ToolButton(random_symbol, elem_id=f"{target_interface}_random_subseed")
  153. reuse_subseed = ToolButton(reuse_symbol, elem_id=f"{target_interface}_reuse_subseed")
  154. subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=f"{target_interface}_subseed_strength")
  155. with FormRow(visible=False) as seed_extra_row_2:
  156. seed_extras.append(seed_extra_row_2)
  157. seed_resize_from_w = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize seed from width", value=0, elem_id=f"{target_interface}_seed_resize_from_w")
  158. seed_resize_from_h = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize seed from height", value=0, elem_id=f"{target_interface}_seed_resize_from_h")
  159. random_seed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[seed])
  160. random_subseed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[subseed])
  161. def change_visibility(show):
  162. return {comp: gr_show(show) for comp in seed_extras}
  163. seed_checkbox.change(change_visibility, show_progress=False, inputs=[seed_checkbox], outputs=seed_extras)
  164. return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox
  165. def connect_clear_prompt(button):
  166. """Given clear button, prompt, and token_counter objects, setup clear prompt button click event"""
  167. button.click(
  168. _js="clear_prompt",
  169. fn=None,
  170. inputs=[],
  171. outputs=[],
  172. )
  173. def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: gr.Textbox, dummy_component, is_subseed):
  174. """ Connects a 'reuse (sub)seed' button's click event so that it copies last used
  175. (sub)seed value from generation info the to the seed field. If copying subseed and subseed strength
  176. was 0, i.e. no variation seed was used, it copies the normal seed value instead."""
  177. def copy_seed(gen_info_string: str, index):
  178. res = -1
  179. try:
  180. gen_info = json.loads(gen_info_string)
  181. index -= gen_info.get('index_of_first_image', 0)
  182. if is_subseed and gen_info.get('subseed_strength', 0) > 0:
  183. all_subseeds = gen_info.get('all_subseeds', [-1])
  184. res = all_subseeds[index if 0 <= index < len(all_subseeds) else 0]
  185. else:
  186. all_seeds = gen_info.get('all_seeds', [-1])
  187. res = all_seeds[index if 0 <= index < len(all_seeds) else 0]
  188. except json.decoder.JSONDecodeError as e:
  189. if gen_info_string != '':
  190. print("Error parsing JSON generation info:", file=sys.stderr)
  191. print(gen_info_string, file=sys.stderr)
  192. return [res, gr_show(False)]
  193. reuse_seed.click(
  194. fn=copy_seed,
  195. _js="(x, y) => [x, selected_gallery_index()]",
  196. show_progress=False,
  197. inputs=[generation_info, dummy_component],
  198. outputs=[seed, dummy_component]
  199. )
  200. def update_token_counter(text, steps):
  201. try:
  202. text, _ = extra_networks.parse_prompt(text)
  203. _, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
  204. prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)
  205. except Exception:
  206. # a parsing error can happen here during typing, and we don't want to bother the user with
  207. # messages related to it in console
  208. prompt_schedules = [[[steps, text]]]
  209. flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules)
  210. prompts = [prompt_text for step, prompt_text in flat_prompts]
  211. token_count, max_length = max([model_hijack.get_prompt_lengths(prompt) for prompt in prompts], key=lambda args: args[0])
  212. return f"<span class='gr-box gr-text-input'>{token_count}/{max_length}</span>"
  213. def create_toprow(is_img2img):
  214. id_part = "img2img" if is_img2img else "txt2img"
  215. with gr.Row(elem_id=f"{id_part}_toprow", variant="compact"):
  216. with gr.Column(elem_id=f"{id_part}_prompt_container", scale=6):
  217. with gr.Row():
  218. with gr.Column(scale=80):
  219. with gr.Row():
  220. prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, lines=3, placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)")
  221. with gr.Row():
  222. with gr.Column(scale=80):
  223. with gr.Row():
  224. negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=3, placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)")
  225. button_interrogate = None
  226. button_deepbooru = None
  227. if is_img2img:
  228. with gr.Column(scale=1, elem_classes="interrogate-col"):
  229. button_interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate")
  230. button_deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru")
  231. with gr.Column(scale=1, elem_id=f"{id_part}_actions_column"):
  232. with gr.Row(elem_id=f"{id_part}_generate_box", elem_classes="generate-box"):
  233. interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt", elem_classes="generate-box-interrupt")
  234. skip = gr.Button('Skip', elem_id=f"{id_part}_skip", elem_classes="generate-box-skip")
  235. submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary')
  236. skip.click(
  237. fn=lambda: shared.state.skip(),
  238. inputs=[],
  239. outputs=[],
  240. )
  241. interrupt.click(
  242. fn=lambda: shared.state.interrupt(),
  243. inputs=[],
  244. outputs=[],
  245. )
  246. with gr.Row(elem_id=f"{id_part}_tools"):
  247. paste = ToolButton(value=paste_symbol, elem_id="paste")
  248. clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt")
  249. extra_networks_button = ToolButton(value=extra_networks_symbol, elem_id=f"{id_part}_extra_networks")
  250. prompt_style_apply = ToolButton(value=apply_style_symbol, elem_id=f"{id_part}_style_apply")
  251. save_style = ToolButton(value=save_style_symbol, elem_id=f"{id_part}_style_create")
  252. restore_progress_button = ToolButton(value=restore_progress_symbol, elem_id=f"{id_part}_restore_progress", visible=False)
  253. token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_token_counter", elem_classes=["token-counter"])
  254. token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")
  255. negative_token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_negative_token_counter", elem_classes=["token-counter"])
  256. negative_token_button = gr.Button(visible=False, elem_id=f"{id_part}_negative_token_button")
  257. clear_prompt_button.click(
  258. fn=lambda *x: x,
  259. _js="confirm_clear_prompt",
  260. inputs=[prompt, negative_prompt],
  261. outputs=[prompt, negative_prompt],
  262. )
  263. with gr.Row(elem_id=f"{id_part}_styles_row"):
  264. prompt_styles = gr.Dropdown(label="Styles", elem_id=f"{id_part}_styles", choices=[k for k, v in shared.prompt_styles.styles.items()], value=[], multiselect=True)
  265. create_refresh_button(prompt_styles, shared.prompt_styles.reload, lambda: {"choices": [k for k, v in shared.prompt_styles.styles.items()]}, f"refresh_{id_part}_styles")
  266. return prompt, prompt_styles, negative_prompt, submit, button_interrogate, button_deepbooru, prompt_style_apply, save_style, paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button, restore_progress_button
  267. def setup_progressbar(*args, **kwargs):
  268. pass
  269. def apply_setting(key, value):
  270. if value is None:
  271. return gr.update()
  272. if shared.cmd_opts.freeze_settings:
  273. return gr.update()
  274. # dont allow model to be swapped when model hash exists in prompt
  275. if key == "sd_model_checkpoint" and opts.disable_weights_auto_swap:
  276. return gr.update()
  277. if key == "sd_model_checkpoint":
  278. ckpt_info = sd_models.get_closet_checkpoint_match(value)
  279. if ckpt_info is not None:
  280. value = ckpt_info.title
  281. else:
  282. return gr.update()
  283. comp_args = opts.data_labels[key].component_args
  284. if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False:
  285. return
  286. valtype = type(opts.data_labels[key].default)
  287. oldval = opts.data.get(key, None)
  288. opts.data[key] = valtype(value) if valtype != type(None) else value
  289. if oldval != value and opts.data_labels[key].onchange is not None:
  290. opts.data_labels[key].onchange()
  291. opts.save(shared.config_filename)
  292. return getattr(opts, key)
  293. def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id):
  294. def refresh():
  295. refresh_method()
  296. args = refreshed_args() if callable(refreshed_args) else refreshed_args
  297. for k, v in args.items():
  298. setattr(refresh_component, k, v)
  299. return gr.update(**(args or {}))
  300. refresh_button = ToolButton(value=refresh_symbol, elem_id=elem_id)
  301. refresh_button.click(
  302. fn=refresh,
  303. inputs=[],
  304. outputs=[refresh_component]
  305. )
  306. return refresh_button
  307. def create_output_panel(tabname, outdir):
  308. return ui_common.create_output_panel(tabname, outdir)
  309. def create_sampler_and_steps_selection(choices, tabname):
  310. if opts.samplers_in_dropdown:
  311. with FormRow(elem_id=f"sampler_selection_{tabname}"):
  312. sampler_index = gr.Dropdown(label='Sampling method', elem_id=f"{tabname}_sampling", choices=[x.name for x in choices], value=choices[0].name, type="index")
  313. steps = gr.Slider(minimum=1, maximum=150, step=1, elem_id=f"{tabname}_steps", label="Sampling steps", value=20)
  314. else:
  315. with FormGroup(elem_id=f"sampler_selection_{tabname}"):
  316. steps = gr.Slider(minimum=1, maximum=150, step=1, elem_id=f"{tabname}_steps", label="Sampling steps", value=20)
  317. sampler_index = gr.Radio(label='Sampling method', elem_id=f"{tabname}_sampling", choices=[x.name for x in choices], value=choices[0].name, type="index")
  318. return steps, sampler_index
  319. def ordered_ui_categories():
  320. user_order = {x.strip(): i * 2 + 1 for i, x in enumerate(shared.opts.ui_reorder.split(","))}
  321. for i, category in sorted(enumerate(shared.ui_reorder_categories), key=lambda x: user_order.get(x[1], x[0] * 2 + 0)):
  322. yield category
  323. def get_value_for_setting(key):
  324. value = getattr(opts, key)
  325. info = opts.data_labels[key]
  326. args = info.component_args() if callable(info.component_args) else info.component_args or {}
  327. args = {k: v for k, v in args.items() if k not in {'precision'}}
  328. return gr.update(value=value, **args)
  329. def create_override_settings_dropdown(tabname, row):
  330. dropdown = gr.Dropdown([], label="Override settings", visible=False, elem_id=f"{tabname}_override_settings", multiselect=True)
  331. dropdown.change(
  332. fn=lambda x: gr.Dropdown.update(visible=len(x) > 0),
  333. inputs=[dropdown],
  334. outputs=[dropdown],
  335. )
  336. return dropdown
  337. def create_ui():
  338. import modules.img2img
  339. import modules.txt2img
  340. reload_javascript()
  341. parameters_copypaste.reset()
  342. modules.scripts.scripts_current = modules.scripts.scripts_txt2img
  343. modules.scripts.scripts_txt2img.initialize_scripts(is_img2img=False)
  344. with gr.Blocks(analytics_enabled=False) as txt2img_interface:
  345. txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button, restore_progress_button = create_toprow(is_img2img=False)
  346. dummy_component = gr.Label(visible=False)
  347. txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="binary", visible=False)
  348. with FormRow(variant='compact', elem_id="txt2img_extra_networks", visible=False) as extra_networks:
  349. from modules import ui_extra_networks
  350. extra_networks_ui = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'txt2img')
  351. with gr.Row().style(equal_height=False):
  352. with gr.Column(variant='compact', elem_id="txt2img_settings"):
  353. for category in ordered_ui_categories():
  354. if category == "sampler":
  355. steps, sampler_index = create_sampler_and_steps_selection(samplers, "txt2img")
  356. elif category == "dimensions":
  357. with FormRow():
  358. with gr.Column(elem_id="txt2img_column_size", scale=4):
  359. width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="txt2img_width")
  360. height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="txt2img_height")
  361. with gr.Column(elem_id="txt2img_dimensions_row", scale=1, elem_classes="dimensions-tools"):
  362. res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn", label="Switch dims")
  363. if opts.dimensions_and_batch_together:
  364. with gr.Column(elem_id="txt2img_column_batch"):
  365. batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count")
  366. batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size")
  367. elif category == "cfg":
  368. cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0, elem_id="txt2img_cfg_scale")
  369. elif category == "seed":
  370. seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs('txt2img')
  371. elif category == "checkboxes":
  372. with FormRow(elem_classes="checkboxes-row", variant="compact"):
  373. restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1, elem_id="txt2img_restore_faces")
  374. tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling")
  375. enable_hr = gr.Checkbox(label='Hires. fix', value=False, elem_id="txt2img_enable_hr")
  376. hr_final_resolution = FormHTML(value="", elem_id="txtimg_hr_finalres", label="Upscaled resolution", interactive=False)
  377. elif category == "hires_fix":
  378. with FormGroup(visible=False, elem_id="txt2img_hires_fix") as hr_options:
  379. with FormRow(elem_id="txt2img_hires_fix_row1", variant="compact"):
  380. hr_upscaler = gr.Dropdown(label="Upscaler", elem_id="txt2img_hr_upscaler", choices=[*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]], value=shared.latent_upscale_default_mode)
  381. hr_second_pass_steps = gr.Slider(minimum=0, maximum=150, step=1, label='Hires steps', value=0, elem_id="txt2img_hires_steps")
  382. denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7, elem_id="txt2img_denoising_strength")
  383. with FormRow(elem_id="txt2img_hires_fix_row2", variant="compact"):
  384. hr_scale = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Upscale by", value=2.0, elem_id="txt2img_hr_scale")
  385. hr_resize_x = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize width to", value=0, elem_id="txt2img_hr_resize_x")
  386. hr_resize_y = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize height to", value=0, elem_id="txt2img_hr_resize_y")
  387. elif category == "batch":
  388. if not opts.dimensions_and_batch_together:
  389. with FormRow(elem_id="txt2img_column_batch"):
  390. batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count")
  391. batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size")
  392. elif category == "override_settings":
  393. with FormRow(elem_id="txt2img_override_settings_row") as row:
  394. override_settings = create_override_settings_dropdown('txt2img', row)
  395. elif category == "scripts":
  396. with FormGroup(elem_id="txt2img_script_container"):
  397. custom_inputs = modules.scripts.scripts_txt2img.setup_ui()
  398. hr_resolution_preview_inputs = [enable_hr, width, height, hr_scale, hr_resize_x, hr_resize_y]
  399. for input in hr_resolution_preview_inputs:
  400. input.change(
  401. fn=calc_resolution_hires,
  402. inputs=hr_resolution_preview_inputs,
  403. outputs=[hr_final_resolution],
  404. show_progress=False,
  405. )
  406. input.change(
  407. None,
  408. _js="onCalcResolutionHires",
  409. inputs=hr_resolution_preview_inputs,
  410. outputs=[],
  411. show_progress=False,
  412. )
  413. txt2img_gallery, generation_info, html_info, html_log = create_output_panel("txt2img", opts.outdir_txt2img_samples)
  414. connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
  415. connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
  416. txt2img_args = dict(
  417. fn=wrap_gradio_gpu_call(modules.txt2img.txt2img, extra_outputs=[None, '', '']),
  418. _js="submit",
  419. inputs=[
  420. dummy_component,
  421. txt2img_prompt,
  422. txt2img_negative_prompt,
  423. txt2img_prompt_styles,
  424. steps,
  425. sampler_index,
  426. restore_faces,
  427. tiling,
  428. batch_count,
  429. batch_size,
  430. cfg_scale,
  431. seed,
  432. subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
  433. height,
  434. width,
  435. enable_hr,
  436. denoising_strength,
  437. hr_scale,
  438. hr_upscaler,
  439. hr_second_pass_steps,
  440. hr_resize_x,
  441. hr_resize_y,
  442. override_settings,
  443. ] + custom_inputs,
  444. outputs=[
  445. txt2img_gallery,
  446. generation_info,
  447. html_info,
  448. html_log,
  449. ],
  450. show_progress=False,
  451. )
  452. txt2img_prompt.submit(**txt2img_args)
  453. submit.click(**txt2img_args)
  454. res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False)
  455. restore_progress_button.click(
  456. fn=progress.restore_progress,
  457. _js="restoreProgressTxt2img",
  458. inputs=[dummy_component],
  459. outputs=[
  460. txt2img_gallery,
  461. generation_info,
  462. html_info,
  463. html_log,
  464. ],
  465. show_progress=False,
  466. )
  467. txt_prompt_img.change(
  468. fn=modules.images.image_data,
  469. inputs=[
  470. txt_prompt_img
  471. ],
  472. outputs=[
  473. txt2img_prompt,
  474. txt_prompt_img
  475. ]
  476. )
  477. enable_hr.change(
  478. fn=lambda x: gr_show(x),
  479. inputs=[enable_hr],
  480. outputs=[hr_options],
  481. show_progress = False,
  482. )
  483. txt2img_paste_fields = [
  484. (txt2img_prompt, "Prompt"),
  485. (txt2img_negative_prompt, "Negative prompt"),
  486. (steps, "Steps"),
  487. (sampler_index, "Sampler"),
  488. (restore_faces, "Face restoration"),
  489. (cfg_scale, "CFG scale"),
  490. (seed, "Seed"),
  491. (width, "Size-1"),
  492. (height, "Size-2"),
  493. (batch_size, "Batch size"),
  494. (subseed, "Variation seed"),
  495. (subseed_strength, "Variation seed strength"),
  496. (seed_resize_from_w, "Seed resize from-1"),
  497. (seed_resize_from_h, "Seed resize from-2"),
  498. (denoising_strength, "Denoising strength"),
  499. (enable_hr, lambda d: "Denoising strength" in d),
  500. (hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)),
  501. (hr_scale, "Hires upscale"),
  502. (hr_upscaler, "Hires upscaler"),
  503. (hr_second_pass_steps, "Hires steps"),
  504. (hr_resize_x, "Hires resize-1"),
  505. (hr_resize_y, "Hires resize-2"),
  506. *modules.scripts.scripts_txt2img.infotext_fields
  507. ]
  508. parameters_copypaste.add_paste_fields("txt2img", None, txt2img_paste_fields, override_settings)
  509. parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding(
  510. paste_button=txt2img_paste, tabname="txt2img", source_text_component=txt2img_prompt, source_image_component=None,
  511. ))
  512. txt2img_preview_params = [
  513. txt2img_prompt,
  514. txt2img_negative_prompt,
  515. steps,
  516. sampler_index,
  517. cfg_scale,
  518. seed,
  519. width,
  520. height,
  521. ]
  522. token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_prompt, steps], outputs=[token_counter])
  523. negative_token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_negative_prompt, steps], outputs=[negative_token_counter])
  524. ui_extra_networks.setup_ui(extra_networks_ui, txt2img_gallery)
  525. modules.scripts.scripts_current = modules.scripts.scripts_img2img
  526. modules.scripts.scripts_img2img.initialize_scripts(is_img2img=True)
  527. with gr.Blocks(analytics_enabled=False) as img2img_interface:
  528. img2img_prompt, img2img_prompt_styles, img2img_negative_prompt, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button, restore_progress_button = create_toprow(is_img2img=True)
  529. img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="binary", visible=False)
  530. with FormRow(variant='compact', elem_id="img2img_extra_networks", visible=False) as extra_networks:
  531. from modules import ui_extra_networks
  532. extra_networks_ui_img2img = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'img2img')
  533. with FormRow().style(equal_height=False):
  534. with gr.Column(variant='compact', elem_id="img2img_settings"):
  535. copy_image_buttons = []
  536. copy_image_destinations = {}
  537. def add_copy_image_controls(tab_name, elem):
  538. with gr.Row(variant="compact", elem_id=f"img2img_copy_to_{tab_name}"):
  539. gr.HTML("Copy image to: ", elem_id=f"img2img_label_copy_to_{tab_name}")
  540. for title, name in zip(['img2img', 'sketch', 'inpaint', 'inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']):
  541. if name == tab_name:
  542. gr.Button(title, interactive=False)
  543. copy_image_destinations[name] = elem
  544. continue
  545. button = gr.Button(title)
  546. copy_image_buttons.append((button, name, elem))
  547. with gr.Tabs(elem_id="mode_img2img"):
  548. img2img_selected_tab = gr.State(0)
  549. with gr.TabItem('img2img', id='img2img', elem_id="img2img_img2img_tab") as tab_img2img:
  550. init_img = gr.Image(label="Image for img2img", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool="editor", image_mode="RGBA").style(height=480)
  551. add_copy_image_controls('img2img', init_img)
  552. with gr.TabItem('Sketch', id='img2img_sketch', elem_id="img2img_img2img_sketch_tab") as tab_sketch:
  553. sketch = gr.Image(label="Image for img2img", elem_id="img2img_sketch", show_label=False, source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA").style(height=480)
  554. add_copy_image_controls('sketch', sketch)
  555. with gr.TabItem('Inpaint', id='inpaint', elem_id="img2img_inpaint_tab") as tab_inpaint:
  556. init_img_with_mask = gr.Image(label="Image for inpainting with mask", show_label=False, elem_id="img2maskimg", source="upload", interactive=True, type="pil", tool="sketch", image_mode="RGBA").style(height=480)
  557. add_copy_image_controls('inpaint', init_img_with_mask)
  558. with gr.TabItem('Inpaint sketch', id='inpaint_sketch', elem_id="img2img_inpaint_sketch_tab") as tab_inpaint_color:
  559. inpaint_color_sketch = gr.Image(label="Color sketch inpainting", show_label=False, elem_id="inpaint_sketch", source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA").style(height=480)
  560. inpaint_color_sketch_orig = gr.State(None)
  561. add_copy_image_controls('inpaint_sketch', inpaint_color_sketch)
  562. def update_orig(image, state):
  563. if image is not None:
  564. same_size = state is not None and state.size == image.size
  565. has_exact_match = np.any(np.all(np.array(image) == np.array(state), axis=-1))
  566. edited = same_size and has_exact_match
  567. return image if not edited or state is None else state
  568. inpaint_color_sketch.change(update_orig, [inpaint_color_sketch, inpaint_color_sketch_orig], inpaint_color_sketch_orig)
  569. with gr.TabItem('Inpaint upload', id='inpaint_upload', elem_id="img2img_inpaint_upload_tab") as tab_inpaint_upload:
  570. init_img_inpaint = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil", elem_id="img_inpaint_base")
  571. init_mask_inpaint = gr.Image(label="Mask", source="upload", interactive=True, type="pil", elem_id="img_inpaint_mask")
  572. with gr.TabItem('Batch', id='batch', elem_id="img2img_batch_tab") as tab_batch:
  573. hidden = '<br>Disabled when launched with --hide-ui-dir-config.' if shared.cmd_opts.hide_ui_dir_config else ''
  574. gr.HTML(
  575. f"<p style='padding-bottom: 1em;' class=\"text-gray-500\">Process images in a directory on the same machine where the server is running." +
  576. f"<br>Use an empty output directory to save pictures normally instead of writing to the output directory." +
  577. f"<br>Add inpaint batch mask directory to enable inpaint batch processing."
  578. f"{hidden}</p>"
  579. )
  580. img2img_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs, elem_id="img2img_batch_input_dir")
  581. img2img_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs, elem_id="img2img_batch_output_dir")
  582. img2img_batch_inpaint_mask_dir = gr.Textbox(label="Inpaint batch mask directory (required for inpaint batch processing only)", **shared.hide_dirs, elem_id="img2img_batch_inpaint_mask_dir")
  583. img2img_tabs = [tab_img2img, tab_sketch, tab_inpaint, tab_inpaint_color, tab_inpaint_upload, tab_batch]
  584. img2img_image_inputs = [init_img, sketch, init_img_with_mask, inpaint_color_sketch]
  585. for i, tab in enumerate(img2img_tabs):
  586. tab.select(fn=lambda tabnum=i: tabnum, inputs=[], outputs=[img2img_selected_tab])
  587. def copy_image(img):
  588. if isinstance(img, dict) and 'image' in img:
  589. return img['image']
  590. return img
  591. for button, name, elem in copy_image_buttons:
  592. button.click(
  593. fn=copy_image,
  594. inputs=[elem],
  595. outputs=[copy_image_destinations[name]],
  596. )
  597. button.click(
  598. fn=lambda: None,
  599. _js=f"switch_to_{name.replace(' ', '_')}",
  600. inputs=[],
  601. outputs=[],
  602. )
  603. with FormRow():
  604. resize_mode = gr.Radio(label="Resize mode", elem_id="resize_mode", choices=["Just resize", "Crop and resize", "Resize and fill", "Just resize (latent upscale)"], type="index", value="Just resize")
  605. for category in ordered_ui_categories():
  606. if category == "sampler":
  607. steps, sampler_index = create_sampler_and_steps_selection(samplers_for_img2img, "img2img")
  608. elif category == "dimensions":
  609. with FormRow():
  610. with gr.Column(elem_id="img2img_column_size", scale=4):
  611. selected_scale_tab = gr.State(value=0)
  612. with gr.Tabs():
  613. with gr.Tab(label="Resize to") as tab_scale_to:
  614. with FormRow():
  615. with gr.Column(elem_id="img2img_column_size", scale=4):
  616. width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="img2img_width")
  617. height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="img2img_height")
  618. with gr.Column(elem_id="img2img_dimensions_row", scale=1, elem_classes="dimensions-tools"):
  619. res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn")
  620. with gr.Tab(label="Resize by") as tab_scale_by:
  621. scale_by = gr.Slider(minimum=0.05, maximum=4.0, step=0.05, label="Scale", value=1.0, elem_id="img2img_scale")
  622. with FormRow():
  623. scale_by_html = FormHTML(resize_from_to_html(0, 0, 0.0), elem_id="img2img_scale_resolution_preview")
  624. gr.Slider(label="Unused", elem_id="img2img_unused_scale_by_slider")
  625. button_update_resize_to = gr.Button(visible=False, elem_id="img2img_update_resize_to")
  626. on_change_args = dict(
  627. fn=resize_from_to_html,
  628. _js="currentImg2imgSourceResolution",
  629. inputs=[dummy_component, dummy_component, scale_by],
  630. outputs=scale_by_html,
  631. show_progress=False,
  632. )
  633. scale_by.release(**on_change_args)
  634. button_update_resize_to.click(**on_change_args)
  635. # the code below is meant to update the resolution label after the image in the image selection UI has changed.
  636. # as it is now the event keeps firing continuously for inpaint edits, which ruins the page with constant requests.
  637. # I assume this must be a gradio bug and for now we'll just do it for non-inpaint inputs.
  638. for component in [init_img, sketch]:
  639. component.change(fn=lambda: None, _js="updateImg2imgResizeToTextAfterChangingImage", inputs=[], outputs=[], show_progress=False)
  640. tab_scale_to.select(fn=lambda: 0, inputs=[], outputs=[selected_scale_tab])
  641. tab_scale_by.select(fn=lambda: 1, inputs=[], outputs=[selected_scale_tab])
  642. if opts.dimensions_and_batch_together:
  643. with gr.Column(elem_id="img2img_column_batch"):
  644. batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count")
  645. batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="img2img_batch_size")
  646. elif category == "cfg":
  647. with FormGroup():
  648. with FormRow():
  649. cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0, elem_id="img2img_cfg_scale")
  650. image_cfg_scale = gr.Slider(minimum=0, maximum=3.0, step=0.05, label='Image CFG Scale', value=1.5, elem_id="img2img_image_cfg_scale", visible=False)
  651. denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.75, elem_id="img2img_denoising_strength")
  652. elif category == "seed":
  653. seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs('img2img')
  654. elif category == "checkboxes":
  655. with FormRow(elem_classes="checkboxes-row", variant="compact"):
  656. restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1, elem_id="img2img_restore_faces")
  657. tiling = gr.Checkbox(label='Tiling', value=False, elem_id="img2img_tiling")
  658. elif category == "batch":
  659. if not opts.dimensions_and_batch_together:
  660. with FormRow(elem_id="img2img_column_batch"):
  661. batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count")
  662. batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="img2img_batch_size")
  663. elif category == "override_settings":
  664. with FormRow(elem_id="img2img_override_settings_row") as row:
  665. override_settings = create_override_settings_dropdown('img2img', row)
  666. elif category == "scripts":
  667. with FormGroup(elem_id="img2img_script_container"):
  668. custom_inputs = modules.scripts.scripts_img2img.setup_ui()
  669. elif category == "inpaint":
  670. with FormGroup(elem_id="inpaint_controls", visible=False) as inpaint_controls:
  671. with FormRow():
  672. mask_blur = gr.Slider(label='Mask blur', minimum=0, maximum=64, step=1, value=4, elem_id="img2img_mask_blur")
  673. mask_alpha = gr.Slider(label="Mask transparency", visible=False, elem_id="img2img_mask_alpha")
  674. with FormRow():
  675. inpainting_mask_invert = gr.Radio(label='Mask mode', choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index", elem_id="img2img_mask_mode")
  676. with FormRow():
  677. inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index", elem_id="img2img_inpainting_fill")
  678. with FormRow():
  679. with gr.Column():
  680. inpaint_full_res = gr.Radio(label="Inpaint area", choices=["Whole picture", "Only masked"], type="index", value="Whole picture", elem_id="img2img_inpaint_full_res")
  681. with gr.Column(scale=4):
  682. inpaint_full_res_padding = gr.Slider(label='Only masked padding, pixels', minimum=0, maximum=256, step=4, value=32, elem_id="img2img_inpaint_full_res_padding")
  683. def select_img2img_tab(tab):
  684. return gr.update(visible=tab in [2, 3, 4]), gr.update(visible=tab == 3),
  685. for i, elem in enumerate(img2img_tabs):
  686. elem.select(
  687. fn=lambda tab=i: select_img2img_tab(tab),
  688. inputs=[],
  689. outputs=[inpaint_controls, mask_alpha],
  690. )
  691. img2img_gallery, generation_info, html_info, html_log = create_output_panel("img2img", opts.outdir_img2img_samples)
  692. connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
  693. connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
  694. img2img_prompt_img.change(
  695. fn=modules.images.image_data,
  696. inputs=[
  697. img2img_prompt_img
  698. ],
  699. outputs=[
  700. img2img_prompt,
  701. img2img_prompt_img
  702. ]
  703. )
  704. img2img_args = dict(
  705. fn=wrap_gradio_gpu_call(modules.img2img.img2img, extra_outputs=[None, '', '']),
  706. _js="submit_img2img",
  707. inputs=[
  708. dummy_component,
  709. dummy_component,
  710. img2img_prompt,
  711. img2img_negative_prompt,
  712. img2img_prompt_styles,
  713. init_img,
  714. sketch,
  715. init_img_with_mask,
  716. inpaint_color_sketch,
  717. inpaint_color_sketch_orig,
  718. init_img_inpaint,
  719. init_mask_inpaint,
  720. steps,
  721. sampler_index,
  722. mask_blur,
  723. mask_alpha,
  724. inpainting_fill,
  725. restore_faces,
  726. tiling,
  727. batch_count,
  728. batch_size,
  729. cfg_scale,
  730. image_cfg_scale,
  731. denoising_strength,
  732. seed,
  733. subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
  734. selected_scale_tab,
  735. height,
  736. width,
  737. scale_by,
  738. resize_mode,
  739. inpaint_full_res,
  740. inpaint_full_res_padding,
  741. inpainting_mask_invert,
  742. img2img_batch_input_dir,
  743. img2img_batch_output_dir,
  744. img2img_batch_inpaint_mask_dir,
  745. override_settings,
  746. ] + custom_inputs,
  747. outputs=[
  748. img2img_gallery,
  749. generation_info,
  750. html_info,
  751. html_log,
  752. ],
  753. show_progress=False,
  754. )
  755. interrogate_args = dict(
  756. _js="get_img2img_tab_index",
  757. inputs=[
  758. dummy_component,
  759. img2img_batch_input_dir,
  760. img2img_batch_output_dir,
  761. init_img,
  762. sketch,
  763. init_img_with_mask,
  764. inpaint_color_sketch,
  765. init_img_inpaint,
  766. ],
  767. outputs=[img2img_prompt, dummy_component],
  768. )
  769. img2img_prompt.submit(**img2img_args)
  770. submit.click(**img2img_args)
  771. res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False)
  772. restore_progress_button.click(
  773. fn=progress.restore_progress,
  774. _js="restoreProgressImg2img",
  775. inputs=[dummy_component],
  776. outputs=[
  777. img2img_gallery,
  778. generation_info,
  779. html_info,
  780. html_log,
  781. ],
  782. show_progress=False,
  783. )
  784. img2img_interrogate.click(
  785. fn=lambda *args: process_interrogate(interrogate, *args),
  786. **interrogate_args,
  787. )
  788. img2img_deepbooru.click(
  789. fn=lambda *args: process_interrogate(interrogate_deepbooru, *args),
  790. **interrogate_args,
  791. )
  792. prompts = [(txt2img_prompt, txt2img_negative_prompt), (img2img_prompt, img2img_negative_prompt)]
  793. style_dropdowns = [txt2img_prompt_styles, img2img_prompt_styles]
  794. style_js_funcs = ["update_txt2img_tokens", "update_img2img_tokens"]
  795. for button, (prompt, negative_prompt) in zip([txt2img_save_style, img2img_save_style], prompts):
  796. button.click(
  797. fn=add_style,
  798. _js="ask_for_style_name",
  799. # Have to pass empty dummy component here, because the JavaScript and Python function have to accept
  800. # the same number of parameters, but we only know the style-name after the JavaScript prompt
  801. inputs=[dummy_component, prompt, negative_prompt],
  802. outputs=[txt2img_prompt_styles, img2img_prompt_styles],
  803. )
  804. for button, (prompt, negative_prompt), styles, js_func in zip([txt2img_prompt_style_apply, img2img_prompt_style_apply], prompts, style_dropdowns, style_js_funcs):
  805. button.click(
  806. fn=apply_styles,
  807. _js=js_func,
  808. inputs=[prompt, negative_prompt, styles],
  809. outputs=[prompt, negative_prompt, styles],
  810. )
  811. token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter])
  812. negative_token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[img2img_negative_prompt, steps], outputs=[negative_token_counter])
  813. ui_extra_networks.setup_ui(extra_networks_ui_img2img, img2img_gallery)
  814. img2img_paste_fields = [
  815. (img2img_prompt, "Prompt"),
  816. (img2img_negative_prompt, "Negative prompt"),
  817. (steps, "Steps"),
  818. (sampler_index, "Sampler"),
  819. (restore_faces, "Face restoration"),
  820. (cfg_scale, "CFG scale"),
  821. (image_cfg_scale, "Image CFG scale"),
  822. (seed, "Seed"),
  823. (width, "Size-1"),
  824. (height, "Size-2"),
  825. (batch_size, "Batch size"),
  826. (subseed, "Variation seed"),
  827. (subseed_strength, "Variation seed strength"),
  828. (seed_resize_from_w, "Seed resize from-1"),
  829. (seed_resize_from_h, "Seed resize from-2"),
  830. (denoising_strength, "Denoising strength"),
  831. (mask_blur, "Mask blur"),
  832. *modules.scripts.scripts_img2img.infotext_fields
  833. ]
  834. parameters_copypaste.add_paste_fields("img2img", init_img, img2img_paste_fields, override_settings)
  835. parameters_copypaste.add_paste_fields("inpaint", init_img_with_mask, img2img_paste_fields, override_settings)
  836. parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding(
  837. paste_button=img2img_paste, tabname="img2img", source_text_component=img2img_prompt, source_image_component=None,
  838. ))
  839. modules.scripts.scripts_current = None
  840. with gr.Blocks(analytics_enabled=False) as extras_interface:
  841. ui_postprocessing.create_ui()
  842. with gr.Blocks(analytics_enabled=False) as pnginfo_interface:
  843. with gr.Row().style(equal_height=False):
  844. with gr.Column(variant='panel'):
  845. image = gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil")
  846. with gr.Column(variant='panel'):
  847. html = gr.HTML()
  848. generation_info = gr.Textbox(visible=False, elem_id="pnginfo_generation_info")
  849. html2 = gr.HTML()
  850. with gr.Row():
  851. buttons = parameters_copypaste.create_buttons(["txt2img", "img2img", "inpaint", "extras"])
  852. for tabname, button in buttons.items():
  853. parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding(
  854. paste_button=button, tabname=tabname, source_text_component=generation_info, source_image_component=image,
  855. ))
  856. image.change(
  857. fn=wrap_gradio_call(modules.extras.run_pnginfo),
  858. inputs=[image],
  859. outputs=[html, generation_info, html2],
  860. )
  861. def update_interp_description(value):
  862. interp_description_css = "<p style='margin-bottom: 2.5em'>{}</p>"
  863. interp_descriptions = {
  864. "No interpolation": interp_description_css.format("No interpolation will be used. Requires one model; A. Allows for format conversion and VAE baking."),
  865. "Weighted sum": interp_description_css.format("A weighted sum will be used for interpolation. Requires two models; A and B. The result is calculated as A * (1 - M) + B * M"),
  866. "Add difference": interp_description_css.format("The difference between the last two models will be added to the first. Requires three models; A, B and C. The result is calculated as A + (B - C) * M")
  867. }
  868. return interp_descriptions[value]
  869. with gr.Blocks(analytics_enabled=False) as modelmerger_interface:
  870. with gr.Row().style(equal_height=False):
  871. with gr.Column(variant='compact'):
  872. interp_description = gr.HTML(value=update_interp_description("Weighted sum"), elem_id="modelmerger_interp_description")
  873. with FormRow(elem_id="modelmerger_models"):
  874. primary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_primary_model_name", label="Primary model (A)")
  875. create_refresh_button(primary_model_name, modules.sd_models.list_models, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, "refresh_checkpoint_A")
  876. secondary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_secondary_model_name", label="Secondary model (B)")
  877. create_refresh_button(secondary_model_name, modules.sd_models.list_models, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, "refresh_checkpoint_B")
  878. tertiary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_tertiary_model_name", label="Tertiary model (C)")
  879. create_refresh_button(tertiary_model_name, modules.sd_models.list_models, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, "refresh_checkpoint_C")
  880. custom_name = gr.Textbox(label="Custom Name (Optional)", elem_id="modelmerger_custom_name")
  881. interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Multiplier (M) - set to 0 to get model A', value=0.3, elem_id="modelmerger_interp_amount")
  882. interp_method = gr.Radio(choices=["No interpolation", "Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method", elem_id="modelmerger_interp_method")
  883. interp_method.change(fn=update_interp_description, inputs=[interp_method], outputs=[interp_description])
  884. with FormRow():
  885. checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", label="Checkpoint format", elem_id="modelmerger_checkpoint_format")
  886. save_as_half = gr.Checkbox(value=False, label="Save as float16", elem_id="modelmerger_save_as_half")
  887. save_metadata = gr.Checkbox(value=True, label="Save metadata (.safetensors only)", elem_id="modelmerger_save_metadata")
  888. with FormRow():
  889. with gr.Column():
  890. config_source = gr.Radio(choices=["A, B or C", "B", "C", "Don't"], value="A, B or C", label="Copy config from", type="index", elem_id="modelmerger_config_method")
  891. with gr.Column():
  892. with FormRow():
  893. bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", label="Bake in VAE", elem_id="modelmerger_bake_in_vae")
  894. create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae")
  895. with FormRow():
  896. discard_weights = gr.Textbox(value="", label="Discard weights with matching name", elem_id="modelmerger_discard_weights")
  897. with gr.Row():
  898. modelmerger_merge = gr.Button(elem_id="modelmerger_merge", value="Merge", variant='primary')
  899. with gr.Column(variant='compact', elem_id="modelmerger_results_container"):
  900. with gr.Group(elem_id="modelmerger_results_panel"):
  901. modelmerger_result = gr.HTML(elem_id="modelmerger_result", show_label=False)
  902. with gr.Blocks(analytics_enabled=False) as train_interface:
  903. with gr.Row().style(equal_height=False):
  904. gr.HTML(value="<p style='margin-bottom: 0.7em'>See <b><a href=\"https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Textual-Inversion\">wiki</a></b> for detailed explanation.</p>")
  905. with gr.Row(variant="compact").style(equal_height=False):
  906. with gr.Tabs(elem_id="train_tabs"):
  907. with gr.Tab(label="Create embedding", id="create_embedding"):
  908. new_embedding_name = gr.Textbox(label="Name", elem_id="train_new_embedding_name")
  909. initialization_text = gr.Textbox(label="Initialization text", value="*", elem_id="train_initialization_text")
  910. nvpt = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1, elem_id="train_nvpt")
  911. overwrite_old_embedding = gr.Checkbox(value=False, label="Overwrite Old Embedding", elem_id="train_overwrite_old_embedding")
  912. with gr.Row():
  913. with gr.Column(scale=3):
  914. gr.HTML(value="")
  915. with gr.Column():
  916. create_embedding = gr.Button(value="Create embedding", variant='primary', elem_id="train_create_embedding")
  917. with gr.Tab(label="Create hypernetwork", id="create_hypernetwork"):
  918. new_hypernetwork_name = gr.Textbox(label="Name", elem_id="train_new_hypernetwork_name")
  919. new_hypernetwork_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "1024", "320", "640", "1280"], elem_id="train_new_hypernetwork_sizes")
  920. new_hypernetwork_layer_structure = gr.Textbox("1, 2, 1", label="Enter hypernetwork layer structure", placeholder="1st and last digit must be 1. ex:'1, 2, 1'", elem_id="train_new_hypernetwork_layer_structure")
  921. new_hypernetwork_activation_func = gr.Dropdown(value="linear", label="Select activation function of hypernetwork. Recommended : Swish / Linear(none)", choices=modules.hypernetworks.ui.keys, elem_id="train_new_hypernetwork_activation_func")
  922. new_hypernetwork_initialization_option = gr.Dropdown(value = "Normal", label="Select Layer weights initialization. Recommended: Kaiming for relu-like, Xavier for sigmoid-like, Normal otherwise", choices=["Normal", "KaimingUniform", "KaimingNormal", "XavierUniform", "XavierNormal"], elem_id="train_new_hypernetwork_initialization_option")
  923. new_hypernetwork_add_layer_norm = gr.Checkbox(label="Add layer normalization", elem_id="train_new_hypernetwork_add_layer_norm")
  924. new_hypernetwork_use_dropout = gr.Checkbox(label="Use dropout", elem_id="train_new_hypernetwork_use_dropout")
  925. new_hypernetwork_dropout_structure = gr.Textbox("0, 0, 0", label="Enter hypernetwork Dropout structure (or empty). Recommended : 0~0.35 incrementing sequence: 0, 0.05, 0.15", placeholder="1st and last digit must be 0 and values should be between 0 and 1. ex:'0, 0.01, 0'")
  926. overwrite_old_hypernetwork = gr.Checkbox(value=False, label="Overwrite Old Hypernetwork", elem_id="train_overwrite_old_hypernetwork")
  927. with gr.Row():
  928. with gr.Column(scale=3):
  929. gr.HTML(value="")
  930. with gr.Column():
  931. create_hypernetwork = gr.Button(value="Create hypernetwork", variant='primary', elem_id="train_create_hypernetwork")
  932. with gr.Tab(label="Preprocess images", id="preprocess_images"):
  933. process_src = gr.Textbox(label='Source directory', elem_id="train_process_src")
  934. process_dst = gr.Textbox(label='Destination directory', elem_id="train_process_dst")
  935. process_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="train_process_width")
  936. process_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="train_process_height")
  937. preprocess_txt_action = gr.Dropdown(label='Existing Caption txt Action', value="ignore", choices=["ignore", "copy", "prepend", "append"], elem_id="train_preprocess_txt_action")
  938. with gr.Row():
  939. process_keep_original_size = gr.Checkbox(label='Keep original size', elem_id="train_process_keep_original_size")
  940. process_flip = gr.Checkbox(label='Create flipped copies', elem_id="train_process_flip")
  941. process_split = gr.Checkbox(label='Split oversized images', elem_id="train_process_split")
  942. process_focal_crop = gr.Checkbox(label='Auto focal point crop', elem_id="train_process_focal_crop")
  943. process_multicrop = gr.Checkbox(label='Auto-sized crop', elem_id="train_process_multicrop")
  944. process_caption = gr.Checkbox(label='Use BLIP for caption', elem_id="train_process_caption")
  945. process_caption_deepbooru = gr.Checkbox(label='Use deepbooru for caption', visible=True, elem_id="train_process_caption_deepbooru")
  946. with gr.Row(visible=False) as process_split_extra_row:
  947. process_split_threshold = gr.Slider(label='Split image threshold', value=0.5, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_split_threshold")
  948. process_overlap_ratio = gr.Slider(label='Split image overlap ratio', value=0.2, minimum=0.0, maximum=0.9, step=0.05, elem_id="train_process_overlap_ratio")
  949. with gr.Row(visible=False) as process_focal_crop_row:
  950. process_focal_crop_face_weight = gr.Slider(label='Focal point face weight', value=0.9, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_face_weight")
  951. process_focal_crop_entropy_weight = gr.Slider(label='Focal point entropy weight', value=0.15, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_entropy_weight")
  952. process_focal_crop_edges_weight = gr.Slider(label='Focal point edges weight', value=0.5, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_edges_weight")
  953. process_focal_crop_debug = gr.Checkbox(label='Create debug image', elem_id="train_process_focal_crop_debug")
  954. with gr.Column(visible=False) as process_multicrop_col:
  955. gr.Markdown('Each image is center-cropped with an automatically chosen width and height.')
  956. with gr.Row():
  957. process_multicrop_mindim = gr.Slider(minimum=64, maximum=2048, step=8, label="Dimension lower bound", value=384, elem_id="train_process_multicrop_mindim")
  958. process_multicrop_maxdim = gr.Slider(minimum=64, maximum=2048, step=8, label="Dimension upper bound", value=768, elem_id="train_process_multicrop_maxdim")
  959. with gr.Row():
  960. process_multicrop_minarea = gr.Slider(minimum=64*64, maximum=2048*2048, step=1, label="Area lower bound", value=64*64, elem_id="train_process_multicrop_minarea")
  961. process_multicrop_maxarea = gr.Slider(minimum=64*64, maximum=2048*2048, step=1, label="Area upper bound", value=640*640, elem_id="train_process_multicrop_maxarea")
  962. with gr.Row():
  963. process_multicrop_objective = gr.Radio(["Maximize area", "Minimize error"], value="Maximize area", label="Resizing objective", elem_id="train_process_multicrop_objective")
  964. process_multicrop_threshold = gr.Slider(minimum=0, maximum=1, step=0.01, label="Error threshold", value=0.1, elem_id="train_process_multicrop_threshold")
  965. with gr.Row():
  966. with gr.Column(scale=3):
  967. gr.HTML(value="")
  968. with gr.Column():
  969. with gr.Row():
  970. interrupt_preprocessing = gr.Button("Interrupt", elem_id="train_interrupt_preprocessing")
  971. run_preprocess = gr.Button(value="Preprocess", variant='primary', elem_id="train_run_preprocess")
  972. process_split.change(
  973. fn=lambda show: gr_show(show),
  974. inputs=[process_split],
  975. outputs=[process_split_extra_row],
  976. )
  977. process_focal_crop.change(
  978. fn=lambda show: gr_show(show),
  979. inputs=[process_focal_crop],
  980. outputs=[process_focal_crop_row],
  981. )
  982. process_multicrop.change(
  983. fn=lambda show: gr_show(show),
  984. inputs=[process_multicrop],
  985. outputs=[process_multicrop_col],
  986. )
  987. def get_textual_inversion_template_names():
  988. return sorted([x for x in textual_inversion.textual_inversion_templates])
  989. with gr.Tab(label="Train", id="train"):
  990. gr.HTML(value="<p style='margin-bottom: 0.7em'>Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images <a href=\"https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Textual-Inversion\" style=\"font-weight:bold;\">[wiki]</a></p>")
  991. with FormRow():
  992. train_embedding_name = gr.Dropdown(label='Embedding', elem_id="train_embedding", choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys()))
  993. create_refresh_button(train_embedding_name, sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings, lambda: {"choices": sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())}, "refresh_train_embedding_name")
  994. train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', elem_id="train_hypernetwork", choices=[x for x in shared.hypernetworks.keys()])
  995. create_refresh_button(train_hypernetwork_name, shared.reload_hypernetworks, lambda: {"choices": sorted([x for x in shared.hypernetworks.keys()])}, "refresh_train_hypernetwork_name")
  996. with FormRow():
  997. embedding_learn_rate = gr.Textbox(label='Embedding Learning rate', placeholder="Embedding Learning rate", value="0.005", elem_id="train_embedding_learn_rate")
  998. hypernetwork_learn_rate = gr.Textbox(label='Hypernetwork Learning rate', placeholder="Hypernetwork Learning rate", value="0.00001", elem_id="train_hypernetwork_learn_rate")
  999. with FormRow():
  1000. clip_grad_mode = gr.Dropdown(value="disabled", label="Gradient Clipping", choices=["disabled", "value", "norm"])
  1001. clip_grad_value = gr.Textbox(placeholder="Gradient clip value", value="0.1", show_label=False)
  1002. with FormRow():
  1003. batch_size = gr.Number(label='Batch size', value=1, precision=0, elem_id="train_batch_size")
  1004. gradient_step = gr.Number(label='Gradient accumulation steps', value=1, precision=0, elem_id="train_gradient_step")
  1005. dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images", elem_id="train_dataset_directory")
  1006. log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion", elem_id="train_log_directory")
  1007. with FormRow():
  1008. template_file = gr.Dropdown(label='Prompt template', value="style_filewords.txt", elem_id="train_template_file", choices=get_textual_inversion_template_names())
  1009. create_refresh_button(template_file, textual_inversion.list_textual_inversion_templates, lambda: {"choices": get_textual_inversion_template_names()}, "refrsh_train_template_file")
  1010. training_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="train_training_width")
  1011. training_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="train_training_height")
  1012. varsize = gr.Checkbox(label="Do not resize images", value=False, elem_id="train_varsize")
  1013. steps = gr.Number(label='Max steps', value=100000, precision=0, elem_id="train_steps")
  1014. with FormRow():
  1015. create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0, elem_id="train_create_image_every")
  1016. save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0, elem_id="train_save_embedding_every")
  1017. use_weight = gr.Checkbox(label="Use PNG alpha channel as loss weight", value=False, elem_id="use_weight")
  1018. save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True, elem_id="train_save_image_with_stored_embedding")
  1019. preview_from_txt2img = gr.Checkbox(label='Read parameters (prompt, etc...) from txt2img tab when making previews', value=False, elem_id="train_preview_from_txt2img")
  1020. shuffle_tags = gr.Checkbox(label="Shuffle tags by ',' when creating prompts.", value=False, elem_id="train_shuffle_tags")
  1021. tag_drop_out = gr.Slider(minimum=0, maximum=1, step=0.1, label="Drop out tags when creating prompts.", value=0, elem_id="train_tag_drop_out")
  1022. latent_sampling_method = gr.Radio(label='Choose latent sampling method', value="once", choices=['once', 'deterministic', 'random'], elem_id="train_latent_sampling_method")
  1023. with gr.Row():
  1024. train_embedding = gr.Button(value="Train Embedding", variant='primary', elem_id="train_train_embedding")
  1025. interrupt_training = gr.Button(value="Interrupt", elem_id="train_interrupt_training")
  1026. train_hypernetwork = gr.Button(value="Train Hypernetwork", variant='primary', elem_id="train_train_hypernetwork")
  1027. params = script_callbacks.UiTrainTabParams(txt2img_preview_params)
  1028. script_callbacks.ui_train_tabs_callback(params)
  1029. with gr.Column(elem_id='ti_gallery_container'):
  1030. ti_output = gr.Text(elem_id="ti_output", value="", show_label=False)
  1031. ti_gallery = gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(columns=4)
  1032. ti_progress = gr.HTML(elem_id="ti_progress", value="")
  1033. ti_outcome = gr.HTML(elem_id="ti_error", value="")
  1034. create_embedding.click(
  1035. fn=modules.textual_inversion.ui.create_embedding,
  1036. inputs=[
  1037. new_embedding_name,
  1038. initialization_text,
  1039. nvpt,
  1040. overwrite_old_embedding,
  1041. ],
  1042. outputs=[
  1043. train_embedding_name,
  1044. ti_output,
  1045. ti_outcome,
  1046. ]
  1047. )
  1048. create_hypernetwork.click(
  1049. fn=modules.hypernetworks.ui.create_hypernetwork,
  1050. inputs=[
  1051. new_hypernetwork_name,
  1052. new_hypernetwork_sizes,
  1053. overwrite_old_hypernetwork,
  1054. new_hypernetwork_layer_structure,
  1055. new_hypernetwork_activation_func,
  1056. new_hypernetwork_initialization_option,
  1057. new_hypernetwork_add_layer_norm,
  1058. new_hypernetwork_use_dropout,
  1059. new_hypernetwork_dropout_structure
  1060. ],
  1061. outputs=[
  1062. train_hypernetwork_name,
  1063. ti_output,
  1064. ti_outcome,
  1065. ]
  1066. )
  1067. run_preprocess.click(
  1068. fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]),
  1069. _js="start_training_textual_inversion",
  1070. inputs=[
  1071. dummy_component,
  1072. process_src,
  1073. process_dst,
  1074. process_width,
  1075. process_height,
  1076. preprocess_txt_action,
  1077. process_keep_original_size,
  1078. process_flip,
  1079. process_split,
  1080. process_caption,
  1081. process_caption_deepbooru,
  1082. process_split_threshold,
  1083. process_overlap_ratio,
  1084. process_focal_crop,
  1085. process_focal_crop_face_weight,
  1086. process_focal_crop_entropy_weight,
  1087. process_focal_crop_edges_weight,
  1088. process_focal_crop_debug,
  1089. process_multicrop,
  1090. process_multicrop_mindim,
  1091. process_multicrop_maxdim,
  1092. process_multicrop_minarea,
  1093. process_multicrop_maxarea,
  1094. process_multicrop_objective,
  1095. process_multicrop_threshold,
  1096. ],
  1097. outputs=[
  1098. ti_output,
  1099. ti_outcome,
  1100. ],
  1101. )
  1102. train_embedding.click(
  1103. fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]),
  1104. _js="start_training_textual_inversion",
  1105. inputs=[
  1106. dummy_component,
  1107. train_embedding_name,
  1108. embedding_learn_rate,
  1109. batch_size,
  1110. gradient_step,
  1111. dataset_directory,
  1112. log_directory,
  1113. training_width,
  1114. training_height,
  1115. varsize,
  1116. steps,
  1117. clip_grad_mode,
  1118. clip_grad_value,
  1119. shuffle_tags,
  1120. tag_drop_out,
  1121. latent_sampling_method,
  1122. use_weight,
  1123. create_image_every,
  1124. save_embedding_every,
  1125. template_file,
  1126. save_image_with_stored_embedding,
  1127. preview_from_txt2img,
  1128. *txt2img_preview_params,
  1129. ],
  1130. outputs=[
  1131. ti_output,
  1132. ti_outcome,
  1133. ]
  1134. )
  1135. train_hypernetwork.click(
  1136. fn=wrap_gradio_gpu_call(modules.hypernetworks.ui.train_hypernetwork, extra_outputs=[gr.update()]),
  1137. _js="start_training_textual_inversion",
  1138. inputs=[
  1139. dummy_component,
  1140. train_hypernetwork_name,
  1141. hypernetwork_learn_rate,
  1142. batch_size,
  1143. gradient_step,
  1144. dataset_directory,
  1145. log_directory,
  1146. training_width,
  1147. training_height,
  1148. varsize,
  1149. steps,
  1150. clip_grad_mode,
  1151. clip_grad_value,
  1152. shuffle_tags,
  1153. tag_drop_out,
  1154. latent_sampling_method,
  1155. use_weight,
  1156. create_image_every,
  1157. save_embedding_every,
  1158. template_file,
  1159. preview_from_txt2img,
  1160. *txt2img_preview_params,
  1161. ],
  1162. outputs=[
  1163. ti_output,
  1164. ti_outcome,
  1165. ]
  1166. )
  1167. interrupt_training.click(
  1168. fn=lambda: shared.state.interrupt(),
  1169. inputs=[],
  1170. outputs=[],
  1171. )
  1172. interrupt_preprocessing.click(
  1173. fn=lambda: shared.state.interrupt(),
  1174. inputs=[],
  1175. outputs=[],
  1176. )
  1177. def create_setting_component(key, is_quicksettings=False):
  1178. def fun():
  1179. return opts.data[key] if key in opts.data else opts.data_labels[key].default
  1180. info = opts.data_labels[key]
  1181. t = type(info.default)
  1182. args = info.component_args() if callable(info.component_args) else info.component_args
  1183. if info.component is not None:
  1184. comp = info.component
  1185. elif t == str:
  1186. comp = gr.Textbox
  1187. elif t == int:
  1188. comp = gr.Number
  1189. elif t == bool:
  1190. comp = gr.Checkbox
  1191. else:
  1192. raise Exception(f'bad options item type: {t} for key {key}')
  1193. elem_id = f"setting_{key}"
  1194. if info.refresh is not None:
  1195. if is_quicksettings:
  1196. res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
  1197. create_refresh_button(res, info.refresh, info.component_args, f"refresh_{key}")
  1198. else:
  1199. with FormRow():
  1200. res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
  1201. create_refresh_button(res, info.refresh, info.component_args, f"refresh_{key}")
  1202. else:
  1203. res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
  1204. return res
  1205. components = []
  1206. component_dict = {}
  1207. shared.settings_components = component_dict
  1208. script_callbacks.ui_settings_callback()
  1209. opts.reorder()
  1210. def run_settings(*args):
  1211. changed = []
  1212. for key, value, comp in zip(opts.data_labels.keys(), args, components):
  1213. assert comp == dummy_component or opts.same_type(value, opts.data_labels[key].default), f"Bad value for setting {key}: {value}; expecting {type(opts.data_labels[key].default).__name__}"
  1214. for key, value, comp in zip(opts.data_labels.keys(), args, components):
  1215. if comp == dummy_component:
  1216. continue
  1217. if opts.set(key, value):
  1218. changed.append(key)
  1219. try:
  1220. opts.save(shared.config_filename)
  1221. except RuntimeError:
  1222. return opts.dumpjson(), f'{len(changed)} settings changed without save: {", ".join(changed)}.'
  1223. return opts.dumpjson(), f'{len(changed)} settings changed{": " if len(changed) > 0 else ""}{", ".join(changed)}.'
  1224. def run_settings_single(value, key):
  1225. if not opts.same_type(value, opts.data_labels[key].default):
  1226. return gr.update(visible=True), opts.dumpjson()
  1227. if not opts.set(key, value):
  1228. return gr.update(value=getattr(opts, key)), opts.dumpjson()
  1229. opts.save(shared.config_filename)
  1230. return get_value_for_setting(key), opts.dumpjson()
  1231. with gr.Blocks(analytics_enabled=False) as settings_interface:
  1232. with gr.Row():
  1233. with gr.Column(scale=6):
  1234. settings_submit = gr.Button(value="Apply settings", variant='primary', elem_id="settings_submit")
  1235. with gr.Column():
  1236. restart_gradio = gr.Button(value='Reload UI', variant='primary', elem_id="settings_restart_gradio")
  1237. result = gr.HTML(elem_id="settings_result")
  1238. quicksettings_names = opts.quicksettings_list
  1239. quicksettings_names = {x: i for i, x in enumerate(quicksettings_names) if x != 'quicksettings'}
  1240. quicksettings_list = []
  1241. previous_section = None
  1242. current_tab = None
  1243. current_row = None
  1244. with gr.Tabs(elem_id="settings"):
  1245. for i, (k, item) in enumerate(opts.data_labels.items()):
  1246. section_must_be_skipped = item.section[0] is None
  1247. if previous_section != item.section and not section_must_be_skipped:
  1248. elem_id, text = item.section
  1249. if current_tab is not None:
  1250. current_row.__exit__()
  1251. current_tab.__exit__()
  1252. gr.Group()
  1253. current_tab = gr.TabItem(elem_id=f"settings_{elem_id}", label=text)
  1254. current_tab.__enter__()
  1255. current_row = gr.Column(variant='compact')
  1256. current_row.__enter__()
  1257. previous_section = item.section
  1258. if k in quicksettings_names and not shared.cmd_opts.freeze_settings:
  1259. quicksettings_list.append((i, k, item))
  1260. components.append(dummy_component)
  1261. elif section_must_be_skipped:
  1262. components.append(dummy_component)
  1263. else:
  1264. component = create_setting_component(k)
  1265. component_dict[k] = component
  1266. components.append(component)
  1267. if current_tab is not None:
  1268. current_row.__exit__()
  1269. current_tab.__exit__()
  1270. with gr.TabItem("Actions", id="actions", elem_id="settings_tab_actions"):
  1271. request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications")
  1272. download_localization = gr.Button(value='Download localization template', elem_id="download_localization")
  1273. reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary', elem_id="settings_reload_script_bodies")
  1274. with gr.Row():
  1275. unload_sd_model = gr.Button(value='Unload SD checkpoint to free VRAM', elem_id="sett_unload_sd_model")
  1276. reload_sd_model = gr.Button(value='Reload the last SD checkpoint back into VRAM', elem_id="sett_reload_sd_model")
  1277. with gr.TabItem("Licenses", id="licenses", elem_id="settings_tab_licenses"):
  1278. gr.HTML(shared.html("licenses.html"), elem_id="licenses")
  1279. gr.Button(value="Show all pages", elem_id="settings_show_all_pages")
  1280. def unload_sd_weights():
  1281. modules.sd_models.unload_model_weights()
  1282. def reload_sd_weights():
  1283. modules.sd_models.reload_model_weights()
  1284. unload_sd_model.click(
  1285. fn=unload_sd_weights,
  1286. inputs=[],
  1287. outputs=[]
  1288. )
  1289. reload_sd_model.click(
  1290. fn=reload_sd_weights,
  1291. inputs=[],
  1292. outputs=[]
  1293. )
  1294. request_notifications.click(
  1295. fn=lambda: None,
  1296. inputs=[],
  1297. outputs=[],
  1298. _js='function(){}'
  1299. )
  1300. download_localization.click(
  1301. fn=lambda: None,
  1302. inputs=[],
  1303. outputs=[],
  1304. _js='download_localization'
  1305. )
  1306. def reload_scripts():
  1307. modules.scripts.reload_script_body_only()
  1308. reload_javascript() # need to refresh the html page
  1309. reload_script_bodies.click(
  1310. fn=reload_scripts,
  1311. inputs=[],
  1312. outputs=[]
  1313. )
  1314. def request_restart():
  1315. shared.state.interrupt()
  1316. shared.state.need_restart = True
  1317. restart_gradio.click(
  1318. fn=request_restart,
  1319. _js='restart_reload',
  1320. inputs=[],
  1321. outputs=[],
  1322. )
  1323. interfaces = [
  1324. (txt2img_interface, "txt2img", "txt2img"),
  1325. (img2img_interface, "img2img", "img2img"),
  1326. (extras_interface, "Extras", "extras"),
  1327. (pnginfo_interface, "PNG Info", "pnginfo"),
  1328. (modelmerger_interface, "Checkpoint Merger", "modelmerger"),
  1329. (train_interface, "Train", "ti"),
  1330. ]
  1331. interfaces += script_callbacks.ui_tabs_callback()
  1332. interfaces += [(settings_interface, "Settings", "settings")]
  1333. extensions_interface = ui_extensions.create_ui()
  1334. interfaces += [(extensions_interface, "Extensions", "extensions")]
  1335. shared.tab_names = []
  1336. for _interface, label, _ifid in interfaces:
  1337. shared.tab_names.append(label)
  1338. with gr.Blocks(theme=shared.gradio_theme, analytics_enabled=False, title="Stable Diffusion") as demo:
  1339. with gr.Row(elem_id="quicksettings", variant="compact"):
  1340. for i, k, item in sorted(quicksettings_list, key=lambda x: quicksettings_names.get(x[1], x[0])):
  1341. component = create_setting_component(k, is_quicksettings=True)
  1342. component_dict[k] = component
  1343. parameters_copypaste.connect_paste_params_buttons()
  1344. with gr.Tabs(elem_id="tabs") as tabs:
  1345. for interface, label, ifid in interfaces:
  1346. if label in shared.opts.hidden_tabs:
  1347. continue
  1348. with gr.TabItem(label, id=ifid, elem_id=f"tab_{ifid}"):
  1349. interface.render()
  1350. if os.path.exists(os.path.join(script_path, "notification.mp3")):
  1351. audio_notification = gr.Audio(interactive=False, value=os.path.join(script_path, "notification.mp3"), elem_id="audio_notification", visible=False)
  1352. footer = shared.html("footer.html")
  1353. footer = footer.format(versions=versions_html())
  1354. gr.HTML(footer, elem_id="footer")
  1355. text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False)
  1356. settings_submit.click(
  1357. fn=wrap_gradio_call(run_settings, extra_outputs=[gr.update()]),
  1358. inputs=components,
  1359. outputs=[text_settings, result],
  1360. )
  1361. for i, k, item in quicksettings_list:
  1362. component = component_dict[k]
  1363. info = opts.data_labels[k]
  1364. change_handler = component.release if hasattr(component, 'release') else component.change
  1365. change_handler(
  1366. fn=lambda value, k=k: run_settings_single(value, key=k),
  1367. inputs=[component],
  1368. outputs=[component, text_settings],
  1369. show_progress=info.refresh is not None,
  1370. )
  1371. update_image_cfg_scale_visibility = lambda: gr.update(visible=shared.sd_model and shared.sd_model.cond_stage_key == "edit")
  1372. text_settings.change(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale])
  1373. demo.load(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale])
  1374. button_set_checkpoint = gr.Button('Change checkpoint', elem_id='change_checkpoint', visible=False)
  1375. button_set_checkpoint.click(
  1376. fn=lambda value, _: run_settings_single(value, key='sd_model_checkpoint'),
  1377. _js="function(v){ var res = desiredCheckpointName; desiredCheckpointName = ''; return [res || v, null]; }",
  1378. inputs=[component_dict['sd_model_checkpoint'], dummy_component],
  1379. outputs=[component_dict['sd_model_checkpoint'], text_settings],
  1380. )
  1381. component_keys = [k for k in opts.data_labels.keys() if k in component_dict]
  1382. def get_settings_values():
  1383. return [get_value_for_setting(key) for key in component_keys]
  1384. demo.load(
  1385. fn=get_settings_values,
  1386. inputs=[],
  1387. outputs=[component_dict[k] for k in component_keys],
  1388. queue=False,
  1389. )
  1390. def modelmerger(*args):
  1391. try:
  1392. results = modules.extras.run_modelmerger(*args)
  1393. except Exception as e:
  1394. print("Error loading/saving model file:", file=sys.stderr)
  1395. print(traceback.format_exc(), file=sys.stderr)
  1396. modules.sd_models.list_models() # to remove the potentially missing models from the list
  1397. return [*[gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"]
  1398. return results
  1399. modelmerger_merge.click(fn=lambda: '', inputs=[], outputs=[modelmerger_result])
  1400. modelmerger_merge.click(
  1401. fn=wrap_gradio_gpu_call(modelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]),
  1402. _js='modelmerger',
  1403. inputs=[
  1404. dummy_component,
  1405. primary_model_name,
  1406. secondary_model_name,
  1407. tertiary_model_name,
  1408. interp_method,
  1409. interp_amount,
  1410. save_as_half,
  1411. custom_name,
  1412. checkpoint_format,
  1413. config_source,
  1414. bake_in_vae,
  1415. discard_weights,
  1416. save_metadata,
  1417. ],
  1418. outputs=[
  1419. primary_model_name,
  1420. secondary_model_name,
  1421. tertiary_model_name,
  1422. component_dict['sd_model_checkpoint'],
  1423. modelmerger_result,
  1424. ]
  1425. )
  1426. ui_config_file = cmd_opts.ui_config_file
  1427. ui_settings = {}
  1428. settings_count = len(ui_settings)
  1429. error_loading = False
  1430. try:
  1431. if os.path.exists(ui_config_file):
  1432. with open(ui_config_file, "r", encoding="utf8") as file:
  1433. ui_settings = json.load(file)
  1434. except Exception:
  1435. error_loading = True
  1436. print("Error loading settings:", file=sys.stderr)
  1437. print(traceback.format_exc(), file=sys.stderr)
  1438. def loadsave(path, x):
  1439. def apply_field(obj, field, condition=None, init_field=None):
  1440. key = f"{path}/{field}"
  1441. if getattr(obj, 'custom_script_source', None) is not None:
  1442. key = f"customscript/{obj.custom_script_source}/{key}"
  1443. if getattr(obj, 'do_not_save_to_config', False):
  1444. return
  1445. saved_value = ui_settings.get(key, None)
  1446. if saved_value is None:
  1447. ui_settings[key] = getattr(obj, field)
  1448. elif condition and not condition(saved_value):
  1449. pass
  1450. # this warning is generally not useful;
  1451. # print(f'Warning: Bad ui setting value: {key}: {saved_value}; Default value "{getattr(obj, field)}" will be used instead.')
  1452. else:
  1453. setattr(obj, field, saved_value)
  1454. if init_field is not None:
  1455. init_field(saved_value)
  1456. if type(x) in [gr.Slider, gr.Radio, gr.Checkbox, gr.Textbox, gr.Number, gr.Dropdown, ToolButton] and x.visible:
  1457. apply_field(x, 'visible')
  1458. if type(x) == gr.Slider:
  1459. apply_field(x, 'value')
  1460. apply_field(x, 'minimum')
  1461. apply_field(x, 'maximum')
  1462. apply_field(x, 'step')
  1463. if type(x) == gr.Radio:
  1464. apply_field(x, 'value', lambda val: val in x.choices)
  1465. if type(x) == gr.Checkbox:
  1466. apply_field(x, 'value')
  1467. if type(x) == gr.Textbox:
  1468. apply_field(x, 'value')
  1469. if type(x) == gr.Number:
  1470. apply_field(x, 'value')
  1471. if type(x) == gr.Dropdown:
  1472. def check_dropdown(val):
  1473. if getattr(x, 'multiselect', False):
  1474. return all([value in x.choices for value in val])
  1475. else:
  1476. return val in x.choices
  1477. apply_field(x, 'value', check_dropdown, getattr(x, 'init_field', None))
  1478. def check_tab_id(tab_id):
  1479. tab_items = list(filter(lambda e: isinstance(e, gr.TabItem), x.children))
  1480. if type(tab_id) == str:
  1481. tab_ids = [t.id for t in tab_items]
  1482. return tab_id in tab_ids
  1483. elif type(tab_id) == int:
  1484. return tab_id >= 0 and tab_id < len(tab_items)
  1485. else:
  1486. return False
  1487. if type(x) == gr.Tabs:
  1488. apply_field(x, 'selected', check_tab_id)
  1489. visit(txt2img_interface, loadsave, "txt2img")
  1490. visit(img2img_interface, loadsave, "img2img")
  1491. visit(extras_interface, loadsave, "extras")
  1492. visit(modelmerger_interface, loadsave, "modelmerger")
  1493. visit(train_interface, loadsave, "train")
  1494. loadsave(f"webui/Tabs@{tabs.elem_id}", tabs)
  1495. if not error_loading and (not os.path.exists(ui_config_file) or settings_count != len(ui_settings)):
  1496. with open(ui_config_file, "w", encoding="utf8") as file:
  1497. json.dump(ui_settings, file, indent=4)
  1498. # Required as a workaround for change() event not triggering when loading values from ui-config.json
  1499. interp_description.value = update_interp_description(interp_method.value)
  1500. return demo
  1501. def webpath(fn):
  1502. if fn.startswith(script_path):
  1503. web_path = os.path.relpath(fn, script_path).replace('\\', '/')
  1504. else:
  1505. web_path = os.path.abspath(fn)
  1506. return f'file={web_path}?{os.path.getmtime(fn)}'
  1507. def javascript_html():
  1508. # Ensure localization is in `window` before scripts
  1509. head = f'<script type="text/javascript">{localization.localization_js(shared.opts.localization)}</script>\n'
  1510. script_js = os.path.join(script_path, "script.js")
  1511. head += f'<script type="text/javascript" src="{webpath(script_js)}"></script>\n'
  1512. for script in modules.scripts.list_scripts("javascript", ".js"):
  1513. head += f'<script type="text/javascript" src="{webpath(script.path)}"></script>\n'
  1514. for script in modules.scripts.list_scripts("javascript", ".mjs"):
  1515. head += f'<script type="module" src="{webpath(script.path)}"></script>\n'
  1516. if cmd_opts.theme:
  1517. head += f'<script type="text/javascript">set_theme(\"{cmd_opts.theme}\");</script>\n'
  1518. return head
  1519. def css_html():
  1520. head = ""
  1521. def stylesheet(fn):
  1522. return f'<link rel="stylesheet" property="stylesheet" href="{webpath(fn)}">'
  1523. for cssfile in modules.scripts.list_files_with_name("style.css"):
  1524. if not os.path.isfile(cssfile):
  1525. continue
  1526. head += stylesheet(cssfile)
  1527. if os.path.exists(os.path.join(data_path, "user.css")):
  1528. head += stylesheet(os.path.join(data_path, "user.css"))
  1529. return head
  1530. def reload_javascript():
  1531. js = javascript_html()
  1532. css = css_html()
  1533. def template_response(*args, **kwargs):
  1534. res = shared.GradioTemplateResponseOriginal(*args, **kwargs)
  1535. res.body = res.body.replace(b'</head>', f'{js}</head>'.encode("utf8"))
  1536. res.body = res.body.replace(b'</body>', f'{css}</body>'.encode("utf8"))
  1537. res.init_headers()
  1538. return res
  1539. gradio.routes.templates.TemplateResponse = template_response
  1540. if not hasattr(shared, 'GradioTemplateResponseOriginal'):
  1541. shared.GradioTemplateResponseOriginal = gradio.routes.templates.TemplateResponse
  1542. def versions_html():
  1543. import torch
  1544. import launch
  1545. python_version = ".".join([str(x) for x in sys.version_info[0:3]])
  1546. commit = launch.commit_hash()
  1547. tag = launch.git_tag()
  1548. if shared.xformers_available:
  1549. import xformers
  1550. xformers_version = xformers.__version__
  1551. else:
  1552. xformers_version = "N/A"
  1553. return f"""
  1554. version: <a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui/commit/{commit}">{tag}</a>
  1555.  • 
  1556. python: <span title="{sys.version}">{python_version}</span>
  1557.  • 
  1558. torch: {getattr(torch, '__long_version__',torch.__version__)}
  1559.  • 
  1560. xformers: {xformers_version}
  1561.  • 
  1562. gradio: {gr.__version__}
  1563.  • 
  1564. checkpoint: <a id="sd_checkpoint_hash">N/A</a>
  1565. """
  1566. def setup_ui_api(app):
  1567. from pydantic import BaseModel, Field
  1568. from typing import List
  1569. class QuicksettingsHint(BaseModel):
  1570. name: str = Field(title="Name of the quicksettings field")
  1571. label: str = Field(title="Label of the quicksettings field")
  1572. def quicksettings_hint():
  1573. return [QuicksettingsHint(name=k, label=v.label) for k, v in opts.data_labels.items()]
  1574. app.add_api_route("/internal/quicksettings-hint", quicksettings_hint, methods=["GET"], response_model=List[QuicksettingsHint])
  1575. app.add_api_route("/internal/ping", lambda: {}, methods=["GET"])