ui.py 92 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911
  1. import html
  2. import json
  3. import math
  4. import mimetypes
  5. import os
  6. import platform
  7. import random
  8. import subprocess as sp
  9. import sys
  10. import tempfile
  11. import time
  12. import traceback
  13. from functools import partial, reduce
  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
  21. from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML
  22. from modules.paths import script_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. import modules.textual_inversion.ui
  37. import modules.hypernetworks.ui
  38. from modules.generation_parameters_copypaste import image_from_url_text
  39. # 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
  40. mimetypes.init()
  41. mimetypes.add_type('application/javascript', '.js')
  42. if not cmd_opts.share and not cmd_opts.listen:
  43. # fix gradio phoning home
  44. gradio.utils.version_check = lambda: None
  45. gradio.utils.get_local_ip_address = lambda: '127.0.0.1'
  46. if cmd_opts.ngrok is not None:
  47. import modules.ngrok as ngrok
  48. print('ngrok authtoken detected, trying to connect...')
  49. ngrok.connect(
  50. cmd_opts.ngrok,
  51. cmd_opts.port if cmd_opts.port is not None else 7860,
  52. cmd_opts.ngrok_region
  53. )
  54. def gr_show(visible=True):
  55. return {"visible": visible, "__type__": "update"}
  56. sample_img2img = "assets/stable-samples/img2img/sketch-mountains-input.jpg"
  57. sample_img2img = sample_img2img if os.path.exists(sample_img2img) else None
  58. css_hide_progressbar = """
  59. .wrap .m-12 svg { display:none!important; }
  60. .wrap .m-12::before { content:"Loading..." }
  61. .wrap .z-20 svg { display:none!important; }
  62. .wrap .z-20::before { content:"Loading..." }
  63. .progress-bar { display:none!important; }
  64. .meta-text { display:none!important; }
  65. .meta-text-center { display:none!important; }
  66. """
  67. # Using constants for these since the variation selector isn't visible.
  68. # Important that they exactly match script.js for tooltip to work.
  69. random_symbol = '\U0001f3b2\ufe0f' # 🎲️
  70. reuse_symbol = '\u267b\ufe0f' # ♻️
  71. paste_symbol = '\u2199\ufe0f' # ↙
  72. folder_symbol = '\U0001f4c2' # 📂
  73. refresh_symbol = '\U0001f504' # 🔄
  74. save_style_symbol = '\U0001f4be' # 💾
  75. apply_style_symbol = '\U0001f4cb' # 📋
  76. clear_prompt_symbol = '\U0001F5D1' # 🗑️
  77. def plaintext_to_html(text):
  78. text = "<p>" + "<br>\n".join([f"{html.escape(x)}" for x in text.split('\n')]) + "</p>"
  79. return text
  80. def send_gradio_gallery_to_image(x):
  81. if len(x) == 0:
  82. return None
  83. return image_from_url_text(x[0])
  84. def save_files(js_data, images, do_make_zip, index):
  85. import csv
  86. filenames = []
  87. fullfns = []
  88. #quick dictionary to class object conversion. Its necessary due apply_filename_pattern requiring it
  89. class MyObject:
  90. def __init__(self, d=None):
  91. if d is not None:
  92. for key, value in d.items():
  93. setattr(self, key, value)
  94. data = json.loads(js_data)
  95. p = MyObject(data)
  96. path = opts.outdir_save
  97. save_to_dirs = opts.use_save_to_dirs_for_ui
  98. extension: str = opts.samples_format
  99. start_index = 0
  100. if index > -1 and opts.save_selected_only and (index >= data["index_of_first_image"]): # ensures we are looking at a specific non-grid picture, and we have save_selected_only
  101. images = [images[index]]
  102. start_index = index
  103. os.makedirs(opts.outdir_save, exist_ok=True)
  104. with open(os.path.join(opts.outdir_save, "log.csv"), "a", encoding="utf8", newline='') as file:
  105. at_start = file.tell() == 0
  106. writer = csv.writer(file)
  107. if at_start:
  108. writer.writerow(["prompt", "seed", "width", "height", "sampler", "cfgs", "steps", "filename", "negative_prompt"])
  109. for image_index, filedata in enumerate(images, start_index):
  110. image = image_from_url_text(filedata)
  111. is_grid = image_index < p.index_of_first_image
  112. i = 0 if is_grid else (image_index - p.index_of_first_image)
  113. fullfn, txt_fullfn = save_image(image, path, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs)
  114. filename = os.path.relpath(fullfn, path)
  115. filenames.append(filename)
  116. fullfns.append(fullfn)
  117. if txt_fullfn:
  118. filenames.append(os.path.basename(txt_fullfn))
  119. fullfns.append(txt_fullfn)
  120. writer.writerow([data["prompt"], data["seed"], data["width"], data["height"], data["sampler_name"], data["cfg_scale"], data["steps"], filenames[0], data["negative_prompt"]])
  121. # Make Zip
  122. if do_make_zip:
  123. zip_filepath = os.path.join(path, "images.zip")
  124. from zipfile import ZipFile
  125. with ZipFile(zip_filepath, "w") as zip_file:
  126. for i in range(len(fullfns)):
  127. with open(fullfns[i], mode="rb") as f:
  128. zip_file.writestr(filenames[i], f.read())
  129. fullfns.insert(0, zip_filepath)
  130. return gr.File.update(value=fullfns, visible=True), plaintext_to_html(f"Saved: {filenames[0]}")
  131. def calc_time_left(progress, threshold, label, force_display, show_eta):
  132. if progress == 0:
  133. return ""
  134. else:
  135. time_since_start = time.time() - shared.state.time_start
  136. eta = (time_since_start/progress)
  137. eta_relative = eta-time_since_start
  138. if (eta_relative > threshold and show_eta) or force_display:
  139. if eta_relative > 3600:
  140. return label + time.strftime('%H:%M:%S', time.gmtime(eta_relative))
  141. elif eta_relative > 60:
  142. return label + time.strftime('%M:%S', time.gmtime(eta_relative))
  143. else:
  144. return label + time.strftime('%Ss', time.gmtime(eta_relative))
  145. else:
  146. return ""
  147. def check_progress_call(id_part):
  148. if shared.state.job_count == 0:
  149. return "", gr_show(False), gr_show(False), gr_show(False)
  150. progress = 0
  151. if shared.state.job_count > 0:
  152. progress += shared.state.job_no / shared.state.job_count
  153. if shared.state.sampling_steps > 0:
  154. progress += 1 / shared.state.job_count * shared.state.sampling_step / shared.state.sampling_steps
  155. # Show progress percentage and time left at the same moment, and base it also on steps done
  156. show_eta = progress >= 0.01 or shared.state.sampling_step >= 10
  157. time_left = calc_time_left(progress, 1, " ETA: ", shared.state.time_left_force_display, show_eta)
  158. if time_left != "":
  159. shared.state.time_left_force_display = True
  160. progress = min(progress, 1)
  161. progressbar = ""
  162. if opts.show_progressbar:
  163. progressbar = f"""<div class='progressDiv'><div class='progress' style="overflow:visible;width:{progress * 100}%;white-space:nowrap;">{"&nbsp;" * 2 + str(int(progress*100))+"%" + time_left if show_eta else ""}</div></div>"""
  164. image = gr_show(False)
  165. preview_visibility = gr_show(False)
  166. if opts.show_progress_every_n_steps != 0:
  167. shared.state.set_current_image()
  168. image = shared.state.current_image
  169. if image is None:
  170. image = gr.update(value=None)
  171. else:
  172. preview_visibility = gr_show(True)
  173. if shared.state.textinfo is not None:
  174. textinfo_result = gr.HTML.update(value=shared.state.textinfo, visible=True)
  175. else:
  176. textinfo_result = gr_show(False)
  177. return f"<span id='{id_part}_progress_span' style='display: none'>{time.time()}</span><p>{progressbar}</p>", preview_visibility, image, textinfo_result
  178. def check_progress_call_initial(id_part):
  179. shared.state.job_count = -1
  180. shared.state.current_latent = None
  181. shared.state.current_image = None
  182. shared.state.textinfo = None
  183. shared.state.time_start = time.time()
  184. shared.state.time_left_force_display = False
  185. return check_progress_call(id_part)
  186. def visit(x, func, path=""):
  187. if hasattr(x, 'children'):
  188. for c in x.children:
  189. visit(c, func, path)
  190. elif x.label is not None:
  191. func(path + "/" + str(x.label), x)
  192. def add_style(name: str, prompt: str, negative_prompt: str):
  193. if name is None:
  194. return [gr_show() for x in range(4)]
  195. style = modules.styles.PromptStyle(name, prompt, negative_prompt)
  196. shared.prompt_styles.styles[style.name] = style
  197. # Save all loaded prompt styles: this allows us to update the storage format in the future more easily, because we
  198. # reserialize all styles every time we save them
  199. shared.prompt_styles.save_styles(shared.styles_filename)
  200. return [gr.Dropdown.update(visible=True, choices=list(shared.prompt_styles.styles)) for _ in range(4)]
  201. def calc_resolution_hires(enable, width, height, hr_scale, hr_resize_x, hr_resize_y):
  202. from modules import processing, devices
  203. if not enable:
  204. return ""
  205. 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)
  206. with devices.autocast():
  207. p.init([""], [0], [0])
  208. return f"resize: from <span class='resolution'>{width}x{height}</span> to <span class='resolution'>{p.hr_upscale_to_x}x{p.hr_upscale_to_y}</span>"
  209. def apply_styles(prompt, prompt_neg, style1_name, style2_name):
  210. prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, [style1_name, style2_name])
  211. prompt_neg = shared.prompt_styles.apply_negative_styles_to_prompt(prompt_neg, [style1_name, style2_name])
  212. return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=prompt_neg), gr.Dropdown.update(value="None"), gr.Dropdown.update(value="None")]
  213. def interrogate(image):
  214. prompt = shared.interrogator.interrogate(image.convert("RGB"))
  215. return gr_show(True) if prompt is None else prompt
  216. def interrogate_deepbooru(image):
  217. prompt = deepbooru.model.tag(image)
  218. return gr_show(True) if prompt is None else prompt
  219. def create_seed_inputs(target_interface):
  220. with FormRow(elem_id=target_interface + '_seed_row'):
  221. seed = (gr.Textbox if cmd_opts.use_textbox_seed else gr.Number)(label='Seed', value=-1, elem_id=target_interface + '_seed')
  222. seed.style(container=False)
  223. random_seed = gr.Button(random_symbol, elem_id=target_interface + '_random_seed')
  224. reuse_seed = gr.Button(reuse_symbol, elem_id=target_interface + '_reuse_seed')
  225. with gr.Group(elem_id=target_interface + '_subseed_show_box'):
  226. seed_checkbox = gr.Checkbox(label='Extra', elem_id=target_interface + '_subseed_show', value=False)
  227. # Components to show/hide based on the 'Extra' checkbox
  228. seed_extras = []
  229. with FormRow(visible=False, elem_id=target_interface + '_subseed_row') as seed_extra_row_1:
  230. seed_extras.append(seed_extra_row_1)
  231. subseed = gr.Number(label='Variation seed', value=-1, elem_id=target_interface + '_subseed')
  232. subseed.style(container=False)
  233. random_subseed = gr.Button(random_symbol, elem_id=target_interface + '_random_subseed')
  234. reuse_subseed = gr.Button(reuse_symbol, elem_id=target_interface + '_reuse_subseed')
  235. subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=target_interface + '_subseed_strength')
  236. with FormRow(visible=False) as seed_extra_row_2:
  237. seed_extras.append(seed_extra_row_2)
  238. seed_resize_from_w = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize seed from width", value=0, elem_id=target_interface + '_seed_resize_from_w')
  239. seed_resize_from_h = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize seed from height", value=0, elem_id=target_interface + '_seed_resize_from_h')
  240. random_seed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[seed])
  241. random_subseed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[subseed])
  242. def change_visibility(show):
  243. return {comp: gr_show(show) for comp in seed_extras}
  244. seed_checkbox.change(change_visibility, show_progress=False, inputs=[seed_checkbox], outputs=seed_extras)
  245. return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox
  246. def connect_clear_prompt(button):
  247. """Given clear button, prompt, and token_counter objects, setup clear prompt button click event"""
  248. button.click(
  249. _js="clear_prompt",
  250. fn=None,
  251. inputs=[],
  252. outputs=[],
  253. )
  254. def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: gr.Textbox, dummy_component, is_subseed):
  255. """ Connects a 'reuse (sub)seed' button's click event so that it copies last used
  256. (sub)seed value from generation info the to the seed field. If copying subseed and subseed strength
  257. was 0, i.e. no variation seed was used, it copies the normal seed value instead."""
  258. def copy_seed(gen_info_string: str, index):
  259. res = -1
  260. try:
  261. gen_info = json.loads(gen_info_string)
  262. index -= gen_info.get('index_of_first_image', 0)
  263. if is_subseed and gen_info.get('subseed_strength', 0) > 0:
  264. all_subseeds = gen_info.get('all_subseeds', [-1])
  265. res = all_subseeds[index if 0 <= index < len(all_subseeds) else 0]
  266. else:
  267. all_seeds = gen_info.get('all_seeds', [-1])
  268. res = all_seeds[index if 0 <= index < len(all_seeds) else 0]
  269. except json.decoder.JSONDecodeError as e:
  270. if gen_info_string != '':
  271. print("Error parsing JSON generation info:", file=sys.stderr)
  272. print(gen_info_string, file=sys.stderr)
  273. return [res, gr_show(False)]
  274. reuse_seed.click(
  275. fn=copy_seed,
  276. _js="(x, y) => [x, selected_gallery_index()]",
  277. show_progress=False,
  278. inputs=[generation_info, dummy_component],
  279. outputs=[seed, dummy_component]
  280. )
  281. def update_token_counter(text, steps):
  282. try:
  283. _, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
  284. prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)
  285. except Exception:
  286. # a parsing error can happen here during typing, and we don't want to bother the user with
  287. # messages related to it in console
  288. prompt_schedules = [[[steps, text]]]
  289. flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules)
  290. prompts = [prompt_text for step, prompt_text in flat_prompts]
  291. token_count, max_length = max([model_hijack.get_prompt_lengths(prompt) for prompt in prompts], key=lambda args: args[0])
  292. style_class = ' class="red"' if (token_count > max_length) else ""
  293. return f"<span {style_class}>{token_count}/{max_length}</span>"
  294. def create_toprow(is_img2img):
  295. id_part = "img2img" if is_img2img else "txt2img"
  296. with gr.Row(elem_id="toprow"):
  297. with gr.Column(scale=6):
  298. with gr.Row():
  299. with gr.Column(scale=80):
  300. with gr.Row():
  301. prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, lines=2,
  302. placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)"
  303. )
  304. with gr.Row():
  305. with gr.Column(scale=80):
  306. with gr.Row():
  307. negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=2,
  308. placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)"
  309. )
  310. with gr.Column(scale=1, elem_id="roll_col"):
  311. paste = gr.Button(value=paste_symbol, elem_id="paste")
  312. save_style = gr.Button(value=save_style_symbol, elem_id="style_create")
  313. prompt_style_apply = gr.Button(value=apply_style_symbol, elem_id="style_apply")
  314. clear_prompt_button = gr.Button(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt")
  315. token_counter = gr.HTML(value="<span></span>", elem_id=f"{id_part}_token_counter")
  316. token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")
  317. clear_prompt_button.click(
  318. fn=lambda *x: x,
  319. _js="confirm_clear_prompt",
  320. inputs=[prompt, negative_prompt],
  321. outputs=[prompt, negative_prompt],
  322. )
  323. button_interrogate = None
  324. button_deepbooru = None
  325. if is_img2img:
  326. with gr.Column(scale=1, elem_id="interrogate_col"):
  327. button_interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate")
  328. button_deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru")
  329. with gr.Column(scale=1):
  330. with gr.Row():
  331. skip = gr.Button('Skip', elem_id=f"{id_part}_skip")
  332. interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt")
  333. submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary')
  334. skip.click(
  335. fn=lambda: shared.state.skip(),
  336. inputs=[],
  337. outputs=[],
  338. )
  339. interrupt.click(
  340. fn=lambda: shared.state.interrupt(),
  341. inputs=[],
  342. outputs=[],
  343. )
  344. with gr.Row():
  345. with gr.Column(scale=1, elem_id="style_pos_col"):
  346. prompt_style = gr.Dropdown(label="Style 1", elem_id=f"{id_part}_style_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())))
  347. with gr.Column(scale=1, elem_id="style_neg_col"):
  348. prompt_style2 = gr.Dropdown(label="Style 2", elem_id=f"{id_part}_style2_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())))
  349. return prompt, prompt_style, negative_prompt, prompt_style2, submit, button_interrogate, button_deepbooru, prompt_style_apply, save_style, paste, token_counter, token_button
  350. def setup_progressbar(progressbar, preview, id_part, textinfo=None):
  351. if textinfo is None:
  352. textinfo = gr.HTML(visible=False)
  353. check_progress = gr.Button('Check progress', elem_id=f"{id_part}_check_progress", visible=False)
  354. check_progress.click(
  355. fn=lambda: check_progress_call(id_part),
  356. show_progress=False,
  357. inputs=[],
  358. outputs=[progressbar, preview, preview, textinfo],
  359. )
  360. check_progress_initial = gr.Button('Check progress (first)', elem_id=f"{id_part}_check_progress_initial", visible=False)
  361. check_progress_initial.click(
  362. fn=lambda: check_progress_call_initial(id_part),
  363. show_progress=False,
  364. inputs=[],
  365. outputs=[progressbar, preview, preview, textinfo],
  366. )
  367. def apply_setting(key, value):
  368. if value is None:
  369. return gr.update()
  370. if shared.cmd_opts.freeze_settings:
  371. return gr.update()
  372. # dont allow model to be swapped when model hash exists in prompt
  373. if key == "sd_model_checkpoint" and opts.disable_weights_auto_swap:
  374. return gr.update()
  375. if key == "sd_model_checkpoint":
  376. ckpt_info = sd_models.get_closet_checkpoint_match(value)
  377. if ckpt_info is not None:
  378. value = ckpt_info.title
  379. else:
  380. return gr.update()
  381. comp_args = opts.data_labels[key].component_args
  382. if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False:
  383. return
  384. valtype = type(opts.data_labels[key].default)
  385. oldval = opts.data.get(key, None)
  386. opts.data[key] = valtype(value) if valtype != type(None) else value
  387. if oldval != value and opts.data_labels[key].onchange is not None:
  388. opts.data_labels[key].onchange()
  389. opts.save(shared.config_filename)
  390. return value
  391. def update_generation_info(args):
  392. generation_info, html_info, img_index = args
  393. try:
  394. generation_info = json.loads(generation_info)
  395. if img_index < 0 or img_index >= len(generation_info["infotexts"]):
  396. return html_info
  397. return plaintext_to_html(generation_info["infotexts"][img_index])
  398. except Exception:
  399. pass
  400. # if the json parse or anything else fails, just return the old html_info
  401. return html_info
  402. def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id):
  403. def refresh():
  404. refresh_method()
  405. args = refreshed_args() if callable(refreshed_args) else refreshed_args
  406. for k, v in args.items():
  407. setattr(refresh_component, k, v)
  408. return gr.update(**(args or {}))
  409. refresh_button = ToolButton(value=refresh_symbol, elem_id=elem_id)
  410. refresh_button.click(
  411. fn=refresh,
  412. inputs=[],
  413. outputs=[refresh_component]
  414. )
  415. return refresh_button
  416. def create_output_panel(tabname, outdir):
  417. def open_folder(f):
  418. if not os.path.exists(f):
  419. print(f'Folder "{f}" does not exist. After you create an image, the folder will be created.')
  420. return
  421. elif not os.path.isdir(f):
  422. print(f"""
  423. WARNING
  424. An open_folder request was made with an argument that is not a folder.
  425. This could be an error or a malicious attempt to run code on your computer.
  426. Requested path was: {f}
  427. """, file=sys.stderr)
  428. return
  429. if not shared.cmd_opts.hide_ui_dir_config:
  430. path = os.path.normpath(f)
  431. if platform.system() == "Windows":
  432. os.startfile(path)
  433. elif platform.system() == "Darwin":
  434. sp.Popen(["open", path])
  435. elif "microsoft-standard-WSL2" in platform.uname().release:
  436. sp.Popen(["wsl-open", path])
  437. else:
  438. sp.Popen(["xdg-open", path])
  439. with gr.Column(variant='panel'):
  440. with gr.Group():
  441. result_gallery = gr.Gallery(label='Output', show_label=False, elem_id=f"{tabname}_gallery").style(grid=4)
  442. generation_info = None
  443. with gr.Column():
  444. with gr.Row(elem_id=f"image_buttons_{tabname}"):
  445. open_folder_button = gr.Button(folder_symbol, elem_id="hidden_element" if shared.cmd_opts.hide_ui_dir_config else f'open_folder_{tabname}')
  446. if tabname != "extras":
  447. save = gr.Button('Save', elem_id=f'save_{tabname}')
  448. save_zip = gr.Button('Zip', elem_id=f'save_zip_{tabname}')
  449. buttons = parameters_copypaste.create_buttons(["img2img", "inpaint", "extras"])
  450. open_folder_button.click(
  451. fn=lambda: open_folder(opts.outdir_samples or outdir),
  452. inputs=[],
  453. outputs=[],
  454. )
  455. if tabname != "extras":
  456. with gr.Row():
  457. download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False, elem_id=f'download_files_{tabname}')
  458. with gr.Group():
  459. html_info = gr.HTML(elem_id=f'html_info_{tabname}')
  460. html_log = gr.HTML(elem_id=f'html_log_{tabname}')
  461. generation_info = gr.Textbox(visible=False, elem_id=f'generation_info_{tabname}')
  462. if tabname == 'txt2img' or tabname == 'img2img':
  463. generation_info_button = gr.Button(visible=False, elem_id=f"{tabname}_generation_info_button")
  464. generation_info_button.click(
  465. fn=update_generation_info,
  466. _js="(x, y) => [x, y, selected_gallery_index()]",
  467. inputs=[generation_info, html_info],
  468. outputs=[html_info],
  469. preprocess=False
  470. )
  471. save.click(
  472. fn=wrap_gradio_call(save_files),
  473. _js="(x, y, z, w) => [x, y, false, selected_gallery_index()]",
  474. inputs=[
  475. generation_info,
  476. result_gallery,
  477. html_info,
  478. html_info,
  479. ],
  480. outputs=[
  481. download_files,
  482. html_log,
  483. ]
  484. )
  485. save_zip.click(
  486. fn=wrap_gradio_call(save_files),
  487. _js="(x, y, z, w) => [x, y, true, selected_gallery_index()]",
  488. inputs=[
  489. generation_info,
  490. result_gallery,
  491. html_info,
  492. html_info,
  493. ],
  494. outputs=[
  495. download_files,
  496. html_log,
  497. ]
  498. )
  499. else:
  500. html_info_x = gr.HTML(elem_id=f'html_info_x_{tabname}')
  501. html_info = gr.HTML(elem_id=f'html_info_{tabname}')
  502. html_log = gr.HTML(elem_id=f'html_log_{tabname}')
  503. parameters_copypaste.bind_buttons(buttons, result_gallery, "txt2img" if tabname == "txt2img" else None)
  504. return result_gallery, generation_info if tabname != "extras" else html_info_x, html_info, html_log
  505. def create_sampler_and_steps_selection(choices, tabname):
  506. if opts.samplers_in_dropdown:
  507. with FormRow(elem_id=f"sampler_selection_{tabname}"):
  508. 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")
  509. steps = gr.Slider(minimum=1, maximum=150, step=1, elem_id=f"{tabname}_steps", label="Sampling steps", value=20)
  510. else:
  511. with FormGroup(elem_id=f"sampler_selection_{tabname}"):
  512. steps = gr.Slider(minimum=1, maximum=150, step=1, elem_id=f"{tabname}_steps", label="Sampling steps", value=20)
  513. 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")
  514. return steps, sampler_index
  515. def ordered_ui_categories():
  516. user_order = {x.strip(): i for i, x in enumerate(shared.opts.ui_reorder.split(","))}
  517. for i, category in sorted(enumerate(shared.ui_reorder_categories), key=lambda x: user_order.get(x[1], x[0] + 1000)):
  518. yield category
  519. def create_ui():
  520. import modules.img2img
  521. import modules.txt2img
  522. reload_javascript()
  523. parameters_copypaste.reset()
  524. modules.scripts.scripts_current = modules.scripts.scripts_txt2img
  525. modules.scripts.scripts_txt2img.initialize_scripts(is_img2img=False)
  526. with gr.Blocks(analytics_enabled=False) as txt2img_interface:
  527. txt2img_prompt, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _,txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, token_counter, token_button = create_toprow(is_img2img=False)
  528. dummy_component = gr.Label(visible=False)
  529. txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="bytes", visible=False)
  530. with gr.Row(elem_id='txt2img_progress_row'):
  531. with gr.Column(scale=1):
  532. pass
  533. with gr.Column(scale=1):
  534. progressbar = gr.HTML(elem_id="txt2img_progressbar")
  535. txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False)
  536. setup_progressbar(progressbar, txt2img_preview, 'txt2img')
  537. with gr.Row().style(equal_height=False):
  538. with gr.Column(variant='panel', elem_id="txt2img_settings"):
  539. for category in ordered_ui_categories():
  540. if category == "sampler":
  541. steps, sampler_index = create_sampler_and_steps_selection(samplers, "txt2img")
  542. elif category == "dimensions":
  543. with FormRow():
  544. with gr.Column(elem_id="txt2img_column_size", scale=4):
  545. width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="txt2img_width")
  546. height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="txt2img_height")
  547. if opts.dimensions_and_batch_together:
  548. with gr.Column(elem_id="txt2img_column_batch"):
  549. batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count")
  550. batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size")
  551. elif category == "cfg":
  552. cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0, elem_id="txt2img_cfg_scale")
  553. elif category == "seed":
  554. seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs('txt2img')
  555. elif category == "checkboxes":
  556. with FormRow(elem_id="txt2img_checkboxes"):
  557. restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1, elem_id="txt2img_restore_faces")
  558. tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling")
  559. enable_hr = gr.Checkbox(label='Hires. fix', value=False, elem_id="txt2img_enable_hr")
  560. hr_final_resolution = FormHTML(value="", elem_id="txtimg_hr_finalres", label="Upscaled resolution", interactive=False)
  561. elif category == "hires_fix":
  562. with FormGroup(visible=False, elem_id="txt2img_hires_fix") as hr_options:
  563. with FormRow(elem_id="txt2img_hires_fix_row1"):
  564. 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)
  565. hr_second_pass_steps = gr.Slider(minimum=0, maximum=150, step=1, label='Hires steps', value=0, elem_id="txt2img_hires_steps")
  566. denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7, elem_id="txt2img_denoising_strength")
  567. with FormRow(elem_id="txt2img_hires_fix_row2"):
  568. hr_scale = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Upscale by", value=2.0, elem_id="txt2img_hr_scale")
  569. hr_resize_x = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize width to", value=0, elem_id="txt2img_hr_resize_x")
  570. hr_resize_y = gr.Slider(minimum=0, maximum=2048, step=8, label="Resize height to", value=0, elem_id="txt2img_hr_resize_y")
  571. elif category == "batch":
  572. if not opts.dimensions_and_batch_together:
  573. with FormRow(elem_id="txt2img_column_batch"):
  574. batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count")
  575. batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size")
  576. elif category == "scripts":
  577. with FormGroup(elem_id="txt2img_script_container"):
  578. custom_inputs = modules.scripts.scripts_txt2img.setup_ui()
  579. hr_resolution_preview_inputs = [enable_hr, width, height, hr_scale, hr_resize_x, hr_resize_y]
  580. hr_resolution_preview_args = dict(
  581. fn=calc_resolution_hires,
  582. inputs=hr_resolution_preview_inputs,
  583. outputs=[hr_final_resolution],
  584. show_progress=False
  585. )
  586. for input in hr_resolution_preview_inputs:
  587. input.change(**hr_resolution_preview_args)
  588. txt2img_gallery, generation_info, html_info, html_log = create_output_panel("txt2img", opts.outdir_txt2img_samples)
  589. parameters_copypaste.bind_buttons({"txt2img": txt2img_paste}, None, txt2img_prompt)
  590. connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
  591. connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
  592. txt2img_args = dict(
  593. fn=wrap_gradio_gpu_call(modules.txt2img.txt2img, extra_outputs=[None, '', '']),
  594. _js="submit",
  595. inputs=[
  596. txt2img_prompt,
  597. txt2img_negative_prompt,
  598. txt2img_prompt_style,
  599. txt2img_prompt_style2,
  600. steps,
  601. sampler_index,
  602. restore_faces,
  603. tiling,
  604. batch_count,
  605. batch_size,
  606. cfg_scale,
  607. seed,
  608. subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
  609. height,
  610. width,
  611. enable_hr,
  612. denoising_strength,
  613. hr_scale,
  614. hr_upscaler,
  615. hr_second_pass_steps,
  616. hr_resize_x,
  617. hr_resize_y,
  618. ] + custom_inputs,
  619. outputs=[
  620. txt2img_gallery,
  621. generation_info,
  622. html_info,
  623. html_log,
  624. ],
  625. show_progress=False,
  626. )
  627. txt2img_prompt.submit(**txt2img_args)
  628. submit.click(**txt2img_args)
  629. txt_prompt_img.change(
  630. fn=modules.images.image_data,
  631. inputs=[
  632. txt_prompt_img
  633. ],
  634. outputs=[
  635. txt2img_prompt,
  636. txt_prompt_img
  637. ]
  638. )
  639. enable_hr.change(
  640. fn=lambda x: gr_show(x),
  641. inputs=[enable_hr],
  642. outputs=[hr_options],
  643. show_progress = False,
  644. )
  645. txt2img_paste_fields = [
  646. (txt2img_prompt, "Prompt"),
  647. (txt2img_negative_prompt, "Negative prompt"),
  648. (steps, "Steps"),
  649. (sampler_index, "Sampler"),
  650. (restore_faces, "Face restoration"),
  651. (cfg_scale, "CFG scale"),
  652. (seed, "Seed"),
  653. (width, "Size-1"),
  654. (height, "Size-2"),
  655. (batch_size, "Batch size"),
  656. (subseed, "Variation seed"),
  657. (subseed_strength, "Variation seed strength"),
  658. (seed_resize_from_w, "Seed resize from-1"),
  659. (seed_resize_from_h, "Seed resize from-2"),
  660. (denoising_strength, "Denoising strength"),
  661. (enable_hr, lambda d: "Denoising strength" in d),
  662. (hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)),
  663. (hr_scale, "Hires upscale"),
  664. (hr_upscaler, "Hires upscaler"),
  665. (hr_second_pass_steps, "Hires steps"),
  666. (hr_resize_x, "Hires resize-1"),
  667. (hr_resize_y, "Hires resize-2"),
  668. *modules.scripts.scripts_txt2img.infotext_fields
  669. ]
  670. parameters_copypaste.add_paste_fields("txt2img", None, txt2img_paste_fields)
  671. txt2img_preview_params = [
  672. txt2img_prompt,
  673. txt2img_negative_prompt,
  674. steps,
  675. sampler_index,
  676. cfg_scale,
  677. seed,
  678. width,
  679. height,
  680. ]
  681. token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_prompt, steps], outputs=[token_counter])
  682. modules.scripts.scripts_current = modules.scripts.scripts_img2img
  683. modules.scripts.scripts_img2img.initialize_scripts(is_img2img=True)
  684. with gr.Blocks(analytics_enabled=False) as img2img_interface:
  685. img2img_prompt, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste,token_counter, token_button = create_toprow(is_img2img=True)
  686. with gr.Row(elem_id='img2img_progress_row'):
  687. img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="bytes", visible=False)
  688. with gr.Column(scale=1):
  689. pass
  690. with gr.Column(scale=1):
  691. progressbar = gr.HTML(elem_id="img2img_progressbar")
  692. img2img_preview = gr.Image(elem_id='img2img_preview', visible=False)
  693. setup_progressbar(progressbar, img2img_preview, 'img2img')
  694. with FormRow().style(equal_height=False):
  695. with gr.Column(variant='panel', elem_id="img2img_settings"):
  696. with gr.Tabs(elem_id="mode_img2img") as tabs_img2img_mode:
  697. with gr.TabItem('img2img', id='img2img', elem_id="img2img_img2img_tab"):
  698. init_img = gr.Image(label="Image for img2img", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool=cmd_opts.gradio_img2img_tool, image_mode="RGBA").style(height=480)
  699. with gr.TabItem('Inpaint', id='inpaint', elem_id="img2img_inpaint_tab"):
  700. 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=cmd_opts.gradio_inpaint_tool, image_mode="RGBA").style(height=480)
  701. init_img_with_mask_orig = gr.State(None)
  702. use_color_sketch = cmd_opts.gradio_inpaint_tool == "color-sketch"
  703. if use_color_sketch:
  704. def update_orig(image, state):
  705. if image is not None:
  706. same_size = state is not None and state.size == image.size
  707. has_exact_match = np.any(np.all(np.array(image) == np.array(state), axis=-1))
  708. edited = same_size and has_exact_match
  709. return image if not edited or state is None else state
  710. init_img_with_mask.change(update_orig, [init_img_with_mask, init_img_with_mask_orig], init_img_with_mask_orig)
  711. init_img_inpaint = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil", visible=False, elem_id="img_inpaint_base")
  712. init_mask_inpaint = gr.Image(label="Mask", source="upload", interactive=True, type="pil", visible=False, elem_id="img_inpaint_mask")
  713. with FormRow():
  714. mask_blur = gr.Slider(label='Mask blur', minimum=0, maximum=64, step=1, value=4, elem_id="img2img_mask_blur")
  715. mask_alpha = gr.Slider(label="Mask transparency", interactive=use_color_sketch, visible=use_color_sketch, elem_id="img2img_mask_alpha")
  716. with FormRow():
  717. mask_mode = gr.Radio(label="Mask source", choices=["Draw mask", "Upload mask"], type="index", value="Draw mask", elem_id="mask_mode")
  718. inpainting_mask_invert = gr.Radio(label='Mask mode', choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index", elem_id="img2img_mask_mode")
  719. with FormRow():
  720. inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index", elem_id="img2img_inpainting_fill")
  721. with FormRow():
  722. with gr.Column():
  723. inpaint_full_res = gr.Radio(label="Inpaint area", choices=["Whole picture", "Only masked"], type="index", value="Whole picture", elem_id="img2img_inpaint_full_res")
  724. with gr.Column(scale=4):
  725. 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")
  726. with gr.TabItem('Batch img2img', id='batch', elem_id="img2img_batch_tab"):
  727. hidden = '<br>Disabled when launched with --hide-ui-dir-config.' if shared.cmd_opts.hide_ui_dir_config else ''
  728. gr.HTML(f"<p class=\"text-gray-500\">Process images in a directory on the same machine where the server is running.<br>Use an empty output directory to save pictures normally instead of writing to the output directory.{hidden}</p>")
  729. img2img_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs, elem_id="img2img_batch_input_dir")
  730. img2img_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs, elem_id="img2img_batch_output_dir")
  731. with FormRow():
  732. 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")
  733. for category in ordered_ui_categories():
  734. if category == "sampler":
  735. steps, sampler_index = create_sampler_and_steps_selection(samplers_for_img2img, "img2img")
  736. elif category == "dimensions":
  737. with FormRow():
  738. with gr.Column(elem_id="img2img_column_size", scale=4):
  739. width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="img2img_width")
  740. height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="img2img_height")
  741. if opts.dimensions_and_batch_together:
  742. with gr.Column(elem_id="img2img_column_batch"):
  743. batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count")
  744. batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="img2img_batch_size")
  745. elif category == "cfg":
  746. with FormGroup():
  747. cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0, elem_id="img2img_cfg_scale")
  748. denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.75, elem_id="img2img_denoising_strength")
  749. elif category == "seed":
  750. seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs('img2img')
  751. elif category == "checkboxes":
  752. with FormRow(elem_id="img2img_checkboxes"):
  753. restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1, elem_id="img2img_restore_faces")
  754. tiling = gr.Checkbox(label='Tiling', value=False, elem_id="img2img_tiling")
  755. elif category == "batch":
  756. if not opts.dimensions_and_batch_together:
  757. with FormRow(elem_id="img2img_column_batch"):
  758. batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count")
  759. batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1, elem_id="img2img_batch_size")
  760. elif category == "scripts":
  761. with FormGroup(elem_id="img2img_script_container"):
  762. custom_inputs = modules.scripts.scripts_img2img.setup_ui()
  763. img2img_gallery, generation_info, html_info, html_log = create_output_panel("img2img", opts.outdir_img2img_samples)
  764. parameters_copypaste.bind_buttons({"img2img": img2img_paste}, None, img2img_prompt)
  765. connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
  766. connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
  767. img2img_prompt_img.change(
  768. fn=modules.images.image_data,
  769. inputs=[
  770. img2img_prompt_img
  771. ],
  772. outputs=[
  773. img2img_prompt,
  774. img2img_prompt_img
  775. ]
  776. )
  777. mask_mode.change(
  778. lambda mode, img: {
  779. init_img_with_mask: gr_show(mode == 0),
  780. init_img_inpaint: gr_show(mode == 1),
  781. init_mask_inpaint: gr_show(mode == 1),
  782. },
  783. inputs=[mask_mode, init_img_with_mask],
  784. outputs=[
  785. init_img_with_mask,
  786. init_img_inpaint,
  787. init_mask_inpaint,
  788. ],
  789. )
  790. img2img_args = dict(
  791. fn=wrap_gradio_gpu_call(modules.img2img.img2img, extra_outputs=[None, '', '']),
  792. _js="submit_img2img",
  793. inputs=[
  794. dummy_component,
  795. img2img_prompt,
  796. img2img_negative_prompt,
  797. img2img_prompt_style,
  798. img2img_prompt_style2,
  799. init_img,
  800. init_img_with_mask,
  801. init_img_with_mask_orig,
  802. init_img_inpaint,
  803. init_mask_inpaint,
  804. mask_mode,
  805. steps,
  806. sampler_index,
  807. mask_blur,
  808. mask_alpha,
  809. inpainting_fill,
  810. restore_faces,
  811. tiling,
  812. batch_count,
  813. batch_size,
  814. cfg_scale,
  815. denoising_strength,
  816. seed,
  817. subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
  818. height,
  819. width,
  820. resize_mode,
  821. inpaint_full_res,
  822. inpaint_full_res_padding,
  823. inpainting_mask_invert,
  824. img2img_batch_input_dir,
  825. img2img_batch_output_dir,
  826. ] + custom_inputs,
  827. outputs=[
  828. img2img_gallery,
  829. generation_info,
  830. html_info,
  831. html_log,
  832. ],
  833. show_progress=False,
  834. )
  835. img2img_prompt.submit(**img2img_args)
  836. submit.click(**img2img_args)
  837. img2img_interrogate.click(
  838. fn=interrogate,
  839. inputs=[init_img],
  840. outputs=[img2img_prompt],
  841. )
  842. img2img_deepbooru.click(
  843. fn=interrogate_deepbooru,
  844. inputs=[init_img],
  845. outputs=[img2img_prompt],
  846. )
  847. prompts = [(txt2img_prompt, txt2img_negative_prompt), (img2img_prompt, img2img_negative_prompt)]
  848. style_dropdowns = [(txt2img_prompt_style, txt2img_prompt_style2), (img2img_prompt_style, img2img_prompt_style2)]
  849. style_js_funcs = ["update_txt2img_tokens", "update_img2img_tokens"]
  850. for button, (prompt, negative_prompt) in zip([txt2img_save_style, img2img_save_style], prompts):
  851. button.click(
  852. fn=add_style,
  853. _js="ask_for_style_name",
  854. # Have to pass empty dummy component here, because the JavaScript and Python function have to accept
  855. # the same number of parameters, but we only know the style-name after the JavaScript prompt
  856. inputs=[dummy_component, prompt, negative_prompt],
  857. outputs=[txt2img_prompt_style, img2img_prompt_style, txt2img_prompt_style2, img2img_prompt_style2],
  858. )
  859. for button, (prompt, negative_prompt), (style1, style2), js_func in zip([txt2img_prompt_style_apply, img2img_prompt_style_apply], prompts, style_dropdowns, style_js_funcs):
  860. button.click(
  861. fn=apply_styles,
  862. _js=js_func,
  863. inputs=[prompt, negative_prompt, style1, style2],
  864. outputs=[prompt, negative_prompt, style1, style2],
  865. )
  866. token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter])
  867. img2img_paste_fields = [
  868. (img2img_prompt, "Prompt"),
  869. (img2img_negative_prompt, "Negative prompt"),
  870. (steps, "Steps"),
  871. (sampler_index, "Sampler"),
  872. (restore_faces, "Face restoration"),
  873. (cfg_scale, "CFG scale"),
  874. (seed, "Seed"),
  875. (width, "Size-1"),
  876. (height, "Size-2"),
  877. (batch_size, "Batch size"),
  878. (subseed, "Variation seed"),
  879. (subseed_strength, "Variation seed strength"),
  880. (seed_resize_from_w, "Seed resize from-1"),
  881. (seed_resize_from_h, "Seed resize from-2"),
  882. (denoising_strength, "Denoising strength"),
  883. (mask_blur, "Mask blur"),
  884. *modules.scripts.scripts_img2img.infotext_fields
  885. ]
  886. parameters_copypaste.add_paste_fields("img2img", init_img, img2img_paste_fields)
  887. parameters_copypaste.add_paste_fields("inpaint", init_img_with_mask, img2img_paste_fields)
  888. modules.scripts.scripts_current = None
  889. with gr.Blocks(analytics_enabled=False) as extras_interface:
  890. with gr.Row().style(equal_height=False):
  891. with gr.Column(variant='panel'):
  892. with gr.Tabs(elem_id="mode_extras"):
  893. with gr.TabItem('Single Image', elem_id="extras_single_tab"):
  894. extras_image = gr.Image(label="Source", source="upload", interactive=True, type="pil", elem_id="extras_image")
  895. with gr.TabItem('Batch Process', elem_id="extras_batch_process_tab"):
  896. image_batch = gr.File(label="Batch Process", file_count="multiple", interactive=True, type="file", elem_id="extras_image_batch")
  897. with gr.TabItem('Batch from Directory', elem_id="extras_batch_directory_tab"):
  898. extras_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs, placeholder="A directory on the same machine where the server is running.", elem_id="extras_batch_input_dir")
  899. extras_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs, placeholder="Leave blank to save images to the default path.", elem_id="extras_batch_output_dir")
  900. show_extras_results = gr.Checkbox(label='Show result images', value=True, elem_id="extras_show_extras_results")
  901. submit = gr.Button('Generate', elem_id="extras_generate", variant='primary')
  902. with gr.Tabs(elem_id="extras_resize_mode"):
  903. with gr.TabItem('Scale by', elem_id="extras_scale_by_tab"):
  904. upscaling_resize = gr.Slider(minimum=1.0, maximum=8.0, step=0.05, label="Resize", value=4, elem_id="extras_upscaling_resize")
  905. with gr.TabItem('Scale to', elem_id="extras_scale_to_tab"):
  906. with gr.Group():
  907. with gr.Row():
  908. upscaling_resize_w = gr.Number(label="Width", value=512, precision=0, elem_id="extras_upscaling_resize_w")
  909. upscaling_resize_h = gr.Number(label="Height", value=512, precision=0, elem_id="extras_upscaling_resize_h")
  910. upscaling_crop = gr.Checkbox(label='Crop to fit', value=True, elem_id="extras_upscaling_crop")
  911. with gr.Group():
  912. extras_upscaler_1 = gr.Radio(label='Upscaler 1', elem_id="extras_upscaler_1", choices=[x.name for x in shared.sd_upscalers], value=shared.sd_upscalers[0].name, type="index")
  913. with gr.Group():
  914. extras_upscaler_2 = gr.Radio(label='Upscaler 2', elem_id="extras_upscaler_2", choices=[x.name for x in shared.sd_upscalers], value=shared.sd_upscalers[0].name, type="index")
  915. extras_upscaler_2_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="Upscaler 2 visibility", value=1, elem_id="extras_upscaler_2_visibility")
  916. with gr.Group():
  917. gfpgan_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="GFPGAN visibility", value=0, interactive=modules.gfpgan_model.have_gfpgan, elem_id="extras_gfpgan_visibility")
  918. with gr.Group():
  919. codeformer_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="CodeFormer visibility", value=0, interactive=modules.codeformer_model.have_codeformer, elem_id="extras_codeformer_visibility")
  920. codeformer_weight = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="CodeFormer weight (0 = maximum effect, 1 = minimum effect)", value=0, interactive=modules.codeformer_model.have_codeformer, elem_id="extras_codeformer_weight")
  921. with gr.Group():
  922. upscale_before_face_fix = gr.Checkbox(label='Upscale Before Restoring Faces', value=False, elem_id="extras_upscale_before_face_fix")
  923. result_images, html_info_x, html_info, html_log = create_output_panel("extras", opts.outdir_extras_samples)
  924. submit.click(
  925. fn=wrap_gradio_gpu_call(modules.extras.run_extras, extra_outputs=[None, '']),
  926. _js="get_extras_tab_index",
  927. inputs=[
  928. dummy_component,
  929. dummy_component,
  930. extras_image,
  931. image_batch,
  932. extras_batch_input_dir,
  933. extras_batch_output_dir,
  934. show_extras_results,
  935. gfpgan_visibility,
  936. codeformer_visibility,
  937. codeformer_weight,
  938. upscaling_resize,
  939. upscaling_resize_w,
  940. upscaling_resize_h,
  941. upscaling_crop,
  942. extras_upscaler_1,
  943. extras_upscaler_2,
  944. extras_upscaler_2_visibility,
  945. upscale_before_face_fix,
  946. ],
  947. outputs=[
  948. result_images,
  949. html_info_x,
  950. html_info,
  951. ]
  952. )
  953. parameters_copypaste.add_paste_fields("extras", extras_image, None)
  954. extras_image.change(
  955. fn=modules.extras.clear_cache,
  956. inputs=[], outputs=[]
  957. )
  958. with gr.Blocks(analytics_enabled=False) as pnginfo_interface:
  959. with gr.Row().style(equal_height=False):
  960. with gr.Column(variant='panel'):
  961. image = gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil")
  962. with gr.Column(variant='panel'):
  963. html = gr.HTML()
  964. generation_info = gr.Textbox(visible=False, elem_id="pnginfo_generation_info")
  965. html2 = gr.HTML()
  966. with gr.Row():
  967. buttons = parameters_copypaste.create_buttons(["txt2img", "img2img", "inpaint", "extras"])
  968. parameters_copypaste.bind_buttons(buttons, image, generation_info)
  969. image.change(
  970. fn=wrap_gradio_call(modules.extras.run_pnginfo),
  971. inputs=[image],
  972. outputs=[html, generation_info, html2],
  973. )
  974. with gr.Blocks(analytics_enabled=False) as modelmerger_interface:
  975. with gr.Row().style(equal_height=False):
  976. with gr.Column(variant='panel'):
  977. gr.HTML(value="<p>A merger of the two checkpoints will be generated in your <b>checkpoint</b> directory.</p>")
  978. with gr.Row():
  979. primary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_primary_model_name", label="Primary model (A)")
  980. create_refresh_button(primary_model_name, modules.sd_models.list_models, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, "refresh_checkpoint_A")
  981. secondary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_secondary_model_name", label="Secondary model (B)")
  982. create_refresh_button(secondary_model_name, modules.sd_models.list_models, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, "refresh_checkpoint_B")
  983. tertiary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_tertiary_model_name", label="Tertiary model (C)")
  984. create_refresh_button(tertiary_model_name, modules.sd_models.list_models, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, "refresh_checkpoint_C")
  985. custom_name = gr.Textbox(label="Custom Name (Optional)", elem_id="modelmerger_custom_name")
  986. 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")
  987. interp_method = gr.Radio(choices=["Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method", elem_id="modelmerger_interp_method")
  988. with gr.Row():
  989. checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="ckpt", label="Checkpoint format", elem_id="modelmerger_checkpoint_format")
  990. save_as_half = gr.Checkbox(value=False, label="Save as float16", elem_id="modelmerger_save_as_half")
  991. modelmerger_merge = gr.Button(elem_id="modelmerger_merge", label="Merge", variant='primary')
  992. with gr.Column(variant='panel'):
  993. submit_result = gr.Textbox(elem_id="modelmerger_result", show_label=False)
  994. with gr.Blocks(analytics_enabled=False) as train_interface:
  995. with gr.Row().style(equal_height=False):
  996. 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>")
  997. with gr.Row().style(equal_height=False):
  998. with gr.Tabs(elem_id="train_tabs"):
  999. with gr.Tab(label="Create embedding"):
  1000. new_embedding_name = gr.Textbox(label="Name", elem_id="train_new_embedding_name")
  1001. initialization_text = gr.Textbox(label="Initialization text", value="*", elem_id="train_initialization_text")
  1002. nvpt = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1, elem_id="train_nvpt")
  1003. overwrite_old_embedding = gr.Checkbox(value=False, label="Overwrite Old Embedding", elem_id="train_overwrite_old_embedding")
  1004. with gr.Row():
  1005. with gr.Column(scale=3):
  1006. gr.HTML(value="")
  1007. with gr.Column():
  1008. create_embedding = gr.Button(value="Create embedding", variant='primary', elem_id="train_create_embedding")
  1009. with gr.Tab(label="Create hypernetwork"):
  1010. new_hypernetwork_name = gr.Textbox(label="Name", elem_id="train_new_hypernetwork_name")
  1011. new_hypernetwork_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "1024", "320", "640", "1280"], elem_id="train_new_hypernetwork_sizes")
  1012. 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")
  1013. 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")
  1014. 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")
  1015. new_hypernetwork_add_layer_norm = gr.Checkbox(label="Add layer normalization", elem_id="train_new_hypernetwork_add_layer_norm")
  1016. new_hypernetwork_use_dropout = gr.Checkbox(label="Use dropout", elem_id="train_new_hypernetwork_use_dropout")
  1017. overwrite_old_hypernetwork = gr.Checkbox(value=False, label="Overwrite Old Hypernetwork", elem_id="train_overwrite_old_hypernetwork")
  1018. with gr.Row():
  1019. with gr.Column(scale=3):
  1020. gr.HTML(value="")
  1021. with gr.Column():
  1022. create_hypernetwork = gr.Button(value="Create hypernetwork", variant='primary', elem_id="train_create_hypernetwork")
  1023. with gr.Tab(label="Preprocess images"):
  1024. process_src = gr.Textbox(label='Source directory', elem_id="train_process_src")
  1025. process_dst = gr.Textbox(label='Destination directory', elem_id="train_process_dst")
  1026. process_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="train_process_width")
  1027. process_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="train_process_height")
  1028. preprocess_txt_action = gr.Dropdown(label='Existing Caption txt Action', value="ignore", choices=["ignore", "copy", "prepend", "append"], elem_id="train_preprocess_txt_action")
  1029. with gr.Row():
  1030. process_flip = gr.Checkbox(label='Create flipped copies', elem_id="train_process_flip")
  1031. process_split = gr.Checkbox(label='Split oversized images', elem_id="train_process_split")
  1032. process_focal_crop = gr.Checkbox(label='Auto focal point crop', elem_id="train_process_focal_crop")
  1033. process_caption = gr.Checkbox(label='Use BLIP for caption', elem_id="train_process_caption")
  1034. process_caption_deepbooru = gr.Checkbox(label='Use deepbooru for caption', visible=True, elem_id="train_process_caption_deepbooru")
  1035. with gr.Row(visible=False) as process_split_extra_row:
  1036. 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")
  1037. 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")
  1038. with gr.Row(visible=False) as process_focal_crop_row:
  1039. 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")
  1040. 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")
  1041. 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")
  1042. process_focal_crop_debug = gr.Checkbox(label='Create debug image', elem_id="train_process_focal_crop_debug")
  1043. with gr.Row():
  1044. with gr.Column(scale=3):
  1045. gr.HTML(value="")
  1046. with gr.Column():
  1047. with gr.Row():
  1048. interrupt_preprocessing = gr.Button("Interrupt", elem_id="train_interrupt_preprocessing")
  1049. run_preprocess = gr.Button(value="Preprocess", variant='primary', elem_id="train_run_preprocess")
  1050. process_split.change(
  1051. fn=lambda show: gr_show(show),
  1052. inputs=[process_split],
  1053. outputs=[process_split_extra_row],
  1054. )
  1055. process_focal_crop.change(
  1056. fn=lambda show: gr_show(show),
  1057. inputs=[process_focal_crop],
  1058. outputs=[process_focal_crop_row],
  1059. )
  1060. with gr.Tab(label="Train"):
  1061. 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>")
  1062. with FormRow():
  1063. train_embedding_name = gr.Dropdown(label='Embedding', elem_id="train_embedding", choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys()))
  1064. 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")
  1065. train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', elem_id="train_hypernetwork", choices=[x for x in shared.hypernetworks.keys()])
  1066. create_refresh_button(train_hypernetwork_name, shared.reload_hypernetworks, lambda: {"choices": sorted([x for x in shared.hypernetworks.keys()])}, "refresh_train_hypernetwork_name")
  1067. with FormRow():
  1068. embedding_learn_rate = gr.Textbox(label='Embedding Learning rate', placeholder="Embedding Learning rate", value="0.005", elem_id="train_embedding_learn_rate")
  1069. hypernetwork_learn_rate = gr.Textbox(label='Hypernetwork Learning rate', placeholder="Hypernetwork Learning rate", value="0.00001", elem_id="train_hypernetwork_learn_rate")
  1070. with FormRow():
  1071. clip_grad_mode = gr.Dropdown(value="disabled", label="Gradient Clipping", choices=["disabled", "value", "norm"])
  1072. clip_grad_value = gr.Textbox(placeholder="Gradient clip value", value="0.1", show_label=False)
  1073. with FormRow():
  1074. batch_size = gr.Number(label='Batch size', value=1, precision=0, elem_id="train_batch_size")
  1075. gradient_step = gr.Number(label='Gradient accumulation steps', value=1, precision=0, elem_id="train_gradient_step")
  1076. dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images", elem_id="train_dataset_directory")
  1077. log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion", elem_id="train_log_directory")
  1078. template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt"), elem_id="train_template_file")
  1079. training_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="train_training_width")
  1080. training_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="train_training_height")
  1081. steps = gr.Number(label='Max steps', value=100000, precision=0, elem_id="train_steps")
  1082. with FormRow():
  1083. 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")
  1084. 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")
  1085. 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")
  1086. preview_from_txt2img = gr.Checkbox(label='Read parameters (prompt, etc...) from txt2img tab when making previews', value=False, elem_id="train_preview_from_txt2img")
  1087. shuffle_tags = gr.Checkbox(label="Shuffle tags by ',' when creating prompts.", value=False, elem_id="train_shuffle_tags")
  1088. 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")
  1089. latent_sampling_method = gr.Radio(label='Choose latent sampling method', value="once", choices=['once', 'deterministic', 'random'], elem_id="train_latent_sampling_method")
  1090. with gr.Row():
  1091. train_embedding = gr.Button(value="Train Embedding", variant='primary', elem_id="train_train_embedding")
  1092. interrupt_training = gr.Button(value="Interrupt", elem_id="train_interrupt_training")
  1093. train_hypernetwork = gr.Button(value="Train Hypernetwork", variant='primary', elem_id="train_train_hypernetwork")
  1094. params = script_callbacks.UiTrainTabParams(txt2img_preview_params)
  1095. script_callbacks.ui_train_tabs_callback(params)
  1096. with gr.Column():
  1097. progressbar = gr.HTML(elem_id="ti_progressbar")
  1098. ti_output = gr.Text(elem_id="ti_output", value="", show_label=False)
  1099. ti_gallery = gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(grid=4)
  1100. ti_preview = gr.Image(elem_id='ti_preview', visible=False)
  1101. ti_progress = gr.HTML(elem_id="ti_progress", value="")
  1102. ti_outcome = gr.HTML(elem_id="ti_error", value="")
  1103. setup_progressbar(progressbar, ti_preview, 'ti', textinfo=ti_progress)
  1104. create_embedding.click(
  1105. fn=modules.textual_inversion.ui.create_embedding,
  1106. inputs=[
  1107. new_embedding_name,
  1108. initialization_text,
  1109. nvpt,
  1110. overwrite_old_embedding,
  1111. ],
  1112. outputs=[
  1113. train_embedding_name,
  1114. ti_output,
  1115. ti_outcome,
  1116. ]
  1117. )
  1118. create_hypernetwork.click(
  1119. fn=modules.hypernetworks.ui.create_hypernetwork,
  1120. inputs=[
  1121. new_hypernetwork_name,
  1122. new_hypernetwork_sizes,
  1123. overwrite_old_hypernetwork,
  1124. new_hypernetwork_layer_structure,
  1125. new_hypernetwork_activation_func,
  1126. new_hypernetwork_initialization_option,
  1127. new_hypernetwork_add_layer_norm,
  1128. new_hypernetwork_use_dropout
  1129. ],
  1130. outputs=[
  1131. train_hypernetwork_name,
  1132. ti_output,
  1133. ti_outcome,
  1134. ]
  1135. )
  1136. run_preprocess.click(
  1137. fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]),
  1138. _js="start_training_textual_inversion",
  1139. inputs=[
  1140. process_src,
  1141. process_dst,
  1142. process_width,
  1143. process_height,
  1144. preprocess_txt_action,
  1145. process_flip,
  1146. process_split,
  1147. process_caption,
  1148. process_caption_deepbooru,
  1149. process_split_threshold,
  1150. process_overlap_ratio,
  1151. process_focal_crop,
  1152. process_focal_crop_face_weight,
  1153. process_focal_crop_entropy_weight,
  1154. process_focal_crop_edges_weight,
  1155. process_focal_crop_debug,
  1156. ],
  1157. outputs=[
  1158. ti_output,
  1159. ti_outcome,
  1160. ],
  1161. )
  1162. train_embedding.click(
  1163. fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]),
  1164. _js="start_training_textual_inversion",
  1165. inputs=[
  1166. train_embedding_name,
  1167. embedding_learn_rate,
  1168. batch_size,
  1169. gradient_step,
  1170. dataset_directory,
  1171. log_directory,
  1172. training_width,
  1173. training_height,
  1174. steps,
  1175. clip_grad_mode,
  1176. clip_grad_value,
  1177. shuffle_tags,
  1178. tag_drop_out,
  1179. latent_sampling_method,
  1180. create_image_every,
  1181. save_embedding_every,
  1182. template_file,
  1183. save_image_with_stored_embedding,
  1184. preview_from_txt2img,
  1185. *txt2img_preview_params,
  1186. ],
  1187. outputs=[
  1188. ti_output,
  1189. ti_outcome,
  1190. ]
  1191. )
  1192. train_hypernetwork.click(
  1193. fn=wrap_gradio_gpu_call(modules.hypernetworks.ui.train_hypernetwork, extra_outputs=[gr.update()]),
  1194. _js="start_training_textual_inversion",
  1195. inputs=[
  1196. train_hypernetwork_name,
  1197. hypernetwork_learn_rate,
  1198. batch_size,
  1199. gradient_step,
  1200. dataset_directory,
  1201. log_directory,
  1202. training_width,
  1203. training_height,
  1204. steps,
  1205. clip_grad_mode,
  1206. clip_grad_value,
  1207. shuffle_tags,
  1208. tag_drop_out,
  1209. latent_sampling_method,
  1210. create_image_every,
  1211. save_embedding_every,
  1212. template_file,
  1213. preview_from_txt2img,
  1214. *txt2img_preview_params,
  1215. ],
  1216. outputs=[
  1217. ti_output,
  1218. ti_outcome,
  1219. ]
  1220. )
  1221. interrupt_training.click(
  1222. fn=lambda: shared.state.interrupt(),
  1223. inputs=[],
  1224. outputs=[],
  1225. )
  1226. interrupt_preprocessing.click(
  1227. fn=lambda: shared.state.interrupt(),
  1228. inputs=[],
  1229. outputs=[],
  1230. )
  1231. def create_setting_component(key, is_quicksettings=False):
  1232. def fun():
  1233. return opts.data[key] if key in opts.data else opts.data_labels[key].default
  1234. info = opts.data_labels[key]
  1235. t = type(info.default)
  1236. args = info.component_args() if callable(info.component_args) else info.component_args
  1237. if info.component is not None:
  1238. comp = info.component
  1239. elif t == str:
  1240. comp = gr.Textbox
  1241. elif t == int:
  1242. comp = gr.Number
  1243. elif t == bool:
  1244. comp = gr.Checkbox
  1245. else:
  1246. raise Exception(f'bad options item type: {str(t)} for key {key}')
  1247. elem_id = "setting_"+key
  1248. if info.refresh is not None:
  1249. if is_quicksettings:
  1250. res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
  1251. create_refresh_button(res, info.refresh, info.component_args, "refresh_" + key)
  1252. else:
  1253. with FormRow():
  1254. res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
  1255. create_refresh_button(res, info.refresh, info.component_args, "refresh_" + key)
  1256. else:
  1257. res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
  1258. return res
  1259. components = []
  1260. component_dict = {}
  1261. script_callbacks.ui_settings_callback()
  1262. opts.reorder()
  1263. def run_settings(*args):
  1264. changed = []
  1265. for key, value, comp in zip(opts.data_labels.keys(), args, components):
  1266. 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__}"
  1267. for key, value, comp in zip(opts.data_labels.keys(), args, components):
  1268. if comp == dummy_component:
  1269. continue
  1270. if opts.set(key, value):
  1271. changed.append(key)
  1272. try:
  1273. opts.save(shared.config_filename)
  1274. except RuntimeError:
  1275. return opts.dumpjson(), f'{len(changed)} settings changed without save: {", ".join(changed)}.'
  1276. return opts.dumpjson(), f'{len(changed)} settings changed{": " if len(changed) > 0 else ""}{", ".join(changed)}.'
  1277. def run_settings_single(value, key):
  1278. if not opts.same_type(value, opts.data_labels[key].default):
  1279. return gr.update(visible=True), opts.dumpjson()
  1280. if not opts.set(key, value):
  1281. return gr.update(value=getattr(opts, key)), opts.dumpjson()
  1282. opts.save(shared.config_filename)
  1283. return gr.update(value=value), opts.dumpjson()
  1284. with gr.Blocks(analytics_enabled=False) as settings_interface:
  1285. with gr.Row():
  1286. with gr.Column(scale=6):
  1287. settings_submit = gr.Button(value="Apply settings", variant='primary', elem_id="settings_submit")
  1288. with gr.Column():
  1289. restart_gradio = gr.Button(value='Reload UI', variant='primary', elem_id="settings_restart_gradio")
  1290. result = gr.HTML(elem_id="settings_result")
  1291. quicksettings_names = [x.strip() for x in opts.quicksettings.split(",")]
  1292. quicksettings_names = {x: i for i, x in enumerate(quicksettings_names) if x != 'quicksettings'}
  1293. quicksettings_list = []
  1294. previous_section = None
  1295. current_tab = None
  1296. with gr.Tabs(elem_id="settings"):
  1297. for i, (k, item) in enumerate(opts.data_labels.items()):
  1298. section_must_be_skipped = item.section[0] is None
  1299. if previous_section != item.section and not section_must_be_skipped:
  1300. elem_id, text = item.section
  1301. if current_tab is not None:
  1302. current_tab.__exit__()
  1303. current_tab = gr.TabItem(elem_id="settings_{}".format(elem_id), label=text)
  1304. current_tab.__enter__()
  1305. previous_section = item.section
  1306. if k in quicksettings_names and not shared.cmd_opts.freeze_settings:
  1307. quicksettings_list.append((i, k, item))
  1308. components.append(dummy_component)
  1309. elif section_must_be_skipped:
  1310. components.append(dummy_component)
  1311. else:
  1312. component = create_setting_component(k)
  1313. component_dict[k] = component
  1314. components.append(component)
  1315. if current_tab is not None:
  1316. current_tab.__exit__()
  1317. with gr.TabItem("Actions"):
  1318. request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications")
  1319. download_localization = gr.Button(value='Download localization template', elem_id="download_localization")
  1320. reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary', elem_id="settings_reload_script_bodies")
  1321. if os.path.exists("html/licenses.html"):
  1322. with open("html/licenses.html", encoding="utf8") as file:
  1323. with gr.TabItem("Licenses"):
  1324. gr.HTML(file.read(), elem_id="licenses")
  1325. gr.Button(value="Show all pages", elem_id="settings_show_all_pages")
  1326. request_notifications.click(
  1327. fn=lambda: None,
  1328. inputs=[],
  1329. outputs=[],
  1330. _js='function(){}'
  1331. )
  1332. download_localization.click(
  1333. fn=lambda: None,
  1334. inputs=[],
  1335. outputs=[],
  1336. _js='download_localization'
  1337. )
  1338. def reload_scripts():
  1339. modules.scripts.reload_script_body_only()
  1340. reload_javascript() # need to refresh the html page
  1341. reload_script_bodies.click(
  1342. fn=reload_scripts,
  1343. inputs=[],
  1344. outputs=[]
  1345. )
  1346. def request_restart():
  1347. shared.state.interrupt()
  1348. shared.state.need_restart = True
  1349. restart_gradio.click(
  1350. fn=request_restart,
  1351. _js='restart_reload',
  1352. inputs=[],
  1353. outputs=[],
  1354. )
  1355. interfaces = [
  1356. (txt2img_interface, "txt2img", "txt2img"),
  1357. (img2img_interface, "img2img", "img2img"),
  1358. (extras_interface, "Extras", "extras"),
  1359. (pnginfo_interface, "PNG Info", "pnginfo"),
  1360. (modelmerger_interface, "Checkpoint Merger", "modelmerger"),
  1361. (train_interface, "Train", "ti"),
  1362. ]
  1363. css = ""
  1364. for cssfile in modules.scripts.list_files_with_name("style.css"):
  1365. if not os.path.isfile(cssfile):
  1366. continue
  1367. with open(cssfile, "r", encoding="utf8") as file:
  1368. css += file.read() + "\n"
  1369. if os.path.exists(os.path.join(script_path, "user.css")):
  1370. with open(os.path.join(script_path, "user.css"), "r", encoding="utf8") as file:
  1371. css += file.read() + "\n"
  1372. if not cmd_opts.no_progressbar_hiding:
  1373. css += css_hide_progressbar
  1374. interfaces += script_callbacks.ui_tabs_callback()
  1375. interfaces += [(settings_interface, "Settings", "settings")]
  1376. extensions_interface = ui_extensions.create_ui()
  1377. interfaces += [(extensions_interface, "Extensions", "extensions")]
  1378. with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo:
  1379. with gr.Row(elem_id="quicksettings"):
  1380. for i, k, item in sorted(quicksettings_list, key=lambda x: quicksettings_names.get(x[1], x[0])):
  1381. component = create_setting_component(k, is_quicksettings=True)
  1382. component_dict[k] = component
  1383. parameters_copypaste.integrate_settings_paste_fields(component_dict)
  1384. parameters_copypaste.run_bind()
  1385. with gr.Tabs(elem_id="tabs") as tabs:
  1386. for interface, label, ifid in interfaces:
  1387. with gr.TabItem(label, id=ifid, elem_id='tab_' + ifid):
  1388. interface.render()
  1389. if os.path.exists(os.path.join(script_path, "notification.mp3")):
  1390. audio_notification = gr.Audio(interactive=False, value=os.path.join(script_path, "notification.mp3"), elem_id="audio_notification", visible=False)
  1391. if os.path.exists("html/footer.html"):
  1392. with open("html/footer.html", encoding="utf8") as file:
  1393. footer = file.read()
  1394. footer = footer.format(versions=versions_html())
  1395. gr.HTML(footer, elem_id="footer")
  1396. text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False)
  1397. settings_submit.click(
  1398. fn=wrap_gradio_call(run_settings, extra_outputs=[gr.update()]),
  1399. inputs=components,
  1400. outputs=[text_settings, result],
  1401. )
  1402. for i, k, item in quicksettings_list:
  1403. component = component_dict[k]
  1404. component.change(
  1405. fn=lambda value, k=k: run_settings_single(value, key=k),
  1406. inputs=[component],
  1407. outputs=[component, text_settings],
  1408. )
  1409. component_keys = [k for k in opts.data_labels.keys() if k in component_dict]
  1410. def get_settings_values():
  1411. return [getattr(opts, key) for key in component_keys]
  1412. demo.load(
  1413. fn=get_settings_values,
  1414. inputs=[],
  1415. outputs=[component_dict[k] for k in component_keys],
  1416. )
  1417. def modelmerger(*args):
  1418. try:
  1419. results = modules.extras.run_modelmerger(*args)
  1420. except Exception as e:
  1421. print("Error loading/saving model file:", file=sys.stderr)
  1422. print(traceback.format_exc(), file=sys.stderr)
  1423. modules.sd_models.list_models() # to remove the potentially missing models from the list
  1424. return [f"Error merging checkpoints: {e}"] + [gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(4)]
  1425. return results
  1426. modelmerger_merge.click(
  1427. fn=modelmerger,
  1428. inputs=[
  1429. primary_model_name,
  1430. secondary_model_name,
  1431. tertiary_model_name,
  1432. interp_method,
  1433. interp_amount,
  1434. save_as_half,
  1435. custom_name,
  1436. checkpoint_format,
  1437. ],
  1438. outputs=[
  1439. submit_result,
  1440. primary_model_name,
  1441. secondary_model_name,
  1442. tertiary_model_name,
  1443. component_dict['sd_model_checkpoint'],
  1444. ]
  1445. )
  1446. ui_config_file = cmd_opts.ui_config_file
  1447. ui_settings = {}
  1448. settings_count = len(ui_settings)
  1449. error_loading = False
  1450. try:
  1451. if os.path.exists(ui_config_file):
  1452. with open(ui_config_file, "r", encoding="utf8") as file:
  1453. ui_settings = json.load(file)
  1454. except Exception:
  1455. error_loading = True
  1456. print("Error loading settings:", file=sys.stderr)
  1457. print(traceback.format_exc(), file=sys.stderr)
  1458. def loadsave(path, x):
  1459. def apply_field(obj, field, condition=None, init_field=None):
  1460. key = path + "/" + field
  1461. if getattr(obj, 'custom_script_source', None) is not None:
  1462. key = 'customscript/' + obj.custom_script_source + '/' + key
  1463. if getattr(obj, 'do_not_save_to_config', False):
  1464. return
  1465. saved_value = ui_settings.get(key, None)
  1466. if saved_value is None:
  1467. ui_settings[key] = getattr(obj, field)
  1468. elif condition and not condition(saved_value):
  1469. print(f'Warning: Bad ui setting value: {key}: {saved_value}; Default value "{getattr(obj, field)}" will be used instead.')
  1470. else:
  1471. setattr(obj, field, saved_value)
  1472. if init_field is not None:
  1473. init_field(saved_value)
  1474. if type(x) in [gr.Slider, gr.Radio, gr.Checkbox, gr.Textbox, gr.Number, gr.Dropdown] and x.visible:
  1475. apply_field(x, 'visible')
  1476. if type(x) == gr.Slider:
  1477. apply_field(x, 'value')
  1478. apply_field(x, 'minimum')
  1479. apply_field(x, 'maximum')
  1480. apply_field(x, 'step')
  1481. if type(x) == gr.Radio:
  1482. apply_field(x, 'value', lambda val: val in x.choices)
  1483. if type(x) == gr.Checkbox:
  1484. apply_field(x, 'value')
  1485. if type(x) == gr.Textbox:
  1486. apply_field(x, 'value')
  1487. if type(x) == gr.Number:
  1488. apply_field(x, 'value')
  1489. if type(x) == gr.Dropdown:
  1490. apply_field(x, 'value', lambda val: val in x.choices, getattr(x, 'init_field', None))
  1491. visit(txt2img_interface, loadsave, "txt2img")
  1492. visit(img2img_interface, loadsave, "img2img")
  1493. visit(extras_interface, loadsave, "extras")
  1494. visit(modelmerger_interface, loadsave, "modelmerger")
  1495. visit(train_interface, loadsave, "train")
  1496. if not error_loading and (not os.path.exists(ui_config_file) or settings_count != len(ui_settings)):
  1497. with open(ui_config_file, "w", encoding="utf8") as file:
  1498. json.dump(ui_settings, file, indent=4)
  1499. return demo
  1500. def reload_javascript():
  1501. with open(os.path.join(script_path, "script.js"), "r", encoding="utf8") as jsfile:
  1502. javascript = f'<script>{jsfile.read()}</script>'
  1503. scripts_list = modules.scripts.list_scripts("javascript", ".js")
  1504. for basedir, filename, path in scripts_list:
  1505. with open(path, "r", encoding="utf8") as jsfile:
  1506. javascript += f"\n<!-- {filename} --><script>{jsfile.read()}</script>"
  1507. if cmd_opts.theme is not None:
  1508. javascript += f"\n<script>set_theme('{cmd_opts.theme}');</script>\n"
  1509. javascript += f"\n<script>{localization.localization_js(shared.opts.localization)}</script>"
  1510. def template_response(*args, **kwargs):
  1511. res = shared.GradioTemplateResponseOriginal(*args, **kwargs)
  1512. res.body = res.body.replace(
  1513. b'</head>', f'{javascript}</head>'.encode("utf8"))
  1514. res.init_headers()
  1515. return res
  1516. gradio.routes.templates.TemplateResponse = template_response
  1517. if not hasattr(shared, 'GradioTemplateResponseOriginal'):
  1518. shared.GradioTemplateResponseOriginal = gradio.routes.templates.TemplateResponse
  1519. def versions_html():
  1520. import torch
  1521. import launch
  1522. python_version = ".".join([str(x) for x in sys.version_info[0:3]])
  1523. commit = launch.commit_hash()
  1524. short_commit = commit[0:8]
  1525. if shared.xformers_available:
  1526. import xformers
  1527. xformers_version = xformers.__version__
  1528. else:
  1529. xformers_version = "N/A"
  1530. return f"""
  1531. python: <span title="{sys.version}">{python_version}</span>
  1532.  • 
  1533. torch: {torch.__version__}
  1534.  • 
  1535. xformers: {xformers_version}
  1536.  • 
  1537. gradio: {gr.__version__}
  1538.  • 
  1539. commit: <a href="https://github.com/AUTOMATIC1111/stable-diffusion-webui/commit/{commit}">{short_commit}</a>
  1540. """