import gradio as gr from modules import script_callbacks, shared import os import json import fnmatch import re import subprocess from modules.shared import opts, cmd_opts from modules.paths import extensions_dir from scripts.civitai_global import print import scripts.civitai_global as gl import scripts.civitai_download as _download import scripts.civitai_file_manage as _file import scripts.civitai_api as _api def git_tag(): try: return subprocess.check_output([os.environ.get('GIT', "git"), "describe", "--tags"], shell=False, encoding='utf8').strip() except: return None try: import modules_forge forge = True ver_bool = True except ImportError: forge = False if not forge: try: from packaging import version ver = git_tag() if not ver: try: from modules import launch_utils ver = launch_utils.git_tag() except: print("Failed to fetch SD-WebUI version") ver_bool = False if ver: ver = ver.split('-')[0].rsplit('-', 1)[0] ver_bool = version.parse(ver[0:]) >= version.parse("1.7") except ImportError: print("Python module 'packaging' has not been imported correctly, please try to restart or install it manually.") ver_bool = False gl.init() def saveSettings(ust, ct, pt, st, bf, cj, td, ol, hi, sn, ss, ts): config = cmd_opts.ui_config_file # Create a dictionary to map the settings to their respective variables settings_map = { "civitai_interface/Search type:/value": ust, "civitai_interface/Content type:/value": ct, "civitai_interface/Time period:/value": pt, "civitai_interface/Sort by:/value": st, "civitai_interface/Base model:/value": bf, "civitai_interface/Save info after download/value": cj, "civitai_interface/Divide cards by date/value": td, "civitai_interface/Liked models only/value": ol, "civitai_interface/Hide installed models/value": hi, "civitai_interface/NSFW content/value": sn, "civitai_interface/Tile size:/value": ss, "civitai_interface/Tile count:/value": ts } # Load the current contents of the config file into a dictionary try: with open(config, "r", encoding="utf8") as file: data = json.load(file) except: print(f"Cannot save settings, failed to open \"{file}\"") print("Please try to manually repair the file or remove it to reset settings.") return # Remove any keys containing the text `civitai_interface` keys_to_remove = [key for key in data if "civitai_interface" in key] for key in keys_to_remove: del data[key] # Update the dictionary with the new settings data.update(settings_map) # Save the modified content back to the file with open(config, 'w', encoding="utf-8") as file: json.dump(data, file, indent=4) print(f"Updated settings to: {config}") def all_visible(html_check): return gr.Button.update(visible="model-checkbox" in html_check) def show_multi_buttons(model_list, type_list, version_value): model_list = json.loads(model_list) type_list = json.loads(type_list) otherButtons = True multi_file_subfolder = False default_subfolder = "Only available if the selected files are of the same model type" sub_folders = ["None"] BtnDwn = version_value and not version_value.endswith('[Installed]') and not model_list BtnDel = version_value.endswith('[Installed]') dot_subfolders = getattr(opts, "dot_subfolders", True) multi = bool(model_list) and not len(gl.download_queue) > 0 if model_list: otherButtons = False if type_list and all(x == type_list[0] for x in type_list): multi_file_subfolder = True model_folder = os.path.join(_api.contenttype_folder(type_list[0])) default_subfolder = "None" try: for root, dirs, _ in os.walk(model_folder, followlinks=True): if dot_subfolders: dirs = [d for d in dirs if not d.startswith('.')] dirs = [d for d in dirs if not any(part.startswith('.') for part in os.path.join(root, d).split(os.sep))] for d in dirs: sub_folder = os.path.relpath(os.path.join(root, d), model_folder) if sub_folder: sub_folders.append(f'{os.sep}{sub_folder}') sub_folders.remove("None") sub_folders = sorted(sub_folders, key=lambda x: (x.lower(), x)) sub_folders.insert(0, "None") list = set() sub_folders = [x for x in sub_folders if not (x in list or list.add(x))] except: sub_folders = ["None"] return (gr.Button.update(visible=multi, interactive=multi), # Download Multi Button gr.Button.update(visible=BtnDwn if multi else True if not version_value.endswith('[Installed]') else False), # Download Button gr.Button.update(visible=BtnDel if not model_list else False), # Delete Button gr.Button.update(visible=otherButtons), # Save model info Button gr.Button.update(visible=otherButtons), # Save images Button gr.Dropdown.update(visible=multi, interactive=multi_file_subfolder, choices=sub_folders, value=default_subfolder) # Selected type sub folder ) def txt2img_output(image_url): clean_url = image_url[4:] geninfo = _api.fetch_and_process_image(clean_url) if geninfo: nr = _download.random_number() geninfo = nr + geninfo return gr.Textbox.update(value=geninfo) def on_ui_tabs(): page_header = getattr(opts, "page_header", False) lobe_directory = None for root, dirs, files in os.walk(extensions_dir, followlinks=True): for dir_name in fnmatch.filter(dirs, '*lobe*'): lobe_directory = os.path.join(root, dir_name) break # Different ID's for Lobe Theme component_id = "togglesL" if lobe_directory else "toggles" toggle1 = "toggle1L" if lobe_directory else "toggle1" toggle2 = "toggle2L" if lobe_directory else "toggle2" toggle3 = "toggle3L" if lobe_directory else "toggle3" toggle5 = "toggle5L" if lobe_directory else "toggle5" refreshbtn = "refreshBtnL" if lobe_directory else "refreshBtn" filterBox = "filterBoxL" if lobe_directory else "filterBox" if page_header: header = "headerL" if lobe_directory else "header" else: header = "header_off" api_key = getattr(opts, "custom_api_key", "") if api_key: toggle4 = "toggle4L_api" if lobe_directory else "toggle4_api" show_only_liked = True else: toggle4 = "toggle4L" if lobe_directory else "toggle4" show_only_liked = False content_choices = _file.get_content_choices() scan_choices = _file.get_content_choices(scan_choices=True) with gr.Blocks() as civitai_interface: with gr.Tab(label="Browser", elem_id="browserTab"): with gr.Row(elem_id="searchRow"): with gr.Accordion(label="", open=False, elem_id=filterBox): with gr.Row(): use_search_term = gr.Radio(label="Search type:", choices=["Model name", "User name", "Tag"], value="Model name", elem_id="searchType") with gr.Row(): content_type = gr.Dropdown(label='Content type:', choices=content_choices, value=None, type="value", multiselect=True, elem_id="centerText") with gr.Row(): base_filter = gr.Dropdown(label='Base model:', multiselect=True, choices=["SD 1.4","SD 1.5","SD 1.5 LCM","SD 2.0","SD 2.0 768","SD 2.1","SD 2.1 768","SD 2.1 Unclip","SDXL 0.9","SDXL 1.0","SDXL 1.0 LCM","SDXL Distilled","SDXL Turbo","SVD","SVD XT","Playground v2","PixArt a","Other"], value=None, type="value", elem_id="centerText") with gr.Row(): period_type = gr.Dropdown(label='Time period:', choices=["All Time", "Year", "Month", "Week", "Day"], value="All Time", type="value", elem_id="centerText") sort_type = gr.Dropdown(label='Sort by:', choices=["Newest","Most Downloaded","Highest Rated","Most Liked", "Most Buzz","Most Discussed","Most Collected","Most Images"], value="Most Downloaded", type="value", elem_id="centerText") with gr.Row(elem_id=component_id): create_json = gr.Checkbox(label=f"Save info after download", value=True, elem_id=toggle1, min_width=171) show_nsfw = gr.Checkbox(label="NSFW content", value=False, elem_id=toggle2, min_width=107) toggle_date = gr.Checkbox(label="Divide cards by date", value=False, elem_id=toggle3, min_width=142) only_liked = gr.Checkbox(label="Liked models only", value=False, interactive=show_only_liked, elem_id=toggle4, min_width=163) hide_installed = gr.Checkbox(label="Hide installed models", value=False, elem_id=toggle5, min_width=170) with gr.Row(): size_slider = gr.Slider(minimum=4, maximum=20, value=8, step=0.25, label='Tile size:') tile_count_slider = gr.Slider(label="Tile count:", minimum=1, maximum=100, value=15, step=1, max_width=100) with gr.Row(elem_id="save_set_box"): save_settings = gr.Button(value="Save settings as default", elem_id="save_set_btn") search_term = gr.Textbox(label="", placeholder="Search CivitAI", elem_id="searchBox") refresh = gr.Button(label="", value="", elem_id=refreshbtn, icon="placeholder") with gr.Row(elem_id=header): with gr.Row(elem_id="pageBox"): get_prev_page = gr.Button(value="Prev page", interactive=False, elem_id="pageBtn1") page_slider = gr.Slider(label='Current page', step=1, minimum=1, maximum=1, value=1, min_width=80, elem_id="pageSlider") get_next_page = gr.Button(value="Next page", interactive=False, elem_id="pageBtn2") with gr.Row(elem_id="pageBoxMobile"): pass # Row used for button placement on mobile with gr.Row(elem_id="select_all_models_container"): select_all = gr.Button(value="Select All", elem_id="select_all_models", visible=False) with gr.Row(): list_html = gr.HTML(value='
Click the search icon to load models.
Use the filter icon to filter results.
') with gr.Row(): download_progress = gr.HTML(value='
', elem_id="DownloadProgress") with gr.Row(): list_models = gr.Dropdown(label="Model:", choices=[], interactive=False, elem_id="quicksettings1", value=None) list_versions = gr.Dropdown(label="Version:", choices=[], interactive=False, elem_id="quicksettings", value=None) file_list = gr.Dropdown(label="File:", choices=[], interactive=False, elem_id="file_list", value=None) with gr.Row(): with gr.Column(scale=4): install_path = gr.Textbox(label="Download folder:", interactive=False, max_lines=1) with gr.Column(scale=2): sub_folder = gr.Dropdown(label="Sub folder:", choices=[], interactive=False, value=None) with gr.Row(): with gr.Column(scale=4): trained_tags = gr.Textbox(label='Trained tags (if any):', value=None, interactive=False, lines=1) with gr.Column(scale=2, elem_id="spanWidth"): base_model = gr.Textbox(label='Base model: ', value='', interactive=False, lines=1, elem_id="baseMdl") model_filename = gr.Textbox(label="Model filename:", interactive=False, value=None) with gr.Row(): save_info = gr.Button(value="Save model info", interactive=False) save_images = gr.Button(value="Save images", interactive=False) delete_model = gr.Button(value="Delete model", interactive=False, visible=False) download_model = gr.Button(value="Download model", interactive=False) subfolder_selected = gr.Dropdown(label="Sub folder for selected files:", choices=[], interactive=False, visible=False, value=None, allow_custom_value=True) download_selected = gr.Button(value="Download all selected", interactive=False, visible=False, elem_id="download_all_button") with gr.Row(): cancel_all_model = gr.Button(value="Cancel all downloads", interactive=False, visible=False) cancel_model = gr.Button(value="Cancel current download", interactive=False, visible=False) with gr.Row(): preview_html = gr.HTML(elem_id="civitai_preview_html") with gr.Row(elem_id="backToTopContainer"): back_to_top = gr.Button(value="↑", elem_id="backToTop") with gr.Tab("Update Models"): with gr.Row(): selected_tags = gr.CheckboxGroup(elem_id="selected_tags", label="Scan for:", choices=scan_choices) with gr.Row(): overwrite_toggle = gr.Checkbox(elem_id="overwrite_toggle", label="Overwrite any existing previews, tags or descriptions.", value=True) with gr.Row(): skip_hash_toggle = gr.Checkbox(elem_id="skip_hash_toggle", label="One-Time Hash Generation for externally downloaded models.", value=True) with gr.Row(): save_all_tags = gr.Button(value="Update model info & tags", interactive=True, visible=True) cancel_all_tags = gr.Button(value="Cancel updating model info & tags", interactive=False, visible=False) with gr.Row(): tag_progress = gr.HTML(value='
') with gr.Row(): update_preview = gr.Button(value="Update model preview", interactive=True, visible=True) cancel_update_preview = gr.Button(value="Cancel updating model previews", interactive=False, visible=False) with gr.Row(): preview_progress = gr.HTML(value='
') with gr.Row(): ver_search = gr.Button(value="Scan for available updates", interactive=True, visible=True) cancel_ver_search = gr.Button(value="Cancel updates scan", interactive=False, visible=False) load_to_browser = gr.Button(value="Load outdated models to browser", interactive=False, visible=False) with gr.Row(): version_progress = gr.HTML(value='
') with gr.Row(): load_installed = gr.Button(value="Load all installed models", interactive=True, visible=True) cancel_installed = gr.Button(value="Cancel loading models", interactive=False, visible=False) load_to_browser_installed = gr.Button(value="Load installed models to browser", interactive=False, visible=False) with gr.Row(): installed_progress = gr.HTML(value='
') with gr.Tab("Download Queue"): def get_style(size, left_border): return f"flex-grow: {size};" + ("border-left: 1px solid var(--border-color-primary);" if left_border else "") + "border-bottom: 1px solid var(--border-color-primary);padding: 5px 10px 5px 10px;width: 0;" download_manager_html = gr.HTML(elem_id="civitai_dl_list", value=f'''
Model:
Version:
Path:
Status:
Action:
In queue: (drag items to rearrange queue order)
''') #Invisible triggers/variables model_id = gr.Textbox(visible=False) queue_trigger = gr.Textbox(visible=False) dl_url = gr.Textbox(visible=False) civitai_text2img_output = gr.Textbox(visible=False) civitai_text2img_input = gr.Textbox(elem_id="civitai_text2img_input", visible=False) selected_model_list = gr.Textbox(elem_id="selected_model_list", visible=False) selected_type_list = gr.Textbox(elem_id="selected_type_list", visible=False) html_cancel_input = gr.Textbox(elem_id="html_cancel_input", visible=False) queue_html_input = gr.Textbox(elem_id="queue_html_input", visible=False) model_path_input = gr.Textbox(elem_id="model_path_input", visible=False) arrange_dl_id = gr.Textbox(elem_id="arrange_dl_id", visible=False) remove_dl_id = gr.Textbox(elem_id="remove_dl_id", visible=False) model_select = gr.Textbox(elem_id="model_select", visible=False) model_sent = gr.Textbox(elem_id="model_sent", visible=False) type_sent = gr.Textbox(elem_id="type_sent", visible=False) download_start = gr.Textbox(visible=False) download_finish = gr.Textbox(visible=False) tag_start = gr.Textbox(visible=False) tag_finish = gr.Textbox(visible=False) preview_start = gr.Textbox(visible=False) preview_finish = gr.Textbox(visible=False) ver_start = gr.Textbox(visible=False) ver_finish = gr.Textbox(visible=False) installed_start = gr.Textbox(visible=None) installed_finish = gr.Textbox(visible=None) delete_finish = gr.Textbox(visible=False) current_model = gr.Textbox(visible=False) current_sha256 = gr.Textbox(visible=False) model_preview_html = gr.Textbox(visible=False) def ToggleDate(toggle_date): gl.sortNewest = toggle_date def select_subfolder(sub_folder): if sub_folder == "None" or sub_folder == "Only available if the selected files are of the same model type": newpath = gl.main_folder else: newpath = gl.main_folder + sub_folder return gr.Textbox.update(value=newpath) # Javascript Functions # list_html.change(fn=None, inputs=hide_installed, _js="(toggleValue) => hideInstalled(toggleValue)") hide_installed.input(fn=None, inputs=hide_installed, _js="(toggleValue) => hideInstalled(toggleValue)") civitai_text2img_output.change(fn=None, inputs=civitai_text2img_output, _js="(genInfo) => genInfo_to_txt2img(genInfo)") download_selected.click(fn=None, _js="() => deselectAllModels()") select_all.click(fn=None, _js="() => selectAllModels()") list_models.select(fn=None, inputs=list_models, _js="(list_models) => select_model(list_models)") preview_html.change(fn=None, _js="() => adjustFilterBoxAndButtons()") back_to_top.click(fn=None, _js="() => BackToTop()") page_slider.release(fn=None, _js="() => pressRefresh()") card_updates = [queue_trigger, download_finish, delete_finish] for func in card_updates: func.change(fn=None, inputs=current_model, _js="(modelName) => updateCard(modelName)") list_html.change(fn=None, inputs=show_nsfw, _js="(hideAndBlur) => toggleNSFWContent(hideAndBlur)") show_nsfw.change(fn=None, inputs=show_nsfw, _js="(hideAndBlur) => toggleNSFWContent(hideAndBlur)") list_html.change(fn=None, inputs=size_slider, _js="(size) => updateCardSize(size, size * 1.5)") size_slider.change(fn=None, inputs=size_slider, _js="(size) => updateCardSize(size, size * 1.5)") model_preview_html.change(fn=None, inputs=model_preview_html, _js="(html_input) => inputHTMLPreviewContent(html_input)") download_manager_html.change(fn=None, _js="() => setSortable()") # Filter button Functions # def HTMLChange(input): return gr.HTML.update(value=input) queue_html_input.change(fn=HTMLChange, inputs=[queue_html_input], outputs=download_manager_html) remove_dl_id.change( fn=_download.remove_from_queue, inputs=[remove_dl_id] ) arrange_dl_id.change( fn=_download.arrange_queue, inputs=[arrange_dl_id] ) html_cancel_input.change( fn=_download.download_cancel ) html_cancel_input.change(fn=None, _js="() => cancelCurrentDl()") save_settings.click( fn=saveSettings, inputs=[ use_search_term, content_type, period_type, sort_type, base_filter, create_json, toggle_date, only_liked, hide_installed, show_nsfw, size_slider, tile_count_slider ] ) toggle_date.input( fn=ToggleDate, inputs=[toggle_date] ) # Model Button Functions # civitai_text2img_input.change(fn=txt2img_output,inputs=civitai_text2img_input,outputs=civitai_text2img_output) list_html.change(fn=all_visible,inputs=list_html,outputs=select_all) def update_models_dropdown(input): model_string = re.sub(r'\.\d{3}$', '', input) model_name, model_id = _api.extract_model_info(model_string) model_versions = _api.update_model_versions(model_id) (html, tags, base_mdl, DwnButton, SaveImages, DelButton, filelist, filename, dl_url, id, current_sha256, install_path, sub_folder) = _api.update_model_info(model_string, model_versions.get('value')) return (gr.Dropdown.update(value=model_string, interactive=True), model_versions,html,tags,base_mdl,filename,install_path,sub_folder,DwnButton,SaveImages,DelButton,filelist,dl_url,id,current_sha256, gr.Button.update(interactive=True)) model_select.change( fn=update_models_dropdown, inputs=[model_select], outputs=[ list_models, list_versions, preview_html, trained_tags, base_model, model_filename, install_path, sub_folder, download_model, save_images, delete_model, file_list, dl_url, model_id, current_sha256, save_info ] ) model_sent.change( fn=_file.model_from_sent, inputs=[model_sent, type_sent, tile_count_slider, model_path_input], outputs=[model_preview_html] ) sub_folder.select( fn=select_subfolder, inputs=[sub_folder], outputs=[install_path] ) list_versions.select( fn=_api.update_model_info, inputs=[ list_models, list_versions ], outputs=[ preview_html, trained_tags, base_model, download_model, save_images, delete_model, file_list, model_filename, dl_url, model_id, current_sha256, install_path, sub_folder ] ) file_list.input( fn=_api.update_file_info, inputs=[ list_models, list_versions, file_list ], outputs=[ model_filename, dl_url, model_id, current_sha256, download_model, delete_model, install_path, sub_folder ] ) # Download/Save Model Button Functions # selected_model_list.change( fn=show_multi_buttons, inputs=[selected_model_list, selected_type_list, list_versions], outputs=[ download_selected, download_model, delete_model, save_info, save_images, subfolder_selected ] ) download_model.click( fn=_download.download_start, inputs=[ download_start, dl_url, model_filename, install_path, list_models, list_versions, current_sha256, model_id, create_json, download_manager_html ], outputs=[ download_model, cancel_model, cancel_all_model, download_start, download_progress, download_manager_html ] ) download_selected.click( fn=_download.selected_to_queue, inputs=[ selected_model_list, subfolder_selected, download_start, create_json, download_manager_html ], outputs=[ download_model, cancel_model, cancel_all_model, download_start, download_progress, download_manager_html ] ) for component in [download_start, queue_trigger]: component.change(fn=None, _js="() => setDownloadProgressBar()") component.change( fn=_download.download_create_thread, inputs=[download_finish, queue_trigger], outputs=[ download_progress, current_model, download_finish, queue_trigger ] ) download_finish.change( fn=_download.download_finish, inputs=[ model_filename, list_versions, model_id ], outputs=[ download_model, cancel_model, cancel_all_model, delete_model, download_progress, list_versions ] ) cancel_model.click(_download.download_cancel) cancel_all_model.click(_download.download_cancel_all) cancel_model.click(fn=None, _js="() => cancelCurrentDl()") cancel_all_model.click(fn=None, _js="() => cancelAllDl()") delete_model.click( fn=_file.delete_model, inputs=[ delete_finish, model_filename, list_models, list_versions, current_sha256, selected_model_list ], outputs=[ download_model, cancel_model, delete_model, delete_finish, current_model, list_versions ] ) save_info.click( fn=_file.save_model_info, inputs=[ install_path, model_filename, sub_folder, current_sha256, preview_html ], outputs=[] ) save_images.click( fn=_file.save_images, inputs=[ preview_html, model_filename, install_path, sub_folder ], outputs=[] ) # Common input&output lists # page_inputs = [ content_type, sort_type, period_type, use_search_term, search_term, page_slider, base_filter, only_liked, show_nsfw, tile_count_slider ] page_outputs = [ list_models, list_versions, list_html, get_prev_page, get_next_page, page_slider, save_info, save_images, download_model, delete_model, install_path, sub_folder, file_list, preview_html, trained_tags, base_model, model_filename ] file_scan_inputs = [ selected_tags, ver_finish, tag_finish, installed_finish, preview_finish, overwrite_toggle, tile_count_slider, skip_hash_toggle ] load_to_browser_inputs = [ content_type, sort_type, period_type, use_search_term, search_term, tile_count_slider, base_filter, show_nsfw ] cancel_btn_list = [cancel_all_tags,cancel_ver_search,cancel_installed,cancel_update_preview] browser = [ver_search,save_all_tags,load_installed,update_preview] browser_installed_load = [cancel_installed,load_to_browser_installed,installed_progress] browser_load = [cancel_ver_search,load_to_browser,version_progress] browser_installed_list = page_outputs + browser + browser_installed_load browser_list = page_outputs + browser + browser_load # Page Button Functions # page_btn_list = { refresh.click: _api.update_model_list, search_term.submit: _api.update_model_list, get_next_page.click: _api.update_next_page, get_prev_page.click: _api.update_prev_page } for trigger, function in page_btn_list.items(): trigger(fn=function, inputs=page_inputs, outputs=page_outputs) trigger(fn=None, _js="() => multi_model_select()") for button in cancel_btn_list: button.click(fn=_file.cancel_scan) # Update model Functions # ver_search.click( fn=_file.ver_search_start, inputs=[ver_start], outputs=[ ver_start, ver_search, cancel_ver_search, load_installed, save_all_tags, update_preview, version_progress ] ) ver_start.change( fn=_file.file_scan, inputs=file_scan_inputs, outputs=[ version_progress, ver_finish ] ) ver_finish.change( fn=_file.scan_finish, outputs=[ ver_search, save_all_tags, load_installed, update_preview, cancel_ver_search, load_to_browser ] ) load_installed.click( fn=_file.installed_models_start, inputs=[installed_start], outputs=[ installed_start, load_installed, cancel_installed, ver_search, save_all_tags, update_preview, installed_progress ] ) installed_start.change( fn=_file.file_scan, inputs=file_scan_inputs, outputs=[ installed_progress, installed_finish ] ) installed_finish.change( fn=_file.scan_finish, outputs=[ ver_search, save_all_tags, load_installed, update_preview, cancel_installed, load_to_browser_installed ] ) save_all_tags.click( fn=_file.save_tag_start, inputs=[tag_start], outputs=[ tag_start, save_all_tags, cancel_all_tags, load_installed, ver_search, update_preview, tag_progress ] ) tag_start.change( fn=_file.file_scan, inputs=file_scan_inputs, outputs=[ tag_progress, tag_finish ] ) tag_finish.change( fn=_file.save_tag_finish, outputs=[ ver_search, save_all_tags, load_installed, update_preview, cancel_all_tags ] ) update_preview.click( fn=_file.save_preview_start, inputs=[preview_start], outputs=[ preview_start, update_preview, cancel_update_preview, load_installed, ver_search, save_all_tags, preview_progress ] ) preview_start.change( fn=_file.file_scan, inputs=file_scan_inputs, outputs=[ preview_progress, preview_finish ] ) preview_finish.change( fn=_file.save_preview_finish, outputs=[ ver_search, save_all_tags, load_installed, update_preview, cancel_update_preview ] ) load_to_browser_installed.click( fn=_file.load_to_browser, inputs=load_to_browser_inputs, outputs=browser_installed_list ) load_to_browser.click( fn=_file.load_to_browser, inputs=load_to_browser_inputs, outputs=browser_list ) if ver_bool: tab_name = "CivitAI Browser+" else: tab_name = "Civitai Browser+" return (civitai_interface, tab_name, "civitai_interface"), def subfolder_list(folder, desc=None): insert_sub_1 = getattr(opts, "insert_sub_1", False) insert_sub_2 = getattr(opts, "insert_sub_2", False) insert_sub_3 = getattr(opts, "insert_sub_3", False) insert_sub_4 = getattr(opts, "insert_sub_4", False) insert_sub_5 = getattr(opts, "insert_sub_5", False) insert_sub_6 = getattr(opts, "insert_sub_6", False) insert_sub_7 = getattr(opts, "insert_sub_7", False) insert_sub_8 = getattr(opts, "insert_sub_8", False) insert_sub_9 = getattr(opts, "insert_sub_9", False) insert_sub_10 = getattr(opts, "insert_sub_10", False) insert_sub_11 = getattr(opts, "insert_sub_11", False) insert_sub_12 = getattr(opts, "insert_sub_12", False) insert_sub_13 = getattr(opts, "insert_sub_13", False) insert_sub_14 = getattr(opts, "insert_sub_14", False) dot_subfolders = getattr(opts, "dot_subfolders", True) if folder == None: return try: model_folder = _api.contenttype_folder(folder, desc) sub_folders = ["None"] for root, dirs, _ in os.walk(model_folder, followlinks=True): if dot_subfolders: dirs = [d for d in dirs if not d.startswith('.')] dirs = [d for d in dirs if not any(part.startswith('.') for part in os.path.join(root, d).split(os.sep))] for d in dirs: sub_folder = os.path.relpath(os.path.join(root, d), model_folder) if sub_folder: sub_folders.append(f'{os.sep}{sub_folder}') sub_folders.remove("None") sub_folders = sorted(sub_folders, key=lambda x: (x.lower(), x)) sub_folders.insert(0, "None") if insert_sub_1: sub_folders.insert(1, f"{os.sep}Base model") if insert_sub_2: sub_folders.insert(2, f"{os.sep}Base model{os.sep}Author name") if insert_sub_3: sub_folders.insert(3, f"{os.sep}Base model{os.sep}Author name{os.sep}Model name") if insert_sub_4: sub_folders.insert(4, f"{os.sep}Base model{os.sep}Author name{os.sep}Model name{os.sep}Version name") if insert_sub_5: sub_folders.insert(5, f"{os.sep}Base model{os.sep}Model name") if insert_sub_6: sub_folders.insert(6, f"{os.sep}Base model{os.sep}Model name{os.sep}Model version") if insert_sub_7: sub_folders.insert(7, f"{os.sep}Author name") if insert_sub_8: sub_folders.insert(8, f"{os.sep}Author name{os.sep}Base model") if insert_sub_9: sub_folders.insert(9, f"{os.sep}Author name{os.sep}Base model{os.sep}Model name") if insert_sub_10: sub_folders.insert(10, f"{os.sep}Author name{os.sep}Base model{os.sep}Model name{os.sep}Model version") if insert_sub_11: sub_folders.insert(11, f"{os.sep}Author name{os.sep}Model name") if insert_sub_12: sub_folders.insert(12, f"{os.sep}Author name{os.sep}Model name{os.sep}Model version") if insert_sub_13: sub_folders.insert(13, f"{os.sep}Model name") if insert_sub_14: sub_folders.insert(14, f"{os.sep}Model name{os.sep}Model version") list = set() sub_folders = [x for x in sub_folders if not (x in list or list.add(x))] except: return None return sub_folders def make_lambda(folder, desc): return lambda: {"choices": subfolder_list(folder, desc)} def on_ui_settings(): if ver_bool: browser = ("civitai_browser", "Browser") download = ("civitai_browser_download", "Downloads") from modules.options import categories categories.register_category("civitai_browser_plus", "CivitAI Browser+") cat_id = "civitai_browser_plus" else: section = ("civitai_browser_plus", "CivitAI Browser+") browser = download = section if not (hasattr(shared.OptionInfo, "info") and callable(getattr(shared.OptionInfo, "info"))): def info(self, info): self.label += f" ({info})" return self shared.OptionInfo.info = info # Download Options shared.opts.add_option( "use_aria2", shared.OptionInfo( True, "Download models using Aria2", section=download, **({'category_id': cat_id} if ver_bool else {}) ).info("Disable this option if you're experiencing any issues with downloads.") ) shared.opts.add_option( "disable_dns", shared.OptionInfo( False, "Disable Async DNS for Aria2", section=download, **({'category_id': cat_id} if ver_bool else {}) ).info("Useful for users who use PortMaster or other software that controls the DNS") ) shared.opts.add_option( "show_log", shared.OptionInfo( False, "Show Aria2 logs in console", section=download, **({'category_id': cat_id} if ver_bool else {}) ).info("Requires UI reload") ) shared.opts.add_option( "split_aria2", shared.OptionInfo( 64, "Number of connections to use for downloading a model", gr.Slider, lambda: {"maximum": "64", "minimum": "1", "step": "1"}, section=download, **({'category_id': cat_id} if ver_bool else {}) ).info("Only applies to Aria2") ) shared.opts.add_option( "aria2_flags", shared.OptionInfo( r"", "Custom Aria2 command line flags", section=download, **({'category_id': cat_id} if ver_bool else {}) ).info("Requires UI reload") ) shared.opts.add_option( "unpack_zip", shared.OptionInfo( False, "Automatically unpack .zip files after downloading", section=download, **({'category_id': cat_id} if ver_bool else {}) ) ) shared.opts.add_option( "save_api_info", shared.OptionInfo( False, "Save API info of model when saving model info", section=download, **({'category_id': cat_id} if ver_bool else {}) ).info("creates an api_info.json file when saving any model info with all the API data of the model") ) shared.opts.add_option( "auto_save_all_img", shared.OptionInfo( False, "Automatically save all images", section=download, **({'category_id': cat_id} if ver_bool else {}) ).info("Automatically saves all the images of a model after downloading") ) # Browser Options shared.opts.add_option( "custom_api_key", shared.OptionInfo( r"", "Personal CivitAI API key", section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info("You can create your own API key in your CivitAI account settings, this required for some downloads, Requires UI reload") ) shared.opts.add_option( "hide_early_access", shared.OptionInfo( True, "Hide early access models", section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info("Early access models are only downloadable for supporter tier members") ) shared.opts.add_option( "use_LORA", shared.OptionInfo( ver_bool, "Treat LoCon's as LORA's", section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info("SD-WebUI v1.5 and higher treats LoCON's the same as LORA's, Requires UI reload") ) shared.opts.add_option( "dot_subfolders", shared.OptionInfo( True, "Hide sub-folders that start with a '.'", section=browser, **({'category_id': cat_id} if ver_bool else {}) ) ) shared.opts.add_option( "use_local_html", shared.OptionInfo( False, "Use local HTML file for model info", section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info("Uses the matching local HTML file when pressing CivitAI button on model cards in txt2img and img2img") ) shared.opts.add_option( "page_header", shared.OptionInfo( False, "Page navigation as header", section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info("Keeps the page navigation always visible at the top, Requires UI reload") ) shared.opts.add_option( "video_playback", shared.OptionInfo( True, 'Gif/video playback in the browser', section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info("Disable this option if you're experiencing high CPU usage during video/gif playback") ) shared.opts.add_option( "individual_meta_btn", shared.OptionInfo( True, 'Individual prompt buttons', section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info("Turns individual prompts from an example image into a button to send it to txt2img") ) shared.opts.add_option( "update_log", shared.OptionInfo( True, 'Show console logs during update scanning', section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info('Shows the "is currently outdated" messages in the console when scanning models for available updates') ) shared.opts.add_option( "image_location", shared.OptionInfo( r"", "Custom save images location", section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info("Overrides the download folder location when saving images.") ) shared.opts.add_option( "sub_image_location", shared.OptionInfo( True, 'Use sub folders inside custom images location', section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info("Will append any content type and sub folders to the custom path.") ) shared.opts.add_option( "local_path_in_html", shared.OptionInfo( False, "Use local images in the HTML", section=browser, **({'category_id': cat_id} if ver_bool else {}) ).info("Does not work in combination with the \"Use local HTML file for model info\" option!") ) shared.opts.add_option( "save_to_custom", shared.OptionInfo( False, "Store the HTML and api_info in the custom images location", section=browser, **({'category_id': cat_id} if ver_bool else {}) ) ) id_and_sub_options = { "1" : f"{os.sep}Base model", "2" : f"{os.sep}Base model{os.sep}Author name", "3" : f"{os.sep}Base model{os.sep}Author name{os.sep}Model name", "4" : f"{os.sep}Base model{os.sep}Author name{os.sep}Model name{os.sep}Model version", "5" : f"{os.sep}Base model{os.sep}Model name", "6" : f"{os.sep}Base model{os.sep}Model name{os.sep}Model version", "7" : f"{os.sep}Author name", "8" : f"{os.sep}Author name{os.sep}Base model", "9" : f"{os.sep}Author name{os.sep}Base model{os.sep}Model name", "10" : f"{os.sep}Author name{os.sep}Base model{os.sep}Model name{os.sep}Model version", "11" : f"{os.sep}Author name{os.sep}Model name", "12" : f"{os.sep}Author name{os.sep}Model name{os.sep}Model version", "13" : f"{os.sep}Model name", "14" : f"{os.sep}Model name{os.sep}Model version", } for number, string in id_and_sub_options.items(): shared.opts.add_option( f"insert_sub_{number}", shared.OptionInfo( False, f"Insert: [{string}]", section=browser, **({'category_id': cat_id} if ver_bool else {}) ) ) use_LORA = getattr(opts, "use_LORA", False) # Default sub folders folders = [ "Checkpoint", "LORA & LoCon" if use_LORA else "LORA", "LoCon" if not use_LORA else None, "TextualInversion", "Poses", "Controlnet", "Hypernetwork", "MotionModule", ("Upscaler", "SWINIR"), ("Upscaler", "REALESRGAN"), ("Upscaler", "GFPGAN"), ("Upscaler", "BSRGAN"), ("Upscaler", "ESRGAN"), "VAE", "AestheticGradient", "Wildcards", "Workflows", "Other" ] for folder in folders: if folder == None: continue desc = None if isinstance(folder, tuple): folder_name = " - ".join(folder) setting_name = f"{folder[1]}_upscale" folder = folder[0] desc = folder[1] else: folder_name = folder setting_name = folder if folder == "LORA & LoCon": folder = "LORA" setting_name = "LORA_LoCon" shared.opts.add_option(f"{setting_name}_subfolder", shared.OptionInfo("None", folder_name, gr.Dropdown, make_lambda(folder, desc), section=download, **({'category_id': cat_id} if ver_bool else {}))) script_callbacks.on_ui_tabs(on_ui_tabs) script_callbacks.on_ui_settings(on_ui_settings)