import torchruntime import platform gpus = torchruntime.device_db.get_gpus() torch_platform = torchruntime.platform_detection.get_torch_platform(gpus) os_platform = platform.system() # Some platform checks if torch_platform == "xpu" and not os_platform == "Windows": torch_platform == "cpu" if torch_platform == "mps" and not os_platform == "Darwin": torch_platform == "cpu" from argparser import args import comfy.cli_args comfy.cli_args.args.cpu = args.cpu comfy.cli_args.args.highvram = args.highvram comfy.cli_args.args.normalvram = args.normalvram comfy.cli_args.args.lowvram = args.lowvram comfy.cli_args.args.novram = args.novram comfy.cli_args.args.reserve_vram = args.reserve_vram comfy.cli_args.args.cpu_vae = args.cpu_vae # FIXME: Should brobably also check directml and other things... if torch_platform == "cpu": comfy.cli_args.args.cpu = True from pathlib import Path import shared from shared import ( state, add_ctrl, performance_settings, resolution_settings, path_manager, settings, ) import time import json import gradio as gr import re import version import modules.async_worker as worker import modules.html import modules.hints import ui_onebutton import ui_controlnet from modules.api import add_api from modules.interrogate import look from comfy.samplers import KSampler from modules.sdxl_styles import load_styles, styles, allstyles, apply_style from modules.prompt_processing import get_promptlist from modules.util import ( get_wildcard_files, load_keywords, get_checkpoint_thumbnail, get_lora_thumbnail, get_model_thumbnail, get_checkpoint_path, get_lora_path, ) from modules.imagebrowser import ImageBrowser import ui_image_gallery import ui_llama_chat import ui_settings from PIL import Image inpaint_toggle = None shared.shared_cache["browser"] = ImageBrowser() def find_unclosed_markers(s): markers = re.findall(r"__", s) for marker in markers: if s.count(marker) % 2 != 0: return s.split(marker)[-1] return None def launch_app(args): inbrowser = not args.nobrowser favicon_path = "logo.ico" shared.gradio_root.queue(api_open=True) # Create theme for main interface if "theme" not in settings or settings["theme"] in ["", "None", None]: theme = gr.themes.Default() else: try: theme = gr.Theme.from_hub(settings["theme"]) except: print(f"ERROR: Could not find theme {settings['theme']}. Check https://huggingface.co/spaces/gradio/theme-gallery for themes") theme = gr.themes.Default() # Override some settings theme.spacing_lg = '8px' theme.spacing_md = '6px' theme.spacing_sm = '4px' theme.spacing_xl = '8px' theme.spacing_xs = '2px' theme.spacing_xxl = '2px' theme.spacing_xxs = '1px' theme.text_xxl = '8px' # Create the image gallery from the new module app_image_browser = ui_image_gallery.create_image_gallery() app_llama_chat = ui_llama_chat.create_chat() app_settings = ui_settings.create_settings() main_tabs = gr.TabbedInterface( [shared.gradio_root, app_image_browser, app_llama_chat, app_settings], ["Main", "Image browser", "Chat bot", "Settings"], theme=theme, title="RuinedFooocus " + version.version, css=modules.html.css, js=modules.html.scripts, analytics_enabled=False, ) main_tabs.launch( inbrowser=inbrowser, server_name=args.listen, server_port=args.port, share=args.share, auth=( args.auth.split("/", 1) if isinstance(args.auth, str) and "/" in args.auth else None ), favicon_path=favicon_path, allowed_paths=["html", "/", path_manager.model_paths["temp_outputs_path"]] + settings.get("archive_folders", []), enable_monitoring=False, pwa=True, ) def update_clicked(): return { run_button: gr.update(interactive=False, visible=False), stop_button: gr.update(interactive=True, visible=True), progress_html: gr.update( visible=True, value=modules.html.make_progress_html(0, "Please wait ..."), ), gallery: gr.update(visible=False), main_view: gr.update(visible=True, value="html/init_image.png"), inpaint_view: gr.update( visible=False, interactive=False, ), hint_text: gr.update(visible=True, value=modules.hints.get_hint()), } def update_preview(product): percentage, title, image = product return { run_button: gr.update(interactive=False, visible=False), stop_button: gr.update(interactive=True, visible=True), progress_html: gr.update( visible=True, value=modules.html.make_progress_html(percentage, title) ), main_view: ( gr.update(visible=True, value=image) if image is not None else gr.update() ), } def update_results(product): metadata = {"Data": "Preview Grid"} if len(product) > 0: with Image.open(product[0]) as im: if im.info.get("parameters"): metadata = im.info["parameters"] return { run_button: gr.update(interactive=True, visible=True), stop_button: gr.update(interactive=False, visible=False), progress_html: gr.update(visible=False), main_view: gr.update(value=product[0]) if len(product) > 0 else gr.update(), inpaint_toggle: gr.update(value=False), gallery: gr.update( visible=True, selected_index=0, allow_preview=True, preview=True, value=product, ), metadata_json: gr.update(value=metadata), } def append_work(gen_data): tmp_data = gen_data.copy() if tmp_data["obp_assume_direct_control"]: prompts = [] prompts.append("") else: prompts = get_promptlist(tmp_data) idx = 0 tmp_data["image_total"] = len(prompts) * tmp_data["image_number"] tmp_data["task_type"] = "process" if len(prompts) == 1: tmp_data["prompt"] = prompts[0] else: tmp_data["prompt"] = prompts task_id = worker.add_task(tmp_data.copy()) return task_id def generate_clicked(*args): global status yield update_clicked() gen_data = {} for key, val in zip(state["ctrls_name"], args): gen_data[key] = val # FIXME this is _ugly_ run_event gets triggerd once at page load # not really gradios fault, we are doing silly things there. :) if gen_data["run_event"] < 1: yield update_results(["html/logo.png"]) return gen_data["generate_forever"] = int(gen_data["image_number"]) == 0 task_id = append_work(gen_data) shared.state["interrupted"] = False finished = False while not finished: flag, product = worker.task_result(task_id) if flag == "preview": yield update_preview(product) elif flag == "results": yield update_results(product) finished = True time.sleep(0.1) shared.state["interrupted"] = False settings = settings.default_settings metadata_json = gr.Json() shared.wildcards = get_wildcard_files() shared.gradio_root = gr.Blocks().queue() with shared.gradio_root as block: block.load() run_event = gr.Number(visible=False, value=0) add_ctrl("run_event", run_event) def get_cfg_timestamp(): return shared.state["last_config"] cfg_timestamp = gr.Textbox(visible=False, value=get_cfg_timestamp, every=5) with gr.Row(): with gr.Column(scale=5): main_view = gr.Image( value="html/init_image.png", height=680, type="filepath", visible=True, show_label=False, show_fullscreen_button=True, show_download_button=True, ) add_ctrl("main_view", main_view) inpaint_view = gr.ImageEditor( height=680, type="numpy", visible=False, show_label=False, show_fullscreen_button=True, show_download_button=True, layers=False, interactive=False, transforms=(), brush=gr.Brush(colors=["#000000"], color_mode="fixed"), ) add_ctrl("inpaint_view", inpaint_view) progress_html = gr.HTML( value=modules.html.make_progress_html(32, "Progress 32%"), visible=False, padding=False, elem_id="progress-bar", elem_classes="progress-bar", ) gallery = gr.Gallery( label=None, show_label=False, object_fit="scale-down", height=60, allow_preview=False, preview=False, interactive=False, visible=True, show_download_button=False, show_fullscreen_button=False, ) @gallery.select( inputs=[gallery], outputs=[main_view, metadata_json], show_progress="hidden", ) def gallery_change(files, sd: gr.SelectData): name = sd.value["image"]["path"] with Image.open(name) as im: if im.info.get("parameters"): metadata = im.info["parameters"] else: metadata = {"Data": "Preview Grid"} return { main_view: gr.update(value=name), metadata_json: gr.update(value=metadata), } with gr.Row(elem_classes="type_row"): with gr.Column(scale=5): with gr.Group(): with gr.Group(), gr.Row(): prompt = gr.Textbox( show_label=False, placeholder="Type prompt here.", container=False, autofocus=True, elem_classes="type_row", lines=5, value=settings["prompt"], scale=4, ) add_ctrl("prompt", prompt) spellcheck = gr.Dropdown( label="Wildcards", visible=False, choices=[], value="", scale=1, ) @prompt.input(inputs=prompt, outputs=spellcheck) def checkforwildcards(text): test = find_unclosed_markers(text) if test is not None: filtered = [s for s in shared.wildcards if test in s] filtered.append(" ") return { spellcheck: gr.update( interactive=True, visible=True, choices=filtered, value=" ", ) } else: return { spellcheck: gr.update(interactive=False, visible=False) } @spellcheck.select(inputs=[prompt, spellcheck], outputs=prompt) def select_spellcheck(text, selection): last_idx = text.rindex("__") newtext = f"{text[:last_idx]}__{selection}__" return {prompt: gr.update(value=newtext)} with gr.Column(scale=1, min_width=0): run_button = gr.Button(value="Generate", elem_id="generate") stop_button = gr.Button( value="Stop", interactive=False, visible=False ) @main_view.upload( inputs=[main_view, prompt], outputs=[prompt, gallery] ) def load_images_handler(file, prompt): image = Image.open(file) params = look(image, prompt, gr) return params, [file] with gr.Column(scale=2) as right_col: with gr.Tab(label="Setting"): performance_selection = gr.Dropdown( label="Performance", choices=list(performance_settings.performance_options.keys()) + [performance_settings.CUSTOM_PERFORMANCE], value=settings["performance"], ) add_ctrl("performance_selection", performance_selection, True) perf_name = gr.Textbox( show_label=False, placeholder="Name", interactive=True, visible=False, ) perf_save = gr.Button( value="Save", visible=False, ) custom_default_values = performance_settings.get_perf_options( settings["performance"] ) custom_steps = gr.Slider( label="Custom Steps", minimum=1, maximum=200, step=1, value=custom_default_values["custom_steps"], visible=False, ) add_ctrl("custom_steps", custom_steps) cfg = gr.Slider( label="CFG", minimum=0.0, maximum=20.0, step=0.1, value=custom_default_values["cfg"], visible=False, ) add_ctrl("cfg", cfg) sampler_name = gr.Dropdown( label="Sampler", choices=KSampler.SAMPLERS, value=custom_default_values["sampler_name"], visible=False, ) add_ctrl("sampler_name", sampler_name) scheduler = gr.Dropdown( label="Scheduler", choices=KSampler.SCHEDULERS, value=custom_default_values["scheduler"], visible=False, ) add_ctrl("scheduler", scheduler) clip_skip = gr.Slider( label="Clip Skip", minimum=1, maximum=5, step=1, value=1, visible=False, ) add_ctrl("clip_skip", clip_skip) performance_outputs = [ perf_name, perf_save, cfg, sampler_name, scheduler, clip_skip, custom_steps, ] @perf_save.click( inputs=performance_outputs, outputs=[performance_selection], ) def performance_save( perf_name, perf_save, cfg, sampler_name, scheduler, clip_skip, custom_steps, ): if perf_name != "": perf_options = performance_settings.load_performance() opts = { "custom_steps": custom_steps, "cfg": cfg, "sampler_name": sampler_name, "scheduler": scheduler, "clip_skip": clip_skip, } perf_options[perf_name] = opts performance_settings.save_performance(perf_options) choices = list(perf_options.keys()) + [ performance_settings.CUSTOM_PERFORMANCE ] return gr.update(choices=choices, value=perf_name) else: return gr.update() with gr.Group(): aspect_ratios_selection = gr.Dropdown( label="Aspect Ratios (width x height)", choices=list(resolution_settings.aspect_ratios.keys()) + [resolution_settings.CUSTOM_RESOLUTION], value=settings["resolution"], ) add_ctrl("aspect_ratios_selection", aspect_ratios_selection, True) ratio_name = gr.Textbox( show_label=False, placeholder="Name", interactive=True, visible=False, ) default_resolution = resolution_settings.get_aspect_ratios( settings["resolution"] ) custom_width = gr.Slider( label="Width", minimum=256, maximum=4096, step=2, visible=False, value=default_resolution[0], ) add_ctrl("custom_width", custom_width) custom_height = gr.Slider( label="Height", minimum=256, maximum=4096, step=2, visible=False, value=default_resolution[1], ) add_ctrl("custom_height", custom_height) ratio_save = gr.Button( value="Save", visible=False, ) @ratio_save.click( inputs=[ratio_name, custom_width, custom_height], outputs=[aspect_ratios_selection], ) def ratio_save_click(ratio_name, custom_width, custom_height): if ratio_name != "": ratio_options = resolution_settings.load_resolutions() ratio_options[ratio_name] = (custom_width, custom_height) resolution_settings.save_resolutions(ratio_options) choices = list(resolution_settings.aspect_ratios.keys()) + [ resolution_settings.CUSTOM_RESOLUTION ] new_ratio_name = ( f"{custom_width}x{custom_height} ({ratio_name})" ) return gr.update(choices=choices, value=new_ratio_name) else: return gr.update() style_selection = gr.Dropdown( label="Style Selection", multiselect=True, container=True, choices=list(load_styles().keys()), value=settings["style"], ) add_ctrl("style_selection", style_selection) style_button = gr.Button(value="⬅️ Send Style to prompt", size="sm") image_number = gr.Slider( label="Image Number", minimum=0, maximum=settings.get("image_number_max", 50), step=1, value=settings.get("image_number", 1), ) add_ctrl("image_number", image_number, configurable=True) auto_negative_prompt = gr.Checkbox( label="Auto Negative Prompt", show_label=True, value=settings["auto_negative_prompt"], ) add_ctrl("auto_negative", auto_negative_prompt) negative_prompt = gr.Textbox( label="Negative Prompt", show_label=True, placeholder="Type prompt here.", value=settings["negative_prompt"], ) add_ctrl("negative", negative_prompt) seed_random = gr.Checkbox( label="Random Seed", value=settings["seed_random"] ) image_seed = gr.Number( label="Seed", value=settings["seed"], precision=0, visible=not settings["seed_random"], ) add_ctrl("seed", image_seed) @style_button.click( inputs=[prompt, negative_prompt, style_selection], outputs=[prompt, negative_prompt, style_selection], ) def send_to_prompt(prompt_text, negative_text, style_inputs): prompt_style, negative_style = apply_style( style_inputs, prompt_text, negative_text, "" ) return prompt_style, negative_style, [] @seed_random.change(inputs=[seed_random], outputs=[image_seed]) def random_checked(r): return gr.update(visible=not r) def refresh_seed(r, s): if r: return -1 else: return s with gr.Tab(label="Models"): # FIXME find a model to use as default # if settings["base_model"] not in path_manager.model_filenames: # settings["base_model"] = path_manager.model_filenames[0] with gr.Tab(label="Model"): model_current = gr.HTML( value=f"{settings['base_model']}", ) with gr.Group(): modelfilter = gr.Textbox( placeholder="Model name", value="", show_label=False, container=False, ) model_gallery = gr.Gallery( label=f"SDXL model: {settings['base_model']}", show_label=False, height="auto", allow_preview=False, preview=False, columns=[2], rows=[3], object_fit="contain", visible=True, show_download_button=False, min_width=60, value=list( map( lambda x: (get_checkpoint_thumbnail(x), x), shared.models.get_names("checkpoints"), ) ), ) base_model = gr.Text( visible=False, value=settings["base_model"], ) add_ctrl("base_model_name", base_model) @modelfilter.input(inputs=modelfilter, outputs=[model_gallery]) @modelfilter.submit(inputs=modelfilter, outputs=[model_gallery]) def update_model_filter(filtered): filtered_filenames = filter( lambda filename: filtered.lower() in filename.lower(), shared.models.get_names("checkpoints"), ) newlist = list( map( lambda x: (get_checkpoint_thumbnail(x), x), filtered_filenames, ) ) return gr.update(value=newlist) def update_model_select(evt: gr.SelectData): model_name = f"{evt.value['caption']}" model = shared.models.get_models_by_path( "checkpoints", model_name ) model_base = shared.models.get_model_base(model) txt = f"{evt.value['caption']}
Model type: {model_base}" return { model_current: gr.update(value=txt), base_model: gr.update(value=model_name), } model_gallery.select( update_model_select, None, outputs=[model_current, base_model] ) with gr.Tab(label="LoRAs"): with gr.Group(visible=False) as lora_add: lorafilter = gr.Textbox( placeholder="Search LoRA", value="", show_label=False, container=False, ) lora_gallery = gr.Gallery( label=None, show_label=False, height="auto", allow_preview=False, preview=False, interactive=False, selected_index=None, columns=[2], rows=[3], object_fit="contain", show_download_button=False, min_width=60, value=list( map( lambda x: (get_lora_thumbnail(x), x), shared.models.get_names("loras"), ) ), ) lora_cancel_btn = gr.Button( value="cancel", scale=1, ) default_active = [] for i in range(1, 6): m = settings.get(f"lora_{i}_model", "None") w = settings.get(f"lora_{i}_weight", 0.0) if m != "" and m != "None": default_active.append((get_lora_thumbnail(m), f"{w} - {m}")) with gr.Group(visible=True) as lora_active: with gr.Row(): lora_weight_slider = gr.Slider( label="Weight", show_label=True, minimum=settings.get("lora_min", 0), maximum=settings.get("lora_max", 2), step=0.05, value=1.0, interactive=True, ) lora_active_gallery = gr.Gallery( label=None, show_label=False, height="auto", allow_preview=False, preview=False, interactive=False, columns=[2], rows=[3], object_fit="contain", visible=True, show_download_button=False, min_width=60, value=default_active, ) add_ctrl("loras", lora_active_gallery) with gr.Group(), gr.Row(): lora_add_btn = gr.Button( value="+", scale=1, ) lora_del_btn = gr.Button( value="-", scale=1, ) lora_keywords = gr.Textbox( label="LoRA Trigger Words", interactive=False ) add_ctrl("lora_keywords", lora_keywords) with gr.Tab(label="MergeMaker"): with gr.Group(): mm_name = gr.Textbox( show_label=False, placeholder="Name(.merge)", container=False, ) mm_comment = gr.Textbox( show_label=False, placeholder="Comment", container=False, ) mm_cache = gr.Checkbox( label="Save cached safetensor of merged model", value=False, container=False, ) with gr.Group(visible=False) as mm_add: mm_filter = gr.Textbox( placeholder="Search model/LoRA", value="", show_label=False, container=False, ) mm_gallery = gr.Gallery( label=f"Models", show_label=False, height="auto", allow_preview=False, preview=False, interactive=False, columns=[2], rows=[3], object_fit="contain", show_download_button=False, min_width=60, value=list( map( lambda x: (get_checkpoint_thumbnail(x), f"C:{x}"), shared.models.get_names("checkpoints"), ) ) + list( map( lambda x: (get_lora_thumbnail(x), f"L:{x}"), shared.models.get_names("checkpoints"), ) ), ) mm_cancel_btn = gr.Button( value="cancel", scale=1, ) with gr.Group(visible=True) as mm_active: with gr.Row(): mm_weight_slider = gr.Slider( label="Weight", show_label=True, minimum=settings.get("lora_min", 0), maximum=settings.get("lora_max", 2), step=0.05, value=1.0, interactive=True, ) mm_active_gallery = gr.Gallery( label=f"Models", show_label=False, height="auto", allow_preview=False, preview=False, interactive=False, columns=[2], rows=[3], object_fit="contain", visible=True, show_download_button=False, min_width=60, value=[], ) add_ctrl("mm_models", mm_active_gallery) with gr.Group(), gr.Row(): mm_add_btn = gr.Button( value="+", scale=1, ) mm_del_btn = gr.Button( value="-", scale=1, ) mm_save_btn = gr.Button( value="Save", ) def gallery_toggle(): result = [ gr.update(visible=True), gr.update(visible=False), ] return result # LoRA @lorafilter.input( inputs=[lorafilter, lora_active_gallery], outputs=[lora_gallery] ) @lorafilter.submit( inputs=[lorafilter, lora_active_gallery], outputs=[lora_gallery] ) def update_lora_filter(lorafilter, lora_active_gallery): if lora_active_gallery: active = list( map(lambda x: x[1].split(" - ", 1)[1], lora_active_gallery) ) else: active = [] filtered_filenames = [ x for x in map( lambda x: (get_lora_thumbnail(x), x), filter( lambda filename: lorafilter.lower() in filename.lower(), shared.models.get_names("loras"), ), ) if x[1] not in active ] # Sorry for this. It is supposed to show all LoRAs matching the filter and is not currently used. return gr.update(value=filtered_filenames) def lora_select(gallery, lorafilter, evt: gr.SelectData): global lora_active_selected w = 1.0 keywords = "" active = [] if gallery is not None: for lora_data in gallery: w, l = lora_data[1].split(" - ", 1) keywords = f"{keywords}, {load_keywords(l)} " active.append(l) else: gallery = [] keywords = f"{keywords}, {load_keywords(evt.value['caption'])} " gallery.append( ( get_lora_thumbnail(evt.value["caption"]), f"{w} - {evt.value['caption']}", ) ) lora_active_selected = len(gallery) - 1 active.append(f"{evt.value['caption']}") inactive = [ x for x in map( lambda x: (get_lora_thumbnail(x), x), filter( lambda filename: lorafilter.lower() in filename.lower(), shared.models.get_names("loras"), ), ) if x[1] not in active ] return { lora_add: gr.update(visible=False), lora_gallery: gr.update( value=inactive, selected_index=65535, ), lora_active: gr.update(visible=True), lora_active_gallery: gr.update( value=gallery, selected_index=lora_active_selected, ), lora_keywords: gr.update(value=keywords), } lora_active_selected = None def lora_active_select(gallery, evt: gr.SelectData): global lora_active_selected lora_active_selected = evt.index return { lora_active: gr.update(), lora_active_gallery: gr.update(), lora_weight_slider: gr.update( value=float(evt.value["caption"].split(" - ", 1)[0]) ), } def lora_delete(gallery, lorafilter): global lora_active_selected if gallery == None or len(gallery) == 0: return { lora_gallery: gr.update(), lora_active_gallery: gr.update(), lora_keywords: gr.update(), } if lora_active_selected is not None and lora_active_selected < len( gallery ): del gallery[lora_active_selected] if lora_active_selected is not None: lora_active_selected = min( lora_active_selected, len(gallery) - 1 ) else: lora_active_selected = len(gallery) - 1 keywords = "" active = [] active_names = [] for lora_data in gallery: w, l = lora_data[1].split(" - ", 1) active.append(lora_data) active_names.append(l) keywords = f"{keywords}, {load_keywords(l)} " loras = list( filter( lambda filename: lorafilter.lower() in filename.lower(), shared.models.get_names("loras"), ) ) if len(loras) == 0: loras = shared.models.get_names("loras") inactive = [ x for x in map(lambda x: (get_lora_thumbnail(x), x), loras) if x[1] not in active_names ] return { lora_gallery: gr.update( value=inactive, selected_index=65535, ), lora_active_gallery: gr.update( value=active, selected_index=lora_active_selected, ), lora_keywords: gr.update(value=keywords), } def lora_weight_slider_update(gallery, w): global lora_active_selected if lora_active_selected is None: return {lora_active_gallery: gr.update()} loras = [] for lora_data in gallery: loras.append((lora_data[0], lora_data[1])) l = gallery[lora_active_selected][1].split(" - ")[1] loras[lora_active_selected] = (get_lora_thumbnail(l), f"{w} - {l}") return { lora_active_gallery: gr.update(value=loras), } lora_weight_slider.release( fn=lora_weight_slider_update, inputs=[lora_active_gallery, lora_weight_slider], outputs=[lora_active_gallery], ) lora_add_btn.click( fn=gallery_toggle, outputs=[lora_add, lora_active], ) lora_cancel_btn.click( fn=gallery_toggle, outputs=[lora_active, lora_add], ) lora_del_btn.click( fn=lora_delete, inputs=[lora_active_gallery, lorafilter], outputs=[lora_gallery, lora_active_gallery, lora_keywords], ) lora_gallery.select( fn=lora_select, inputs=[lora_active_gallery, lorafilter], outputs=[ lora_add, lora_gallery, lora_active, lora_active_gallery, lora_keywords, ], ) lora_active_gallery.select( fn=lora_active_select, inputs=[lora_active_gallery], outputs=[lora_active, lora_active_gallery, lora_weight_slider], ) # MergeMaker @mm_filter.input(inputs=mm_filter, outputs=[mm_gallery]) @mm_filter.submit(inputs=mm_filter, outputs=[mm_gallery]) def update_mm_filter(filtered): filtered_models = filter( lambda filename: ".merge" not in filename.lower(), shared.models.get_names("checkpoints"), ) filtered_models = filter( lambda filename: filtered.lower() in filename.lower(), filtered_models, ) filtered_loras = filter( lambda filename: filtered.lower() in filename.lower(), shared.models.get_names("loras"), ) newlist = list( map( lambda x: (get_checkpoint_thumbnail(x), f"C:{x}"), filtered_models, ) ) + list( map( lambda x: (get_lora_thumbnail(x), f"L:{x}"), filtered_loras, ) ) return gr.update(value=newlist) def mm_select(gallery, evt: gr.SelectData): w = 1.0 mm = [] if gallery is not None: for mm_data in gallery: mm.append((mm_data[0], mm_data[1])) m = evt.value["caption"] n = re.sub("[CL]:", "", m) mm.append((get_model_thumbnail(n), f"{w} - {m}")) return { mm_add: gr.update(visible=False), mm_active: gr.update(visible=True), mm_active_gallery: gr.update(value=mm), } mm_active_selected = None def mm_active_select(gallery, evt: gr.SelectData): global mm_active_selected mm_active_selected = evt.index mm = [] for mm_data in gallery: mm.append((mm_data[0], mm_data[1])) return { mm_active: gr.update(), mm_active_gallery: gr.update(), mm_weight_slider: gr.update( value=float(mm[evt.index][1].split(" - ", 1)[0]) ), } def mm_delete(gallery): global mm_active_selected if mm_active_selected is not None: del gallery[mm_active_selected] if mm_active_selected >= len(gallery): mm_active_selected = None mm = [] for mm_data in gallery: mm.append((mm_data[0], mm_data[1])) return { mm_active_gallery: gr.update(value=mm), } def mm_weight_slider_update(gallery, w): global mm_active_selected if mm_active_selected is None: return {mm_active_gallery: gr.update()} mm = [] for mm_data in gallery: mm.append((mm_data[0], mm_data[1])) l = gallery[mm_active_selected][1].split(" - ")[1] n = re.sub("[CL]:", "", l) mm[mm_active_selected] = (get_model_thumbnail(n), f"{w} - {l}") return { mm_active_gallery: gr.update(value=mm), } def mm_save(name, comment, gallery, cache): if name == "": gr.Info("Merge needs a name.") return if comment == "": gr.Info("You probably want a comment.") return dict = {} models = [] loras = [] for model_data in gallery: w, m = model_data[1].split(" - ", 1) n = re.sub("[CL]:", "", m) if m.startswith("C:"): models.append((n, w)) if m.startswith("L:"): loras.append((n, w)) dict["comment"] = comment base = models.pop(0) dict["base"] = {"name": base[0], "weight": float(base[1])} dict["models"] = [] for model in models: dict["models"].append( {"name": model[0], "weight": float(model[1])} ) dict["loras"] = [] for lora in loras: dict["loras"].append( {"name": lora[0], "weight": float(lora[1])} ) dict["normalize"] = 1.0 dict["cache"] = cache folder = path_manager.model_paths["modelfile_path"] folder = folder[0] if isinstance(folder, list) else folder filename = Path( folder / name ).with_suffix(".merge") if filename.exists(): gr.Info("Not saving, file already exists.") else: with open(filename, "w") as outfile: json.dump(dict, outfile, indent=2) gr.Info(f"Saved {Path(name).with_suffix('.merge')}") mm_weight_slider.release( fn=mm_weight_slider_update, inputs=[mm_active_gallery, mm_weight_slider], outputs=[mm_active_gallery], ) mm_add_btn.click( fn=gallery_toggle, outputs=[mm_add, mm_active], ) mm_cancel_btn.click( fn=gallery_toggle, outputs=[mm_active, mm_add], ) mm_del_btn.click( fn=mm_delete, inputs=mm_active_gallery, outputs=[mm_active_gallery], ) mm_gallery.select( fn=mm_select, inputs=[mm_active_gallery], outputs=[mm_add, mm_active, mm_active_gallery], ) mm_active_gallery.select( fn=mm_active_select, inputs=[mm_active_gallery], outputs=[mm_active, mm_active_gallery, mm_weight_slider], ) mm_save_btn.click( fn=mm_save, inputs=[mm_name, mm_comment, mm_active_gallery, mm_cache], outputs=[], ) with gr.Row(): model_refresh = gr.Button( value="\U0001f504 Refresh All Files", variant="secondary", elem_classes="refresh_button", ) @model_refresh.click( inputs=[lora_active_gallery], outputs=[ modelfilter, model_gallery, lorafilter, lora_gallery, style_selection, mm_filter, mm_gallery, ], ) def model_refresh_clicked(lora_active_gallery): global civit_checkpoints, civit_loras shared.models.update_all_models() results = { modelfilter: gr.update(value=""), model_gallery: update_model_filter(""), lorafilter: gr.update(value=""), lora_gallery: update_lora_filter("", lora_active_gallery), style_selection: gr.update(choices=list(load_styles().keys())), mm_filter: gr.update(value=""), mm_gallery: update_mm_filter(""), } return results ui_onebutton.ui_onebutton(prompt, run_event) inpaint_toggle = ui_controlnet.add_controlnet_tab( main_view, inpaint_view, prompt, image_number, run_event ) with gr.Tab(label="Info"): with gr.Row(): metadata_json.render() with gr.Row(): gr.HTML( value="""  Discord
 Github
π """, ) hint_text = gr.Markdown( value="", elem_id="hint-container", elem_classes="hint-container", ) @performance_selection.change( inputs=[performance_selection], outputs=[perf_name] + performance_outputs, ) def performance_changed(selection): if selection == performance_settings.CUSTOM_PERFORMANCE: return [gr.update(value="")] + [gr.update(visible=True)] * len( performance_outputs ) else: return [gr.update(visible=False)] + [ gr.update(visible=False) ] * len(performance_outputs) @performance_selection.change( inputs=[performance_selection], outputs=[custom_steps] + [cfg] + [sampler_name] + [scheduler] + [clip_skip], ) def performance_changed_update_custom(selection): # Skip if Custom was selected if selection == performance_settings.CUSTOM_PERFORMANCE: return [gr.update()] * 5 # Update Custom values based on selected Performance mode selected_perf_options = performance_settings.get_perf_options(selection) return { custom_steps: gr.update( value=selected_perf_options["custom_steps"] ), cfg: gr.update(value=selected_perf_options["cfg"]), sampler_name: gr.update( value=selected_perf_options["sampler_name"] ), scheduler: gr.update(value=selected_perf_options["scheduler"]), clip_skip: gr.update(value=selected_perf_options["clip_skip"]), } @aspect_ratios_selection.change( inputs=[aspect_ratios_selection], outputs=[ratio_name, custom_width, custom_height, ratio_save], ) def aspect_ratios_changed(selection): # Show resolution controls when selecting Custom if selection == resolution_settings.CUSTOM_RESOLUTION: return [gr.update(visible=True)] * 4 # Hide resolution controls and update with selected resolution selected_width, selected_height = resolution_settings.get_aspect_ratios( selection ) return { ratio_name: gr.update(visible=False), custom_width: gr.update(visible=False, value=selected_width), custom_height: gr.update(visible=False, value=selected_height), ratio_save: gr.update(visible=False), } def activate(): # UGLY workaround for https://github.com/gradio-app/gradio/issues/7586 return gr.update(interactive=True) run_event.change( fn=refresh_seed, inputs=[seed_random, image_seed], outputs=image_seed ).then( fn=activate, outputs=[inpaint_view] ).then( fn=generate_clicked, inputs=state["ctrls_obj"], outputs=[ run_button, stop_button, progress_html, main_view, inpaint_view, inpaint_toggle, gallery, metadata_json, hint_text, ], ) def poke(number): return number + 1 run_button.click(fn=poke, inputs=run_event, outputs=run_event) def stop_clicked(): worker.interrupt_ruined_processing = True shared.state["interrupted"] = False stop_button.click(fn=stop_clicked, queue=False) def update_cfg(): # Update ui components # Only refresh things like minimum, maximum and choices. Assume the user already # have options selected and don't overwrite them. (They should restart if they want that) return { image_number: gr.update(maximum=settings.get("image_number_max", 50)), performance_selection: gr.update( choices=list(performance_settings.performance_options.keys()) + [performance_settings.CUSTOM_PERFORMANCE] ), aspect_ratios_selection: gr.update( choices=list(resolution_settings.aspect_ratios.keys()) + [resolution_settings.CUSTOM_RESOLUTION] ), cfg_timestamp: gr.update(value=shared.state["last_config"]), } # If cfg_timestamp has a new value, trigger an update cfg_timestamp.change(fn=update_cfg, outputs=[cfg_timestamp] + state["cfg_items_obj"]) add_api() if isinstance(args.auth, str) and not "/" in args.auth: if len(args.auth): print( f'\nERROR! --auth need be in the form of "username/password" not "{args.auth}"\n' ) if args.share: print( f"\nWARNING! Will not enable --share without proper --auth=username/password\n" ) args.share = False launch_app(args)