ui.py 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810
  1. import base64
  2. import html
  3. import io
  4. import json
  5. import math
  6. import mimetypes
  7. import os
  8. import random
  9. import sys
  10. import tempfile
  11. import time
  12. import traceback
  13. import platform
  14. import subprocess as sp
  15. from functools import reduce
  16. import numpy as np
  17. import torch
  18. from PIL import Image, PngImagePlugin
  19. import piexif
  20. import gradio as gr
  21. import gradio.utils
  22. import gradio.routes
  23. from modules import sd_hijack, sd_models, localization
  24. from modules.paths import script_path
  25. from modules.shared import opts, cmd_opts, restricted_opts
  26. if cmd_opts.deepdanbooru:
  27. from modules.deepbooru import get_deepbooru_tags
  28. import modules.shared as shared
  29. from modules.sd_samplers import samplers, samplers_for_img2img
  30. from modules.sd_hijack import model_hijack
  31. import modules.ldsr_model
  32. import modules.scripts
  33. import modules.gfpgan_model
  34. import modules.codeformer_model
  35. import modules.styles
  36. import modules.generation_parameters_copypaste
  37. from modules import prompt_parser
  38. from modules.images import save_image
  39. import modules.textual_inversion.ui
  40. import modules.hypernetworks.ui
  41. import modules.images_history as img_his
  42. # 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
  43. mimetypes.init()
  44. mimetypes.add_type('application/javascript', '.js')
  45. if not cmd_opts.share and not cmd_opts.listen:
  46. # fix gradio phoning home
  47. gradio.utils.version_check = lambda: None
  48. gradio.utils.get_local_ip_address = lambda: '127.0.0.1'
  49. if cmd_opts.ngrok != None:
  50. import modules.ngrok as ngrok
  51. print('ngrok authtoken detected, trying to connect...')
  52. ngrok.connect(cmd_opts.ngrok, cmd_opts.port if cmd_opts.port != None else 7860, cmd_opts.ngrok_region)
  53. def gr_show(visible=True):
  54. return {"visible": visible, "__type__": "update"}
  55. sample_img2img = "assets/stable-samples/img2img/sketch-mountains-input.jpg"
  56. sample_img2img = sample_img2img if os.path.exists(sample_img2img) else None
  57. css_hide_progressbar = """
  58. .wrap .m-12 svg { display:none!important; }
  59. .wrap .m-12::before { content:"Loading..." }
  60. .progress-bar { display:none!important; }
  61. .meta-text { display:none!important; }
  62. """
  63. # Using constants for these since the variation selector isn't visible.
  64. # Important that they exactly match script.js for tooltip to work.
  65. random_symbol = '\U0001f3b2\ufe0f' # 🎲️
  66. reuse_symbol = '\u267b\ufe0f' # ♻️
  67. art_symbol = '\U0001f3a8' # 🎨
  68. paste_symbol = '\u2199\ufe0f' # ↙
  69. folder_symbol = '\U0001f4c2' # 📂
  70. refresh_symbol = '\U0001f504' # 🔄
  71. save_style_symbol = '\U0001f4be' # 💾
  72. apply_style_symbol = '\U0001f4cb' # 📋
  73. def plaintext_to_html(text):
  74. text = "<p>" + "<br>\n".join([f"{html.escape(x)}" for x in text.split('\n')]) + "</p>"
  75. return text
  76. def image_from_url_text(filedata):
  77. if type(filedata) == dict and filedata["is_file"]:
  78. filename = filedata["name"]
  79. tempdir = os.path.normpath(tempfile.gettempdir())
  80. normfn = os.path.normpath(filename)
  81. assert normfn.startswith(tempdir), 'trying to open image file not in temporary directory'
  82. return Image.open(filename)
  83. if type(filedata) == list:
  84. if len(filedata) == 0:
  85. return None
  86. filedata = filedata[0]
  87. if filedata.startswith("data:image/png;base64,"):
  88. filedata = filedata[len("data:image/png;base64,"):]
  89. filedata = base64.decodebytes(filedata.encode('utf-8'))
  90. image = Image.open(io.BytesIO(filedata))
  91. return image
  92. def send_gradio_gallery_to_image(x):
  93. if len(x) == 0:
  94. return None
  95. return image_from_url_text(x[0])
  96. def save_files(js_data, images, do_make_zip, index):
  97. import csv
  98. filenames = []
  99. fullfns = []
  100. #quick dictionary to class object conversion. Its necessary due apply_filename_pattern requiring it
  101. class MyObject:
  102. def __init__(self, d=None):
  103. if d is not None:
  104. for key, value in d.items():
  105. setattr(self, key, value)
  106. data = json.loads(js_data)
  107. p = MyObject(data)
  108. path = opts.outdir_save
  109. save_to_dirs = opts.use_save_to_dirs_for_ui
  110. extension: str = opts.samples_format
  111. start_index = 0
  112. 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
  113. images = [images[index]]
  114. start_index = index
  115. os.makedirs(opts.outdir_save, exist_ok=True)
  116. with open(os.path.join(opts.outdir_save, "log.csv"), "a", encoding="utf8", newline='') as file:
  117. at_start = file.tell() == 0
  118. writer = csv.writer(file)
  119. if at_start:
  120. writer.writerow(["prompt", "seed", "width", "height", "sampler", "cfgs", "steps", "filename", "negative_prompt"])
  121. for image_index, filedata in enumerate(images, start_index):
  122. image = image_from_url_text(filedata)
  123. is_grid = image_index < p.index_of_first_image
  124. i = 0 if is_grid else (image_index - p.index_of_first_image)
  125. 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)
  126. filename = os.path.relpath(fullfn, path)
  127. filenames.append(filename)
  128. fullfns.append(fullfn)
  129. if txt_fullfn:
  130. filenames.append(os.path.basename(txt_fullfn))
  131. fullfns.append(txt_fullfn)
  132. writer.writerow([data["prompt"], data["seed"], data["width"], data["height"], data["sampler"], data["cfg_scale"], data["steps"], filenames[0], data["negative_prompt"]])
  133. # Make Zip
  134. if do_make_zip:
  135. zip_filepath = os.path.join(path, "images.zip")
  136. from zipfile import ZipFile
  137. with ZipFile(zip_filepath, "w") as zip_file:
  138. for i in range(len(fullfns)):
  139. with open(fullfns[i], mode="rb") as f:
  140. zip_file.writestr(filenames[i], f.read())
  141. fullfns.insert(0, zip_filepath)
  142. return gr.File.update(value=fullfns, visible=True), '', '', plaintext_to_html(f"Saved: {filenames[0]}")
  143. def save_pil_to_file(pil_image, dir=None):
  144. use_metadata = False
  145. metadata = PngImagePlugin.PngInfo()
  146. for key, value in pil_image.info.items():
  147. if isinstance(key, str) and isinstance(value, str):
  148. metadata.add_text(key, value)
  149. use_metadata = True
  150. file_obj = tempfile.NamedTemporaryFile(delete=False, suffix=".png", dir=dir)
  151. pil_image.save(file_obj, pnginfo=(metadata if use_metadata else None))
  152. return file_obj
  153. # override save to file function so that it also writes PNG info
  154. gr.processing_utils.save_pil_to_file = save_pil_to_file
  155. def wrap_gradio_call(func, extra_outputs=None):
  156. def f(*args, extra_outputs_array=extra_outputs, **kwargs):
  157. run_memmon = opts.memmon_poll_rate > 0 and not shared.mem_mon.disabled
  158. if run_memmon:
  159. shared.mem_mon.monitor()
  160. t = time.perf_counter()
  161. try:
  162. res = list(func(*args, **kwargs))
  163. except Exception as e:
  164. # When printing out our debug argument list, do not print out more than a MB of text
  165. max_debug_str_len = 131072 # (1024*1024)/8
  166. print("Error completing request", file=sys.stderr)
  167. argStr = f"Arguments: {str(args)} {str(kwargs)}"
  168. print(argStr[:max_debug_str_len], file=sys.stderr)
  169. if len(argStr) > max_debug_str_len:
  170. print(f"(Argument list truncated at {max_debug_str_len}/{len(argStr)} characters)", file=sys.stderr)
  171. print(traceback.format_exc(), file=sys.stderr)
  172. shared.state.job = ""
  173. shared.state.job_count = 0
  174. if extra_outputs_array is None:
  175. extra_outputs_array = [None, '']
  176. res = extra_outputs_array + [f"<div class='error'>{plaintext_to_html(type(e).__name__+': '+str(e))}</div>"]
  177. elapsed = time.perf_counter() - t
  178. elapsed_m = int(elapsed // 60)
  179. elapsed_s = elapsed % 60
  180. elapsed_text = f"{elapsed_s:.2f}s"
  181. if (elapsed_m > 0):
  182. elapsed_text = f"{elapsed_m}m "+elapsed_text
  183. if run_memmon:
  184. mem_stats = {k: -(v//-(1024*1024)) for k, v in shared.mem_mon.stop().items()}
  185. active_peak = mem_stats['active_peak']
  186. reserved_peak = mem_stats['reserved_peak']
  187. sys_peak = mem_stats['system_peak']
  188. sys_total = mem_stats['total']
  189. sys_pct = round(sys_peak/max(sys_total, 1) * 100, 2)
  190. vram_html = f"<p class='vram'>Torch active/reserved: {active_peak}/{reserved_peak} MiB, <wbr>Sys VRAM: {sys_peak}/{sys_total} MiB ({sys_pct}%)</p>"
  191. else:
  192. vram_html = ''
  193. # last item is always HTML
  194. res[-1] += f"<div class='performance'><p class='time'>Time taken: <wbr>{elapsed_text}</p>{vram_html}</div>"
  195. shared.state.skipped = False
  196. shared.state.interrupted = False
  197. shared.state.job_count = 0
  198. return tuple(res)
  199. return f
  200. def check_progress_call(id_part):
  201. if shared.state.job_count == 0:
  202. return "", gr_show(False), gr_show(False), gr_show(False)
  203. progress = 0
  204. if shared.state.job_count > 0:
  205. progress += shared.state.job_no / shared.state.job_count
  206. if shared.state.sampling_steps > 0:
  207. progress += 1 / shared.state.job_count * shared.state.sampling_step / shared.state.sampling_steps
  208. progress = min(progress, 1)
  209. progressbar = ""
  210. if opts.show_progressbar:
  211. progressbar = f"""<div class='progressDiv'><div class='progress' style="width:{progress * 100}%">{str(int(progress*100))+"%" if progress > 0.01 else ""}</div></div>"""
  212. image = gr_show(False)
  213. preview_visibility = gr_show(False)
  214. if opts.show_progress_every_n_steps > 0:
  215. if shared.parallel_processing_allowed:
  216. if shared.state.sampling_step - shared.state.current_image_sampling_step >= opts.show_progress_every_n_steps and shared.state.current_latent is not None:
  217. shared.state.current_image = modules.sd_samplers.sample_to_image(shared.state.current_latent)
  218. shared.state.current_image_sampling_step = shared.state.sampling_step
  219. image = shared.state.current_image
  220. if image is None:
  221. image = gr.update(value=None)
  222. else:
  223. preview_visibility = gr_show(True)
  224. if shared.state.textinfo is not None:
  225. textinfo_result = gr.HTML.update(value=shared.state.textinfo, visible=True)
  226. else:
  227. textinfo_result = gr_show(False)
  228. return f"<span id='{id_part}_progress_span' style='display: none'>{time.time()}</span><p>{progressbar}</p>", preview_visibility, image, textinfo_result
  229. def check_progress_call_initial(id_part):
  230. shared.state.job_count = -1
  231. shared.state.current_latent = None
  232. shared.state.current_image = None
  233. shared.state.textinfo = None
  234. return check_progress_call(id_part)
  235. def roll_artist(prompt):
  236. allowed_cats = set([x for x in shared.artist_db.categories() if len(opts.random_artist_categories)==0 or x in opts.random_artist_categories])
  237. artist = random.choice([x for x in shared.artist_db.artists if x.category in allowed_cats])
  238. return prompt + ", " + artist.name if prompt != '' else artist.name
  239. def visit(x, func, path=""):
  240. if hasattr(x, 'children'):
  241. for c in x.children:
  242. visit(c, func, path)
  243. elif x.label is not None:
  244. func(path + "/" + str(x.label), x)
  245. def add_style(name: str, prompt: str, negative_prompt: str):
  246. if name is None:
  247. return [gr_show() for x in range(4)]
  248. style = modules.styles.PromptStyle(name, prompt, negative_prompt)
  249. shared.prompt_styles.styles[style.name] = style
  250. # Save all loaded prompt styles: this allows us to update the storage format in the future more easily, because we
  251. # reserialize all styles every time we save them
  252. shared.prompt_styles.save_styles(shared.styles_filename)
  253. return [gr.Dropdown.update(visible=True, choices=list(shared.prompt_styles.styles)) for _ in range(4)]
  254. def apply_styles(prompt, prompt_neg, style1_name, style2_name):
  255. prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, [style1_name, style2_name])
  256. prompt_neg = shared.prompt_styles.apply_negative_styles_to_prompt(prompt_neg, [style1_name, style2_name])
  257. return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=prompt_neg), gr.Dropdown.update(value="None"), gr.Dropdown.update(value="None")]
  258. def interrogate(image):
  259. prompt = shared.interrogator.interrogate(image)
  260. return gr_show(True) if prompt is None else prompt
  261. def interrogate_deepbooru(image):
  262. prompt = get_deepbooru_tags(image)
  263. return gr_show(True) if prompt is None else prompt
  264. def create_seed_inputs():
  265. with gr.Row():
  266. with gr.Box():
  267. with gr.Row(elem_id='seed_row'):
  268. seed = (gr.Textbox if cmd_opts.use_textbox_seed else gr.Number)(label='Seed', value=-1)
  269. seed.style(container=False)
  270. random_seed = gr.Button(random_symbol, elem_id='random_seed')
  271. reuse_seed = gr.Button(reuse_symbol, elem_id='reuse_seed')
  272. with gr.Box(elem_id='subseed_show_box'):
  273. seed_checkbox = gr.Checkbox(label='Extra', elem_id='subseed_show', value=False)
  274. # Components to show/hide based on the 'Extra' checkbox
  275. seed_extras = []
  276. with gr.Row(visible=False) as seed_extra_row_1:
  277. seed_extras.append(seed_extra_row_1)
  278. with gr.Box():
  279. with gr.Row(elem_id='subseed_row'):
  280. subseed = gr.Number(label='Variation seed', value=-1)
  281. subseed.style(container=False)
  282. random_subseed = gr.Button(random_symbol, elem_id='random_subseed')
  283. reuse_subseed = gr.Button(reuse_symbol, elem_id='reuse_subseed')
  284. subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01)
  285. with gr.Row(visible=False) as seed_extra_row_2:
  286. seed_extras.append(seed_extra_row_2)
  287. seed_resize_from_w = gr.Slider(minimum=0, maximum=2048, step=64, label="Resize seed from width", value=0)
  288. seed_resize_from_h = gr.Slider(minimum=0, maximum=2048, step=64, label="Resize seed from height", value=0)
  289. random_seed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[seed])
  290. random_subseed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[subseed])
  291. def change_visibility(show):
  292. return {comp: gr_show(show) for comp in seed_extras}
  293. seed_checkbox.change(change_visibility, show_progress=False, inputs=[seed_checkbox], outputs=seed_extras)
  294. return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox
  295. def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: gr.Textbox, dummy_component, is_subseed):
  296. """ Connects a 'reuse (sub)seed' button's click event so that it copies last used
  297. (sub)seed value from generation info the to the seed field. If copying subseed and subseed strength
  298. was 0, i.e. no variation seed was used, it copies the normal seed value instead."""
  299. def copy_seed(gen_info_string: str, index):
  300. res = -1
  301. try:
  302. gen_info = json.loads(gen_info_string)
  303. index -= gen_info.get('index_of_first_image', 0)
  304. if is_subseed and gen_info.get('subseed_strength', 0) > 0:
  305. all_subseeds = gen_info.get('all_subseeds', [-1])
  306. res = all_subseeds[index if 0 <= index < len(all_subseeds) else 0]
  307. else:
  308. all_seeds = gen_info.get('all_seeds', [-1])
  309. res = all_seeds[index if 0 <= index < len(all_seeds) else 0]
  310. except json.decoder.JSONDecodeError as e:
  311. if gen_info_string != '':
  312. print("Error parsing JSON generation info:", file=sys.stderr)
  313. print(gen_info_string, file=sys.stderr)
  314. return [res, gr_show(False)]
  315. reuse_seed.click(
  316. fn=copy_seed,
  317. _js="(x, y) => [x, selected_gallery_index()]",
  318. show_progress=False,
  319. inputs=[generation_info, dummy_component],
  320. outputs=[seed, dummy_component]
  321. )
  322. def update_token_counter(text, steps):
  323. try:
  324. _, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
  325. prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)
  326. except Exception:
  327. # a parsing error can happen here during typing, and we don't want to bother the user with
  328. # messages related to it in console
  329. prompt_schedules = [[[steps, text]]]
  330. flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules)
  331. prompts = [prompt_text for step, prompt_text in flat_prompts]
  332. tokens, token_count, max_length = max([model_hijack.tokenize(prompt) for prompt in prompts], key=lambda args: args[1])
  333. style_class = ' class="red"' if (token_count > max_length) else ""
  334. return f"<span {style_class}>{token_count}/{max_length}</span>"
  335. def create_toprow(is_img2img):
  336. id_part = "img2img" if is_img2img else "txt2img"
  337. with gr.Row(elem_id="toprow"):
  338. with gr.Column(scale=6):
  339. with gr.Row():
  340. with gr.Column(scale=80):
  341. with gr.Row():
  342. prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, lines=2,
  343. placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)"
  344. )
  345. with gr.Row():
  346. with gr.Column(scale=80):
  347. with gr.Row():
  348. negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=2,
  349. placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)"
  350. )
  351. with gr.Column(scale=1, elem_id="roll_col"):
  352. roll = gr.Button(value=art_symbol, elem_id="roll", visible=len(shared.artist_db.artists) > 0)
  353. paste = gr.Button(value=paste_symbol, elem_id="paste")
  354. save_style = gr.Button(value=save_style_symbol, elem_id="style_create")
  355. prompt_style_apply = gr.Button(value=apply_style_symbol, elem_id="style_apply")
  356. token_counter = gr.HTML(value="<span></span>", elem_id=f"{id_part}_token_counter")
  357. token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")
  358. button_interrogate = None
  359. button_deepbooru = None
  360. if is_img2img:
  361. with gr.Column(scale=1, elem_id="interrogate_col"):
  362. button_interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate")
  363. if cmd_opts.deepdanbooru:
  364. button_deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru")
  365. with gr.Column(scale=1):
  366. with gr.Row():
  367. skip = gr.Button('Skip', elem_id=f"{id_part}_skip")
  368. interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt")
  369. submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary')
  370. skip.click(
  371. fn=lambda: shared.state.skip(),
  372. inputs=[],
  373. outputs=[],
  374. )
  375. interrupt.click(
  376. fn=lambda: shared.state.interrupt(),
  377. inputs=[],
  378. outputs=[],
  379. )
  380. with gr.Row():
  381. with gr.Column(scale=1, elem_id="style_pos_col"):
  382. 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())))
  383. prompt_style.save_to_config = True
  384. with gr.Column(scale=1, elem_id="style_neg_col"):
  385. 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())))
  386. prompt_style2.save_to_config = True
  387. return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, button_interrogate, button_deepbooru, prompt_style_apply, save_style, paste, token_counter, token_button
  388. def setup_progressbar(progressbar, preview, id_part, textinfo=None):
  389. if textinfo is None:
  390. textinfo = gr.HTML(visible=False)
  391. check_progress = gr.Button('Check progress', elem_id=f"{id_part}_check_progress", visible=False)
  392. check_progress.click(
  393. fn=lambda: check_progress_call(id_part),
  394. show_progress=False,
  395. inputs=[],
  396. outputs=[progressbar, preview, preview, textinfo],
  397. )
  398. check_progress_initial = gr.Button('Check progress (first)', elem_id=f"{id_part}_check_progress_initial", visible=False)
  399. check_progress_initial.click(
  400. fn=lambda: check_progress_call_initial(id_part),
  401. show_progress=False,
  402. inputs=[],
  403. outputs=[progressbar, preview, preview, textinfo],
  404. )
  405. def apply_setting(key, value):
  406. if value is None:
  407. return gr.update()
  408. if key == "sd_model_checkpoint":
  409. ckpt_info = sd_models.get_closet_checkpoint_match(value)
  410. if ckpt_info is not None:
  411. value = ckpt_info.title
  412. else:
  413. return gr.update()
  414. comp_args = opts.data_labels[key].component_args
  415. if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False:
  416. return
  417. valtype = type(opts.data_labels[key].default)
  418. oldval = opts.data[key]
  419. opts.data[key] = valtype(value) if valtype != type(None) else value
  420. if oldval != value and opts.data_labels[key].onchange is not None:
  421. opts.data_labels[key].onchange()
  422. opts.save(shared.config_filename)
  423. return value
  424. def create_ui(wrap_gradio_gpu_call):
  425. import modules.img2img
  426. import modules.txt2img
  427. def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id):
  428. def refresh():
  429. refresh_method()
  430. args = refreshed_args() if callable(refreshed_args) else refreshed_args
  431. for k, v in args.items():
  432. setattr(refresh_component, k, v)
  433. return gr.update(**(args or {}))
  434. refresh_button = gr.Button(value=refresh_symbol, elem_id=elem_id)
  435. refresh_button.click(
  436. fn = refresh,
  437. inputs = [],
  438. outputs = [refresh_component]
  439. )
  440. return refresh_button
  441. with gr.Blocks(analytics_enabled=False) as txt2img_interface:
  442. txt2img_prompt, roll, 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)
  443. dummy_component = gr.Label(visible=False)
  444. txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="bytes", visible=False)
  445. with gr.Row(elem_id='txt2img_progress_row'):
  446. with gr.Column(scale=1):
  447. pass
  448. with gr.Column(scale=1):
  449. progressbar = gr.HTML(elem_id="txt2img_progressbar")
  450. txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False)
  451. setup_progressbar(progressbar, txt2img_preview, 'txt2img')
  452. with gr.Row().style(equal_height=False):
  453. with gr.Column(variant='panel'):
  454. steps = gr.Slider(minimum=1, maximum=150, step=1, label="Sampling Steps", value=20)
  455. sampler_index = gr.Radio(label='Sampling method', elem_id="txt2img_sampling", choices=[x.name for x in samplers], value=samplers[0].name, type="index")
  456. with gr.Group():
  457. width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512)
  458. height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512)
  459. with gr.Row():
  460. restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1)
  461. tiling = gr.Checkbox(label='Tiling', value=False)
  462. enable_hr = gr.Checkbox(label='Highres. fix', value=False)
  463. with gr.Row(visible=False) as hr_options:
  464. firstphase_width = gr.Slider(minimum=0, maximum=1024, step=64, label="Firstpass width", value=0)
  465. firstphase_height = gr.Slider(minimum=0, maximum=1024, step=64, label="Firstpass height", value=0)
  466. denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7)
  467. with gr.Row(equal_height=True):
  468. batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1)
  469. batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1)
  470. cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0)
  471. seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs()
  472. with gr.Group():
  473. custom_inputs = modules.scripts.scripts_txt2img.setup_ui(is_img2img=False)
  474. with gr.Column(variant='panel'):
  475. with gr.Group():
  476. txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False)
  477. txt2img_gallery = gr.Gallery(label='Output', show_label=False, elem_id='txt2img_gallery').style(grid=4)
  478. with gr.Column():
  479. with gr.Row():
  480. save = gr.Button('Save')
  481. send_to_img2img = gr.Button('Send to img2img')
  482. send_to_inpaint = gr.Button('Send to inpaint')
  483. send_to_extras = gr.Button('Send to extras')
  484. button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else 'open_folder'
  485. open_txt2img_folder = gr.Button(folder_symbol, elem_id=button_id)
  486. with gr.Row():
  487. do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False)
  488. with gr.Row():
  489. download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False)
  490. with gr.Group():
  491. html_info = gr.HTML()
  492. generation_info = gr.Textbox(visible=False)
  493. connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
  494. connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
  495. txt2img_args = dict(
  496. fn=wrap_gradio_gpu_call(modules.txt2img.txt2img),
  497. _js="submit",
  498. inputs=[
  499. txt2img_prompt,
  500. txt2img_negative_prompt,
  501. txt2img_prompt_style,
  502. txt2img_prompt_style2,
  503. steps,
  504. sampler_index,
  505. restore_faces,
  506. tiling,
  507. batch_count,
  508. batch_size,
  509. cfg_scale,
  510. seed,
  511. subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
  512. height,
  513. width,
  514. enable_hr,
  515. denoising_strength,
  516. firstphase_width,
  517. firstphase_height,
  518. ] + custom_inputs,
  519. outputs=[
  520. txt2img_gallery,
  521. generation_info,
  522. html_info
  523. ],
  524. show_progress=False,
  525. )
  526. txt2img_prompt.submit(**txt2img_args)
  527. submit.click(**txt2img_args)
  528. txt_prompt_img.change(
  529. fn=modules.images.image_data,
  530. inputs=[
  531. txt_prompt_img
  532. ],
  533. outputs=[
  534. txt2img_prompt,
  535. txt_prompt_img
  536. ]
  537. )
  538. enable_hr.change(
  539. fn=lambda x: gr_show(x),
  540. inputs=[enable_hr],
  541. outputs=[hr_options],
  542. )
  543. save.click(
  544. fn=wrap_gradio_call(save_files),
  545. _js="(x, y, z, w) => [x, y, z, selected_gallery_index()]",
  546. inputs=[
  547. generation_info,
  548. txt2img_gallery,
  549. do_make_zip,
  550. html_info,
  551. ],
  552. outputs=[
  553. download_files,
  554. html_info,
  555. html_info,
  556. html_info,
  557. ]
  558. )
  559. roll.click(
  560. fn=roll_artist,
  561. _js="update_txt2img_tokens",
  562. inputs=[
  563. txt2img_prompt,
  564. ],
  565. outputs=[
  566. txt2img_prompt,
  567. ]
  568. )
  569. txt2img_paste_fields = [
  570. (txt2img_prompt, "Prompt"),
  571. (txt2img_negative_prompt, "Negative prompt"),
  572. (steps, "Steps"),
  573. (sampler_index, "Sampler"),
  574. (restore_faces, "Face restoration"),
  575. (cfg_scale, "CFG scale"),
  576. (seed, "Seed"),
  577. (width, "Size-1"),
  578. (height, "Size-2"),
  579. (batch_size, "Batch size"),
  580. (subseed, "Variation seed"),
  581. (subseed_strength, "Variation seed strength"),
  582. (seed_resize_from_w, "Seed resize from-1"),
  583. (seed_resize_from_h, "Seed resize from-2"),
  584. (denoising_strength, "Denoising strength"),
  585. (enable_hr, lambda d: "Denoising strength" in d),
  586. (hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)),
  587. (firstphase_width, "First pass size-1"),
  588. (firstphase_height, "First pass size-2"),
  589. ]
  590. txt2img_preview_params = [
  591. txt2img_prompt,
  592. txt2img_negative_prompt,
  593. steps,
  594. sampler_index,
  595. cfg_scale,
  596. seed,
  597. width,
  598. height,
  599. ]
  600. token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter])
  601. with gr.Blocks(analytics_enabled=False) as img2img_interface:
  602. img2img_prompt, roll, 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)
  603. with gr.Row(elem_id='img2img_progress_row'):
  604. img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="bytes", visible=False)
  605. with gr.Column(scale=1):
  606. pass
  607. with gr.Column(scale=1):
  608. progressbar = gr.HTML(elem_id="img2img_progressbar")
  609. img2img_preview = gr.Image(elem_id='img2img_preview', visible=False)
  610. setup_progressbar(progressbar, img2img_preview, 'img2img')
  611. with gr.Row().style(equal_height=False):
  612. with gr.Column(variant='panel'):
  613. with gr.Tabs(elem_id="mode_img2img") as tabs_img2img_mode:
  614. with gr.TabItem('img2img', id='img2img'):
  615. 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).style(height=480)
  616. with gr.TabItem('Inpaint', id='inpaint'):
  617. 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)
  618. 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")
  619. init_mask_inpaint = gr.Image(label="Mask", source="upload", interactive=True, type="pil", visible=False, elem_id="img_inpaint_mask")
  620. mask_blur = gr.Slider(label='Mask blur', minimum=0, maximum=64, step=1, value=4)
  621. with gr.Row():
  622. mask_mode = gr.Radio(label="Mask mode", show_label=False, choices=["Draw mask", "Upload mask"], type="index", value="Draw mask", elem_id="mask_mode")
  623. inpainting_mask_invert = gr.Radio(label='Masking mode', show_label=False, choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index")
  624. inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index")
  625. with gr.Row():
  626. inpaint_full_res = gr.Checkbox(label='Inpaint at full resolution', value=False)
  627. inpaint_full_res_padding = gr.Slider(label='Inpaint at full resolution padding, pixels', minimum=0, maximum=256, step=4, value=32)
  628. with gr.TabItem('Batch img2img', id='batch'):
  629. hidden = '<br>Disabled when launched with --hide-ui-dir-config.' if shared.cmd_opts.hide_ui_dir_config else ''
  630. 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>")
  631. img2img_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs)
  632. img2img_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs)
  633. with gr.Row():
  634. resize_mode = gr.Radio(label="Resize mode", elem_id="resize_mode", show_label=False, choices=["Just resize", "Crop and resize", "Resize and fill"], type="index", value="Just resize")
  635. steps = gr.Slider(minimum=1, maximum=150, step=1, label="Sampling Steps", value=20)
  636. sampler_index = gr.Radio(label='Sampling method', choices=[x.name for x in samplers_for_img2img], value=samplers_for_img2img[0].name, type="index")
  637. with gr.Group():
  638. width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512)
  639. height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512)
  640. with gr.Row():
  641. restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1)
  642. tiling = gr.Checkbox(label='Tiling', value=False)
  643. with gr.Row():
  644. batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1)
  645. batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1)
  646. with gr.Group():
  647. cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0)
  648. denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.75)
  649. seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs()
  650. with gr.Group():
  651. custom_inputs = modules.scripts.scripts_img2img.setup_ui(is_img2img=True)
  652. with gr.Column(variant='panel'):
  653. with gr.Group():
  654. img2img_preview = gr.Image(elem_id='img2img_preview', visible=False)
  655. img2img_gallery = gr.Gallery(label='Output', show_label=False, elem_id='img2img_gallery').style(grid=4)
  656. with gr.Column():
  657. with gr.Row():
  658. save = gr.Button('Save')
  659. img2img_send_to_img2img = gr.Button('Send to img2img')
  660. img2img_send_to_inpaint = gr.Button('Send to inpaint')
  661. img2img_send_to_extras = gr.Button('Send to extras')
  662. button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else 'open_folder'
  663. open_img2img_folder = gr.Button(folder_symbol, elem_id=button_id)
  664. with gr.Row():
  665. do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False)
  666. with gr.Row():
  667. download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False)
  668. with gr.Group():
  669. html_info = gr.HTML()
  670. generation_info = gr.Textbox(visible=False)
  671. connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
  672. connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
  673. img2img_prompt_img.change(
  674. fn=modules.images.image_data,
  675. inputs=[
  676. img2img_prompt_img
  677. ],
  678. outputs=[
  679. img2img_prompt,
  680. img2img_prompt_img
  681. ]
  682. )
  683. mask_mode.change(
  684. lambda mode, img: {
  685. init_img_with_mask: gr_show(mode == 0),
  686. init_img_inpaint: gr_show(mode == 1),
  687. init_mask_inpaint: gr_show(mode == 1),
  688. },
  689. inputs=[mask_mode, init_img_with_mask],
  690. outputs=[
  691. init_img_with_mask,
  692. init_img_inpaint,
  693. init_mask_inpaint,
  694. ],
  695. )
  696. img2img_args = dict(
  697. fn=wrap_gradio_gpu_call(modules.img2img.img2img),
  698. _js="submit_img2img",
  699. inputs=[
  700. dummy_component,
  701. img2img_prompt,
  702. img2img_negative_prompt,
  703. img2img_prompt_style,
  704. img2img_prompt_style2,
  705. init_img,
  706. init_img_with_mask,
  707. init_img_inpaint,
  708. init_mask_inpaint,
  709. mask_mode,
  710. steps,
  711. sampler_index,
  712. mask_blur,
  713. inpainting_fill,
  714. restore_faces,
  715. tiling,
  716. batch_count,
  717. batch_size,
  718. cfg_scale,
  719. denoising_strength,
  720. seed,
  721. subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
  722. height,
  723. width,
  724. resize_mode,
  725. inpaint_full_res,
  726. inpaint_full_res_padding,
  727. inpainting_mask_invert,
  728. img2img_batch_input_dir,
  729. img2img_batch_output_dir,
  730. ] + custom_inputs,
  731. outputs=[
  732. img2img_gallery,
  733. generation_info,
  734. html_info
  735. ],
  736. show_progress=False,
  737. )
  738. img2img_prompt.submit(**img2img_args)
  739. submit.click(**img2img_args)
  740. img2img_interrogate.click(
  741. fn=interrogate,
  742. inputs=[init_img],
  743. outputs=[img2img_prompt],
  744. )
  745. if cmd_opts.deepdanbooru:
  746. img2img_deepbooru.click(
  747. fn=interrogate_deepbooru,
  748. inputs=[init_img],
  749. outputs=[img2img_prompt],
  750. )
  751. save.click(
  752. fn=wrap_gradio_call(save_files),
  753. _js="(x, y, z, w) => [x, y, z, selected_gallery_index()]",
  754. inputs=[
  755. generation_info,
  756. img2img_gallery,
  757. do_make_zip,
  758. html_info,
  759. ],
  760. outputs=[
  761. download_files,
  762. html_info,
  763. html_info,
  764. html_info,
  765. ]
  766. )
  767. roll.click(
  768. fn=roll_artist,
  769. _js="update_img2img_tokens",
  770. inputs=[
  771. img2img_prompt,
  772. ],
  773. outputs=[
  774. img2img_prompt,
  775. ]
  776. )
  777. prompts = [(txt2img_prompt, txt2img_negative_prompt), (img2img_prompt, img2img_negative_prompt)]
  778. style_dropdowns = [(txt2img_prompt_style, txt2img_prompt_style2), (img2img_prompt_style, img2img_prompt_style2)]
  779. style_js_funcs = ["update_txt2img_tokens", "update_img2img_tokens"]
  780. for button, (prompt, negative_prompt) in zip([txt2img_save_style, img2img_save_style], prompts):
  781. button.click(
  782. fn=add_style,
  783. _js="ask_for_style_name",
  784. # Have to pass empty dummy component here, because the JavaScript and Python function have to accept
  785. # the same number of parameters, but we only know the style-name after the JavaScript prompt
  786. inputs=[dummy_component, prompt, negative_prompt],
  787. outputs=[txt2img_prompt_style, img2img_prompt_style, txt2img_prompt_style2, img2img_prompt_style2],
  788. )
  789. 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):
  790. button.click(
  791. fn=apply_styles,
  792. _js=js_func,
  793. inputs=[prompt, negative_prompt, style1, style2],
  794. outputs=[prompt, negative_prompt, style1, style2],
  795. )
  796. img2img_paste_fields = [
  797. (img2img_prompt, "Prompt"),
  798. (img2img_negative_prompt, "Negative prompt"),
  799. (steps, "Steps"),
  800. (sampler_index, "Sampler"),
  801. (restore_faces, "Face restoration"),
  802. (cfg_scale, "CFG scale"),
  803. (seed, "Seed"),
  804. (width, "Size-1"),
  805. (height, "Size-2"),
  806. (batch_size, "Batch size"),
  807. (subseed, "Variation seed"),
  808. (subseed_strength, "Variation seed strength"),
  809. (seed_resize_from_w, "Seed resize from-1"),
  810. (seed_resize_from_h, "Seed resize from-2"),
  811. (denoising_strength, "Denoising strength"),
  812. ]
  813. token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter])
  814. with gr.Blocks(analytics_enabled=False) as extras_interface:
  815. with gr.Row().style(equal_height=False):
  816. with gr.Column(variant='panel'):
  817. with gr.Tabs(elem_id="mode_extras"):
  818. with gr.TabItem('Single Image'):
  819. extras_image = gr.Image(label="Source", source="upload", interactive=True, type="pil")
  820. with gr.TabItem('Batch Process'):
  821. image_batch = gr.File(label="Batch Process", file_count="multiple", interactive=True, type="file")
  822. with gr.TabItem('Batch from Directory'):
  823. extras_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs,
  824. placeholder="A directory on the same machine where the server is running."
  825. )
  826. extras_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs,
  827. placeholder="Leave blank to save images to the default path."
  828. )
  829. show_extras_results = gr.Checkbox(label='Show result images', value=True)
  830. with gr.Tabs(elem_id="extras_resize_mode"):
  831. with gr.TabItem('Scale by'):
  832. upscaling_resize = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Resize", value=2)
  833. with gr.TabItem('Scale to'):
  834. with gr.Group():
  835. with gr.Row():
  836. upscaling_resize_w = gr.Number(label="Width", value=512, precision=0)
  837. upscaling_resize_h = gr.Number(label="Height", value=512, precision=0)
  838. upscaling_crop = gr.Checkbox(label='Crop to fit', value=True)
  839. with gr.Group():
  840. 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")
  841. with gr.Group():
  842. extras_upscaler_2 = gr.Radio(label='Upscaler 2', celem_id="extras_upscaler_2", hoices=[x.name for x in shared.sd_upscalers], value=shared.sd_upscalers[0].name, type="index")
  843. extras_upscaler_2_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="Upscaler 2 visibility", value=1)
  844. with gr.Group():
  845. gfpgan_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="GFPGAN visibility", value=0, interactive=modules.gfpgan_model.have_gfpgan)
  846. with gr.Group():
  847. codeformer_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="CodeFormer visibility", value=0, interactive=modules.codeformer_model.have_codeformer)
  848. 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)
  849. submit = gr.Button('Generate', elem_id="extras_generate", variant='primary')
  850. with gr.Column(variant='panel'):
  851. result_images = gr.Gallery(label="Result", show_label=False)
  852. html_info_x = gr.HTML()
  853. html_info = gr.HTML()
  854. extras_send_to_img2img = gr.Button('Send to img2img')
  855. extras_send_to_inpaint = gr.Button('Send to inpaint')
  856. button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else ''
  857. open_extras_folder = gr.Button('Open output directory', elem_id=button_id)
  858. submit.click(
  859. fn=wrap_gradio_gpu_call(modules.extras.run_extras),
  860. _js="get_extras_tab_index",
  861. inputs=[
  862. dummy_component,
  863. dummy_component,
  864. extras_image,
  865. image_batch,
  866. extras_batch_input_dir,
  867. extras_batch_output_dir,
  868. show_extras_results,
  869. gfpgan_visibility,
  870. codeformer_visibility,
  871. codeformer_weight,
  872. upscaling_resize,
  873. upscaling_resize_w,
  874. upscaling_resize_h,
  875. upscaling_crop,
  876. extras_upscaler_1,
  877. extras_upscaler_2,
  878. extras_upscaler_2_visibility,
  879. ],
  880. outputs=[
  881. result_images,
  882. html_info_x,
  883. html_info,
  884. ]
  885. )
  886. extras_send_to_img2img.click(
  887. fn=lambda x: image_from_url_text(x),
  888. _js="extract_image_from_gallery_img2img",
  889. inputs=[result_images],
  890. outputs=[init_img],
  891. )
  892. extras_send_to_inpaint.click(
  893. fn=lambda x: image_from_url_text(x),
  894. _js="extract_image_from_gallery_inpaint",
  895. inputs=[result_images],
  896. outputs=[init_img_with_mask],
  897. )
  898. with gr.Blocks(analytics_enabled=False) as pnginfo_interface:
  899. with gr.Row().style(equal_height=False):
  900. with gr.Column(variant='panel'):
  901. image = gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil")
  902. with gr.Column(variant='panel'):
  903. html = gr.HTML()
  904. generation_info = gr.Textbox(visible=False)
  905. html2 = gr.HTML()
  906. with gr.Row():
  907. pnginfo_send_to_txt2img = gr.Button('Send to txt2img')
  908. pnginfo_send_to_img2img = gr.Button('Send to img2img')
  909. image.change(
  910. fn=wrap_gradio_call(modules.extras.run_pnginfo),
  911. inputs=[image],
  912. outputs=[html, generation_info, html2],
  913. )
  914. #images history
  915. images_history_switch_dict = {
  916. "fn":modules.generation_parameters_copypaste.connect_paste,
  917. "t2i":txt2img_paste_fields,
  918. "i2i":img2img_paste_fields
  919. }
  920. images_history = img_his.create_history_tabs(gr, opts, wrap_gradio_call(modules.extras.run_pnginfo), images_history_switch_dict)
  921. with gr.Blocks() as modelmerger_interface:
  922. with gr.Row().style(equal_height=False):
  923. with gr.Column(variant='panel'):
  924. gr.HTML(value="<p>A merger of the two checkpoints will be generated in your <b>checkpoint</b> directory.</p>")
  925. with gr.Row():
  926. primary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_primary_model_name", label="Primary model (A)")
  927. secondary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_secondary_model_name", label="Secondary model (B)")
  928. tertiary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_tertiary_model_name", label="Tertiary model (C)")
  929. custom_name = gr.Textbox(label="Custom Name (Optional)")
  930. 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)
  931. interp_method = gr.Radio(choices=["Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method")
  932. save_as_half = gr.Checkbox(value=False, label="Save as float16")
  933. modelmerger_merge = gr.Button(elem_id="modelmerger_merge", label="Merge", variant='primary')
  934. with gr.Column(variant='panel'):
  935. submit_result = gr.Textbox(elem_id="modelmerger_result", show_label=False)
  936. sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings()
  937. with gr.Blocks() as train_interface:
  938. with gr.Row().style(equal_height=False):
  939. 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>")
  940. with gr.Row().style(equal_height=False):
  941. with gr.Tabs(elem_id="train_tabs"):
  942. with gr.Tab(label="Create embedding"):
  943. new_embedding_name = gr.Textbox(label="Name")
  944. initialization_text = gr.Textbox(label="Initialization text", value="*")
  945. nvpt = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1)
  946. with gr.Row():
  947. with gr.Column(scale=3):
  948. gr.HTML(value="")
  949. with gr.Column():
  950. create_embedding = gr.Button(value="Create embedding", variant='primary')
  951. with gr.Tab(label="Create hypernetwork"):
  952. new_hypernetwork_name = gr.Textbox(label="Name")
  953. new_hypernetwork_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "320", "640", "1280"])
  954. with gr.Row():
  955. with gr.Column(scale=3):
  956. gr.HTML(value="")
  957. with gr.Column():
  958. create_hypernetwork = gr.Button(value="Create hypernetwork", variant='primary')
  959. with gr.Tab(label="Preprocess images"):
  960. process_src = gr.Textbox(label='Source directory')
  961. process_dst = gr.Textbox(label='Destination directory')
  962. process_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512)
  963. process_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512)
  964. with gr.Row():
  965. process_flip = gr.Checkbox(label='Create flipped copies')
  966. process_split = gr.Checkbox(label='Split oversized images into two')
  967. process_caption = gr.Checkbox(label='Use BLIP for caption')
  968. process_caption_deepbooru = gr.Checkbox(label='Use deepbooru for caption', visible=True if cmd_opts.deepdanbooru else False)
  969. with gr.Row():
  970. with gr.Column(scale=3):
  971. gr.HTML(value="")
  972. with gr.Column():
  973. run_preprocess = gr.Button(value="Preprocess", variant='primary')
  974. with gr.Tab(label="Train"):
  975. gr.HTML(value="<p style='margin-bottom: 0.7em'>Train an embedding; must specify a directory with a set of 1:1 ratio images</p>")
  976. with gr.Row():
  977. train_embedding_name = gr.Dropdown(label='Embedding', elem_id="train_embedding", choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys()))
  978. 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")
  979. with gr.Row():
  980. train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', elem_id="train_hypernetwork", choices=[x for x in shared.hypernetworks.keys()])
  981. create_refresh_button(train_hypernetwork_name, shared.reload_hypernetworks, lambda: {"choices": sorted([x for x in shared.hypernetworks.keys()])}, "refresh_train_hypernetwork_name")
  982. learn_rate = gr.Textbox(label='Learning rate', placeholder="Learning rate", value="0.005")
  983. batch_size = gr.Number(label='Batch size', value=1, precision=0)
  984. dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images")
  985. log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion")
  986. template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt"))
  987. training_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512)
  988. training_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512)
  989. steps = gr.Number(label='Max steps', value=100000, precision=0)
  990. create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0)
  991. save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0)
  992. save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True)
  993. preview_from_txt2img = gr.Checkbox(label='Read parameters (prompt, etc...) from txt2img tab when making previews', value=False)
  994. with gr.Row():
  995. interrupt_training = gr.Button(value="Interrupt")
  996. train_hypernetwork = gr.Button(value="Train Hypernetwork", variant='primary')
  997. train_embedding = gr.Button(value="Train Embedding", variant='primary')
  998. with gr.Column():
  999. progressbar = gr.HTML(elem_id="ti_progressbar")
  1000. ti_output = gr.Text(elem_id="ti_output", value="", show_label=False)
  1001. ti_gallery = gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(grid=4)
  1002. ti_preview = gr.Image(elem_id='ti_preview', visible=False)
  1003. ti_progress = gr.HTML(elem_id="ti_progress", value="")
  1004. ti_outcome = gr.HTML(elem_id="ti_error", value="")
  1005. setup_progressbar(progressbar, ti_preview, 'ti', textinfo=ti_progress)
  1006. create_embedding.click(
  1007. fn=modules.textual_inversion.ui.create_embedding,
  1008. inputs=[
  1009. new_embedding_name,
  1010. initialization_text,
  1011. nvpt,
  1012. ],
  1013. outputs=[
  1014. train_embedding_name,
  1015. ti_output,
  1016. ti_outcome,
  1017. ]
  1018. )
  1019. create_hypernetwork.click(
  1020. fn=modules.hypernetworks.ui.create_hypernetwork,
  1021. inputs=[
  1022. new_hypernetwork_name,
  1023. new_hypernetwork_sizes,
  1024. ],
  1025. outputs=[
  1026. train_hypernetwork_name,
  1027. ti_output,
  1028. ti_outcome,
  1029. ]
  1030. )
  1031. run_preprocess.click(
  1032. fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]),
  1033. _js="start_training_textual_inversion",
  1034. inputs=[
  1035. process_src,
  1036. process_dst,
  1037. process_width,
  1038. process_height,
  1039. process_flip,
  1040. process_split,
  1041. process_caption,
  1042. process_caption_deepbooru
  1043. ],
  1044. outputs=[
  1045. ti_output,
  1046. ti_outcome,
  1047. ],
  1048. )
  1049. train_embedding.click(
  1050. fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]),
  1051. _js="start_training_textual_inversion",
  1052. inputs=[
  1053. train_embedding_name,
  1054. learn_rate,
  1055. batch_size,
  1056. dataset_directory,
  1057. log_directory,
  1058. training_width,
  1059. training_height,
  1060. steps,
  1061. create_image_every,
  1062. save_embedding_every,
  1063. template_file,
  1064. save_image_with_stored_embedding,
  1065. preview_from_txt2img,
  1066. *txt2img_preview_params,
  1067. ],
  1068. outputs=[
  1069. ti_output,
  1070. ti_outcome,
  1071. ]
  1072. )
  1073. train_hypernetwork.click(
  1074. fn=wrap_gradio_gpu_call(modules.hypernetworks.ui.train_hypernetwork, extra_outputs=[gr.update()]),
  1075. _js="start_training_textual_inversion",
  1076. inputs=[
  1077. train_hypernetwork_name,
  1078. learn_rate,
  1079. batch_size,
  1080. dataset_directory,
  1081. log_directory,
  1082. steps,
  1083. create_image_every,
  1084. save_embedding_every,
  1085. template_file,
  1086. preview_from_txt2img,
  1087. *txt2img_preview_params,
  1088. ],
  1089. outputs=[
  1090. ti_output,
  1091. ti_outcome,
  1092. ]
  1093. )
  1094. interrupt_training.click(
  1095. fn=lambda: shared.state.interrupt(),
  1096. inputs=[],
  1097. outputs=[],
  1098. )
  1099. def create_setting_component(key, is_quicksettings=False):
  1100. def fun():
  1101. return opts.data[key] if key in opts.data else opts.data_labels[key].default
  1102. info = opts.data_labels[key]
  1103. t = type(info.default)
  1104. args = info.component_args() if callable(info.component_args) else info.component_args
  1105. if info.component is not None:
  1106. comp = info.component
  1107. elif t == str:
  1108. comp = gr.Textbox
  1109. elif t == int:
  1110. comp = gr.Number
  1111. elif t == bool:
  1112. comp = gr.Checkbox
  1113. else:
  1114. raise Exception(f'bad options item type: {str(t)} for key {key}')
  1115. elem_id = "setting_"+key
  1116. if info.refresh is not None:
  1117. if is_quicksettings:
  1118. res = comp(label=info.label, value=fun, elem_id=elem_id, **(args or {}))
  1119. create_refresh_button(res, info.refresh, info.component_args, "refresh_" + key)
  1120. else:
  1121. with gr.Row(variant="compact"):
  1122. res = comp(label=info.label, value=fun, elem_id=elem_id, **(args or {}))
  1123. create_refresh_button(res, info.refresh, info.component_args, "refresh_" + key)
  1124. else:
  1125. res = comp(label=info.label, value=fun, elem_id=elem_id, **(args or {}))
  1126. return res
  1127. components = []
  1128. component_dict = {}
  1129. def open_folder(f):
  1130. if not os.path.exists(f):
  1131. print(f'Folder "{f}" does not exist. After you create an image, the folder will be created.')
  1132. return
  1133. elif not os.path.isdir(f):
  1134. print(f"""
  1135. WARNING
  1136. An open_folder request was made with an argument that is not a folder.
  1137. This could be an error or a malicious attempt to run code on your computer.
  1138. Requested path was: {f}
  1139. """, file=sys.stderr)
  1140. return
  1141. if not shared.cmd_opts.hide_ui_dir_config:
  1142. path = os.path.normpath(f)
  1143. if platform.system() == "Windows":
  1144. os.startfile(path)
  1145. elif platform.system() == "Darwin":
  1146. sp.Popen(["open", path])
  1147. else:
  1148. sp.Popen(["xdg-open", path])
  1149. def run_settings(*args):
  1150. changed = 0
  1151. for key, value, comp in zip(opts.data_labels.keys(), args, components):
  1152. if comp != dummy_component and not opts.same_type(value, opts.data_labels[key].default):
  1153. return f"Bad value for setting {key}: {value}; expecting {type(opts.data_labels[key].default).__name__}", opts.dumpjson()
  1154. for key, value, comp in zip(opts.data_labels.keys(), args, components):
  1155. if comp == dummy_component:
  1156. continue
  1157. comp_args = opts.data_labels[key].component_args
  1158. if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False:
  1159. continue
  1160. if cmd_opts.hide_ui_dir_config and key in restricted_opts:
  1161. continue
  1162. oldval = opts.data.get(key, None)
  1163. opts.data[key] = value
  1164. if oldval != value:
  1165. if opts.data_labels[key].onchange is not None:
  1166. opts.data_labels[key].onchange()
  1167. changed += 1
  1168. opts.save(shared.config_filename)
  1169. return f'{changed} settings changed.', opts.dumpjson()
  1170. def run_settings_single(value, key):
  1171. if not opts.same_type(value, opts.data_labels[key].default):
  1172. return gr.update(visible=True), opts.dumpjson()
  1173. if cmd_opts.hide_ui_dir_config and key in restricted_opts:
  1174. return gr.update(value=oldval), opts.dumpjson()
  1175. oldval = opts.data.get(key, None)
  1176. opts.data[key] = value
  1177. if oldval != value:
  1178. if opts.data_labels[key].onchange is not None:
  1179. opts.data_labels[key].onchange()
  1180. opts.save(shared.config_filename)
  1181. return gr.update(value=value), opts.dumpjson()
  1182. with gr.Blocks(analytics_enabled=False) as settings_interface:
  1183. settings_submit = gr.Button(value="Apply settings", variant='primary')
  1184. result = gr.HTML()
  1185. settings_cols = 3
  1186. items_per_col = int(len(opts.data_labels) * 0.9 / settings_cols)
  1187. quicksettings_names = [x.strip() for x in opts.quicksettings.split(",")]
  1188. quicksettings_names = set(x for x in quicksettings_names if x != 'quicksettings')
  1189. quicksettings_list = []
  1190. cols_displayed = 0
  1191. items_displayed = 0
  1192. previous_section = None
  1193. column = None
  1194. with gr.Row(elem_id="settings").style(equal_height=False):
  1195. for i, (k, item) in enumerate(opts.data_labels.items()):
  1196. if previous_section != item.section:
  1197. if cols_displayed < settings_cols and (items_displayed >= items_per_col or previous_section is None):
  1198. if column is not None:
  1199. column.__exit__()
  1200. column = gr.Column(variant='panel')
  1201. column.__enter__()
  1202. items_displayed = 0
  1203. cols_displayed += 1
  1204. previous_section = item.section
  1205. gr.HTML(elem_id="settings_header_text_{}".format(item.section[0]), value='<h1 class="gr-button-lg">{}</h1>'.format(item.section[1]))
  1206. if k in quicksettings_names:
  1207. quicksettings_list.append((i, k, item))
  1208. components.append(dummy_component)
  1209. else:
  1210. component = create_setting_component(k)
  1211. component_dict[k] = component
  1212. components.append(component)
  1213. items_displayed += 1
  1214. with gr.Row():
  1215. request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications")
  1216. download_localization = gr.Button(value='Download localization template', elem_id="download_localization")
  1217. with gr.Row():
  1218. reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary')
  1219. restart_gradio = gr.Button(value='Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)', variant='primary')
  1220. request_notifications.click(
  1221. fn=lambda: None,
  1222. inputs=[],
  1223. outputs=[],
  1224. _js='function(){}'
  1225. )
  1226. download_localization.click(
  1227. fn=lambda: None,
  1228. inputs=[],
  1229. outputs=[],
  1230. _js='download_localization'
  1231. )
  1232. def reload_scripts():
  1233. modules.scripts.reload_script_body_only()
  1234. reload_script_bodies.click(
  1235. fn=reload_scripts,
  1236. inputs=[],
  1237. outputs=[],
  1238. _js='function(){}'
  1239. )
  1240. def request_restart():
  1241. shared.state.interrupt()
  1242. settings_interface.gradio_ref.do_restart = True
  1243. restart_gradio.click(
  1244. fn=request_restart,
  1245. inputs=[],
  1246. outputs=[],
  1247. _js='function(){restart_reload()}'
  1248. )
  1249. if column is not None:
  1250. column.__exit__()
  1251. interfaces = [
  1252. (txt2img_interface, "txt2img", "txt2img"),
  1253. (img2img_interface, "img2img", "img2img"),
  1254. (extras_interface, "Extras", "extras"),
  1255. (pnginfo_interface, "PNG Info", "pnginfo"),
  1256. (images_history, "History", "images_history"),
  1257. (modelmerger_interface, "Checkpoint Merger", "modelmerger"),
  1258. (train_interface, "Train", "ti"),
  1259. (settings_interface, "Settings", "settings"),
  1260. ]
  1261. with open(os.path.join(script_path, "style.css"), "r", encoding="utf8") as file:
  1262. css = file.read()
  1263. if os.path.exists(os.path.join(script_path, "user.css")):
  1264. with open(os.path.join(script_path, "user.css"), "r", encoding="utf8") as file:
  1265. usercss = file.read()
  1266. css += usercss
  1267. if not cmd_opts.no_progressbar_hiding:
  1268. css += css_hide_progressbar
  1269. with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo:
  1270. with gr.Row(elem_id="quicksettings"):
  1271. for i, k, item in quicksettings_list:
  1272. component = create_setting_component(k, is_quicksettings=True)
  1273. component_dict[k] = component
  1274. settings_interface.gradio_ref = demo
  1275. with gr.Tabs(elem_id="tabs") as tabs:
  1276. for interface, label, ifid in interfaces:
  1277. with gr.TabItem(label, id=ifid, elem_id='tab_' + ifid):
  1278. interface.render()
  1279. if os.path.exists(os.path.join(script_path, "notification.mp3")):
  1280. audio_notification = gr.Audio(interactive=False, value=os.path.join(script_path, "notification.mp3"), elem_id="audio_notification", visible=False)
  1281. text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False)
  1282. settings_submit.click(
  1283. fn=run_settings,
  1284. inputs=components,
  1285. outputs=[result, text_settings],
  1286. )
  1287. for i, k, item in quicksettings_list:
  1288. component = component_dict[k]
  1289. component.change(
  1290. fn=lambda value, k=k: run_settings_single(value, key=k),
  1291. inputs=[component],
  1292. outputs=[component, text_settings],
  1293. )
  1294. def modelmerger(*args):
  1295. try:
  1296. results = modules.extras.run_modelmerger(*args)
  1297. except Exception as e:
  1298. print("Error loading/saving model file:", file=sys.stderr)
  1299. print(traceback.format_exc(), file=sys.stderr)
  1300. modules.sd_models.list_models() # to remove the potentially missing models from the list
  1301. return ["Error loading/saving model file. It doesn't exist or the name contains illegal characters"] + [gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(3)]
  1302. return results
  1303. modelmerger_merge.click(
  1304. fn=modelmerger,
  1305. inputs=[
  1306. primary_model_name,
  1307. secondary_model_name,
  1308. tertiary_model_name,
  1309. interp_method,
  1310. interp_amount,
  1311. save_as_half,
  1312. custom_name,
  1313. ],
  1314. outputs=[
  1315. submit_result,
  1316. primary_model_name,
  1317. secondary_model_name,
  1318. tertiary_model_name,
  1319. component_dict['sd_model_checkpoint'],
  1320. ]
  1321. )
  1322. paste_field_names = ['Prompt', 'Negative prompt', 'Steps', 'Face restoration', 'Seed', 'Size-1', 'Size-2']
  1323. txt2img_fields = [field for field,name in txt2img_paste_fields if name in paste_field_names]
  1324. img2img_fields = [field for field,name in img2img_paste_fields if name in paste_field_names]
  1325. send_to_img2img.click(
  1326. fn=lambda img, *args: (image_from_url_text(img),*args),
  1327. _js="(gallery, ...args) => [extract_image_from_gallery_img2img(gallery), ...args]",
  1328. inputs=[txt2img_gallery] + txt2img_fields,
  1329. outputs=[init_img] + img2img_fields,
  1330. )
  1331. send_to_inpaint.click(
  1332. fn=lambda x, *args: (image_from_url_text(x), *args),
  1333. _js="(gallery, ...args) => [extract_image_from_gallery_inpaint(gallery), ...args]",
  1334. inputs=[txt2img_gallery] + txt2img_fields,
  1335. outputs=[init_img_with_mask] + img2img_fields,
  1336. )
  1337. img2img_send_to_img2img.click(
  1338. fn=lambda x: image_from_url_text(x),
  1339. _js="extract_image_from_gallery_img2img",
  1340. inputs=[img2img_gallery],
  1341. outputs=[init_img],
  1342. )
  1343. img2img_send_to_inpaint.click(
  1344. fn=lambda x: image_from_url_text(x),
  1345. _js="extract_image_from_gallery_inpaint",
  1346. inputs=[img2img_gallery],
  1347. outputs=[init_img_with_mask],
  1348. )
  1349. send_to_extras.click(
  1350. fn=lambda x: image_from_url_text(x),
  1351. _js="extract_image_from_gallery_extras",
  1352. inputs=[txt2img_gallery],
  1353. outputs=[extras_image],
  1354. )
  1355. open_txt2img_folder.click(
  1356. fn=lambda: open_folder(opts.outdir_samples or opts.outdir_txt2img_samples),
  1357. inputs=[],
  1358. outputs=[],
  1359. )
  1360. open_img2img_folder.click(
  1361. fn=lambda: open_folder(opts.outdir_samples or opts.outdir_img2img_samples),
  1362. inputs=[],
  1363. outputs=[],
  1364. )
  1365. open_extras_folder.click(
  1366. fn=lambda: open_folder(opts.outdir_samples or opts.outdir_extras_samples),
  1367. inputs=[],
  1368. outputs=[],
  1369. )
  1370. img2img_send_to_extras.click(
  1371. fn=lambda x: image_from_url_text(x),
  1372. _js="extract_image_from_gallery_extras",
  1373. inputs=[img2img_gallery],
  1374. outputs=[extras_image],
  1375. )
  1376. settings_map = {
  1377. 'sd_hypernetwork': 'Hypernet',
  1378. 'CLIP_stop_at_last_layers': 'Clip skip',
  1379. 'sd_model_checkpoint': 'Model hash',
  1380. }
  1381. settings_paste_fields = [
  1382. (component_dict[k], lambda d, k=k, v=v: apply_setting(k, d.get(v, None)))
  1383. for k, v in settings_map.items()
  1384. ]
  1385. modules.generation_parameters_copypaste.connect_paste(txt2img_paste, txt2img_paste_fields + settings_paste_fields, txt2img_prompt)
  1386. modules.generation_parameters_copypaste.connect_paste(img2img_paste, img2img_paste_fields + settings_paste_fields, img2img_prompt)
  1387. modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_txt2img, txt2img_paste_fields + settings_paste_fields, generation_info, 'switch_to_txt2img')
  1388. modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_img2img, img2img_paste_fields + settings_paste_fields, generation_info, 'switch_to_img2img_img2img')
  1389. ui_config_file = cmd_opts.ui_config_file
  1390. ui_settings = {}
  1391. settings_count = len(ui_settings)
  1392. error_loading = False
  1393. try:
  1394. if os.path.exists(ui_config_file):
  1395. with open(ui_config_file, "r", encoding="utf8") as file:
  1396. ui_settings = json.load(file)
  1397. except Exception:
  1398. error_loading = True
  1399. print("Error loading settings:", file=sys.stderr)
  1400. print(traceback.format_exc(), file=sys.stderr)
  1401. def loadsave(path, x):
  1402. def apply_field(obj, field, condition=None):
  1403. key = path + "/" + field
  1404. if getattr(obj,'custom_script_source',None) is not None:
  1405. key = 'customscript/' + obj.custom_script_source + '/' + key
  1406. if getattr(obj, 'do_not_save_to_config', False):
  1407. return
  1408. saved_value = ui_settings.get(key, None)
  1409. if saved_value is None:
  1410. ui_settings[key] = getattr(obj, field)
  1411. elif condition and not condition(saved_value):
  1412. print(f'Warning: Bad ui setting value: {key}: {saved_value}; Default value "{getattr(obj, field)}" will be used instead.')
  1413. else:
  1414. setattr(obj, field, saved_value)
  1415. if type(x) in [gr.Slider, gr.Radio, gr.Checkbox, gr.Textbox, gr.Number] and x.visible:
  1416. apply_field(x, 'visible')
  1417. if type(x) == gr.Slider:
  1418. apply_field(x, 'value')
  1419. apply_field(x, 'minimum')
  1420. apply_field(x, 'maximum')
  1421. apply_field(x, 'step')
  1422. if type(x) == gr.Radio:
  1423. apply_field(x, 'value', lambda val: val in x.choices)
  1424. if type(x) == gr.Checkbox:
  1425. apply_field(x, 'value')
  1426. if type(x) == gr.Textbox:
  1427. apply_field(x, 'value')
  1428. if type(x) == gr.Number:
  1429. apply_field(x, 'value')
  1430. # Since there are many dropdowns that shouldn't be saved,
  1431. # we only mark dropdowns that should be saved.
  1432. if type(x) == gr.Dropdown and getattr(x, 'save_to_config', False):
  1433. apply_field(x, 'value', lambda val: val in x.choices)
  1434. visit(txt2img_interface, loadsave, "txt2img")
  1435. visit(img2img_interface, loadsave, "img2img")
  1436. visit(extras_interface, loadsave, "extras")
  1437. visit(modelmerger_interface, loadsave, "modelmerger")
  1438. if not error_loading and (not os.path.exists(ui_config_file) or settings_count != len(ui_settings)):
  1439. with open(ui_config_file, "w", encoding="utf8") as file:
  1440. json.dump(ui_settings, file, indent=4)
  1441. return demo
  1442. with open(os.path.join(script_path, "script.js"), "r", encoding="utf8") as jsfile:
  1443. javascript = f'<script>{jsfile.read()}</script>'
  1444. jsdir = os.path.join(script_path, "javascript")
  1445. for filename in sorted(os.listdir(jsdir)):
  1446. with open(os.path.join(jsdir, filename), "r", encoding="utf8") as jsfile:
  1447. javascript += f"\n<script>{jsfile.read()}</script>"
  1448. javascript += f"\n<script>{localization.localization_js(shared.opts.localization)}</script>"
  1449. if 'gradio_routes_templates_response' not in globals():
  1450. def template_response(*args, **kwargs):
  1451. res = gradio_routes_templates_response(*args, **kwargs)
  1452. res.body = res.body.replace(b'</head>', f'{javascript}</head>'.encode("utf8"))
  1453. res.init_headers()
  1454. return res
  1455. gradio_routes_templates_response = gradio.routes.templates.TemplateResponse
  1456. gradio.routes.templates.TemplateResponse = template_response