From 1cde3d325dd5b58ae8bf7b82f71e9f9617cc698a Mon Sep 17 00:00:00 2001 From: nabilaba Date: Wed, 11 Jun 2025 00:09:21 +0700 Subject: [PATCH] separate file, and more function --- presets/nabil.json | 13 --- webui.py | 195 +++++-------------------------- webui_others.py | 280 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+), 177 deletions(-) delete mode 100644 presets/nabil.json create mode 100644 webui_others.py diff --git a/presets/nabil.json b/presets/nabil.json deleted file mode 100644 index 9c2d4a12..00000000 --- a/presets/nabil.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "default_refiner_switch": 0.5, - "default_cfg_scale": 4.0, - "default_sample_sharpness": 2.0, - "default_sampler": "dpmpp_2m_sde_gpu", - "default_scheduler": "karras", - "default_performance": "Quality", - "default_prompt": "ultra-detailed, photorealistic, 8K resolution, high dynamic range, realistic lighting, global illumination, shallow depth of field, cinematic look, DSLR camera, ray tracing, volumetric lighting, bokeh effect, hyper-realistic textures, shot on Canon EOS R5, 50mm lens, HDR imaging, post-processed in Adobe Lightroom and Photoshop", - "default_prompt_negative": "low resolution, extra limbs, cartoon, anime, illustration, drawing, painting, sketch, grainy, noisy, watermark, logo, text, glitch, jpeg artifacts, duplicate, poorly drawn, out of frame, cropped, low quality, bad anatomy, bad hands, extra fingers, distorted face", - "default_styles": [], - "default_aspect_ratio": "1080*1920", - "default_overwrite_step": -1 -} \ No newline at end of file diff --git a/webui.py b/webui.py index 567965bc..0962d634 100644 --- a/webui.py +++ b/webui.py @@ -24,6 +24,7 @@ from modules.ui_gradio_extensions import reload_javascript from modules.auth import auth_enabled, check_auth from modules.util import is_json +import webui_others import os import shutil import requests @@ -562,7 +563,7 @@ with shared.gradio_root: outputs=enhance_input_panel, queue=False, show_progress=False, _js=switch_js) with gr.Column(scale=1, visible=modules.config.default_advanced_checkbox) as advanced_column: - with gr.Tab(label='Settings'): + with gr.Tab(label='Settings') as seetings_tab: if not args_manager.args.disable_preset_selection: preset_selection = gr.Dropdown(label='Preset', choices=modules.config.available_presets, @@ -891,7 +892,23 @@ with shared.gradio_root: refresh_files_output += [preset_selection] refresh_files.click(refresh_files_clicked, [], refresh_files_output + lora_ctrls, queue=False, show_progress=False) - + + advanced_checkbox.select( + fn=refresh_files_clicked, + inputs=[], + outputs=refresh_files_output + lora_ctrls, + queue=False, + show_progress=False + ) + + seetings_tab.select( + fn=refresh_files_clicked, + inputs=[], + outputs=refresh_files_output + lora_ctrls, + queue=False, + show_progress=False + ) + model_tab.select( fn=refresh_files_clicked, inputs=[], @@ -900,168 +917,18 @@ with shared.gradio_root: show_progress=False ) - with gr.Tab(label='Others'): - with gr.Column(): - with gr.Tab(label='Download'): - file_input_path = gr.Textbox( - label='File Path or URL', - placeholder='Enter full path to file or downloadable URL', - lines=1 - ) - - destination_folder = gr.Dropdown( - label='Target Folder', - choices=[ - modules.config.paths_checkpoints[0], - modules.config.paths_loras[0], - modules.config.path_embeddings, - modules.config.path_vae, - modules.config.path_outputs - ], - value=modules.config.paths_checkpoints[0] - ) - - download_result_text = gr.Textbox(label='Download Status', interactive=False) - download_file_button = gr.Button(value='\U00002B07 Download', variant='secondary', elem_classes='refresh_button') - - def perform_download(file_url_or_path, target_directory): - try: - if isinstance(target_directory, tuple): - target_directory = target_directory[1] - - if file_url_or_path.startswith(('http://', 'https://')): - response = requests.get(file_url_or_path, stream=True) - response.raise_for_status() - - # Ambil nama file dari header jika tersedia - content_disposition = response.headers.get('Content-Disposition', '') - if 'filename=' in content_disposition: - filename = content_disposition.split('filename=')[-1].strip('"') - else: - # Fallback: ambil dari path URL - parsed_url = urlparse(file_url_or_path) - filename = unquote(os.path.basename(parsed_url.path)) - downloaded_path = load_file_from_url( - file_url_or_path, - model_dir=target_directory, - progress=True, - file_name=filename - ) - modules.config.update_files() # ✅ REFRESH MODEL LIST - return ( - f"✅ Downloaded to: {downloaded_path}", - gr.update(choices=['None'] + modules.config.model_filenames), - gr.update(choices=['None'] + modules.config.model_filenames), - *[ - item - for _ in range(len(lora_ctrls) // 3) - for item in ( - gr.update(interactive=True), - gr.update(choices=['None'] + modules.config.lora_filenames), - gr.update() - ) - ] - ) - - if os.path.isfile(file_url_or_path): - filename = os.path.basename(file_url_or_path) - destination_path = os.path.join(target_directory, filename) - shutil.copy(file_url_or_path, destination_path) - modules.config.update_files() # ✅ Auto-refresh files - return ( - f"✅ Copied to: {destination_path}", - gr.update(choices=['None'] + modules.config.model_filenames), - gr.update(choices=['None'] + modules.config.model_filenames), - *[ - item - for _ in range(len(lora_ctrls) // 3) - for item in ( - gr.update(interactive=True), - gr.update(choices=['None'] + modules.config.lora_filenames), - gr.update() - ) - ] - ) - - return ("❌ Error: File not found or invalid input.",) + ( - gr.update(), gr.update(), *[gr.update()] * len(lora_ctrls) - ) - - except Exception as e: - return (f"❌ Failed: {str(e)}",) + ( - gr.update(), gr.update(), *[gr.update()] * len(lora_ctrls) - ) - - download_file_button.click( - fn=perform_download, - inputs=[file_input_path, destination_folder], - outputs=[download_result_text, base_model, refiner_model] + lora_ctrls - ) - - with gr.Tab(label='Delete') as delete_tab: - delete_folder_dropdown = gr.Dropdown( - label='Select Folder', - choices=[ - modules.config.paths_checkpoints[0], - modules.config.paths_loras[0], - modules.config.path_embeddings, - modules.config.path_vae, - modules.config.path_outputs - ], - value=modules.config.paths_checkpoints[0] - ) - - file_list_dropdown = gr.Dropdown(label="Select File to Delete", choices=[], multiselect=True) - delete_button = gr.Button(value='\U0001F5D1 Delete Selected File(s)', variant='stop') - delete_status = gr.Textbox(visible=True, interactive=False, label="Delete Status") - - def update_file_list(folder): - try: - files = [f for f in os.listdir(folder) if os.path.isfile(os.path.join(folder, f))] - return gr.update(choices=files, value=[]) - except Exception as e: - return gr.update(choices=[], value=[]) - - def delete_selected_files(folder, selected_files): - deleted = [] - errors = [] - - for fname in selected_files: - try: - file_path = os.path.join(folder, fname) - if os.path.isfile(file_path): - os.remove(file_path) - deleted.append(fname) - else: - errors.append(fname) - except Exception as e: - errors.append(f"{fname} (error: {e})") - - if not deleted and not errors: - status = "⚠️ No files selected." - else: - status = "" - if deleted: - status += f"✅ Deleted: {', '.join(deleted)}. " - if errors: - status += f"❌ Failed: {', '.join(errors)}" - - try: - files = [f for f in os.listdir(folder) if os.path.isfile(os.path.join(folder, f))] - except Exception: - files = [] - - return status.strip(), gr.update(choices=files, value=[]) - - delete_folder_dropdown.change(update_file_list, inputs=[delete_folder_dropdown], outputs=[file_list_dropdown]) - delete_button.click(delete_selected_files, inputs=[delete_folder_dropdown, file_list_dropdown], outputs=[delete_status, file_list_dropdown]) - delete_tab.select( - fn=update_file_list, - inputs=[delete_folder_dropdown], - outputs=[file_list_dropdown], - queue=False, - show_progress=False - ) + webui_others.build_others_tab( + prompt=prompt, + negative_prompt=negative_prompt, + aspect_ratio=aspect_ratios_selection, + performance=performance_selection, + styles=style_selections, + base_model=base_model, + refiner_model=refiner_model, + refiner_switch=refiner_switch, + image_number=image_number, + lora_ctrls=lora_ctrls + ) state_is_generating = gr.State(False) diff --git a/webui_others.py b/webui_others.py new file mode 100644 index 00000000..0927541b --- /dev/null +++ b/webui_others.py @@ -0,0 +1,280 @@ +# webui_others.py +import os +import shutil +import requests +from urllib.parse import urlparse, unquote +import gradio as gr +import modules.config +from modules.model_loader import load_file_from_url + +def build_others_tab( + prompt, + negative_prompt, + aspect_ratio, + performance, + styles, + base_model, + refiner_model, + refiner_switch, + image_number, + lora_ctrls +): + with gr.Tab(label="Others") as others_tab: + with gr.Tab(label="Download"): + file_input_path = gr.Textbox( + label="File Path or URL", + placeholder="Enter full path to file or downloadable URL", + lines=1, + ) + + destination_folder = gr.Dropdown( + label="Target Folder", + choices=[ + modules.config.paths_checkpoints[0], + modules.config.paths_loras[0], + modules.config.path_embeddings, + modules.config.path_vae, + ], + value=modules.config.paths_checkpoints[0], + ) + + download_result_text = gr.Textbox( + label="Download Status", interactive=False + ) + download_file_button = gr.Button( + value="\u2b07 Download", + variant="secondary", + elem_classes="refresh_button", + ) + + def perform_download(file_url_or_path, target_directory): + try: + if isinstance(target_directory, tuple): + target_directory = target_directory[1] + + if file_url_or_path.startswith(("http://", "https://")): + response = requests.get(file_url_or_path, stream=True) + response.raise_for_status() + content_disposition = response.headers.get( + "Content-Disposition", "" + ) + if "filename=" in content_disposition: + filename = content_disposition.split("filename=")[ + -1 + ].strip('"') + else: + parsed_url = urlparse(file_url_or_path) + filename = unquote(os.path.basename(parsed_url.path)) + downloaded_path = load_file_from_url( + file_url_or_path, + model_dir=target_directory, + progress=True, + file_name=filename, + ) + return f"\u2705 Downloaded to: {downloaded_path}" + + if os.path.isfile(file_url_or_path): + filename = os.path.basename(file_url_or_path) + destination_path = os.path.join(target_directory, filename) + shutil.copy(file_url_or_path, destination_path) + return f"\u2705 Copied to: {destination_path}" + + return "\u274c Error: File not found or invalid input." + + except Exception as e: + return f"\u274c Failed: {str(e)}" + + download_file_button.click( + fn=perform_download, + inputs=[file_input_path, destination_folder], + outputs=[download_result_text], + ) + + with gr.Tab(label="Delete"): + delete_folder_dropdown = gr.Dropdown( + label="Select Folder", + choices=[ + modules.config.paths_checkpoints[0], + modules.config.paths_loras[0], + modules.config.path_embeddings, + modules.config.path_vae, + modules.config.get_dir_or_set_default("path_presets", "../presets"), + ], + value=modules.config.paths_checkpoints[0], + ) + + file_list_dropdown = gr.Dropdown( + label="Select File to Delete", choices=[], multiselect=True + ) + delete_button = gr.Button( + value="\U0001f5d1 Delete Selected File(s)", variant="stop" + ) + delete_status = gr.Textbox( + visible=True, interactive=False, label="Delete Status" + ) + + def update_file_list(folder): + try: + files = [ + f + for f in os.listdir(folder) + if os.path.isfile(os.path.join(folder, f)) + ] + return gr.update(choices=files, value=[]) + except Exception as e: + return gr.update(choices=[], value=[]) + + def delete_selected_files(folder, selected_files): + deleted = [] + errors = [] + + for fname in selected_files: + try: + file_path = os.path.join(folder, fname) + if os.path.isfile(file_path): + os.remove(file_path) + deleted.append(fname) + else: + errors.append(fname) + except Exception as e: + errors.append(f"{fname} (error: {e})") + + status = "" + if deleted: + status += f"\u2705 Deleted: {', '.join(deleted)}. " + if errors: + status += f"\u274c Failed: {', '.join(errors)}" + if not deleted and not errors: + status = "\u26a0\ufe0f No files selected." + + try: + files = [ + f + for f in os.listdir(folder) + if os.path.isfile(os.path.join(folder, f)) + ] + except Exception: + files = [] + + return status.strip(), gr.update(choices=files, value=[]) + + delete_folder_dropdown.change( + update_file_list, + inputs=[delete_folder_dropdown], + outputs=[file_list_dropdown], + ) + delete_button.click( + delete_selected_files, + inputs=[delete_folder_dropdown, file_list_dropdown], + outputs=[delete_status, file_list_dropdown], + ) + + with gr.Tab(label="Backup/Restore"): + with gr.Tab(label="Preset"): + with gr.Row(): + backup_name = gr.Textbox(label="Backup Filename (no extension)", placeholder="e.g. my_config_backup") + backup_button = gr.Button(value="\u2B06 Backup Settings") + backup_file = gr.File(label="Download .json", interactive=False) + + def clean_aspect_ratio(value): + if not value: + return None + raw = value.split(" ")[0] + return raw.replace("×", "*") # convert Unicode × to ASCII * + + def backup_selected_settings( + filename, + prompt, negative_prompt, aspect_ratio, performance, styles, + base_model, refiner_model, refiner_switch, image_number, + *lora_ctrls + ): + import json + if not filename: + return None + + config = { + "default_prompt": prompt, + "default_prompt_negative": negative_prompt, + "default_aspect_ratio": clean_aspect_ratio(aspect_ratio), + "default_performance": performance, + "default_styles": styles, + "default_model": base_model, + "default_refiner": refiner_model, + "default_refiner_switch": refiner_switch, + "default_image_number": image_number + } + + loras = [] + for i in range(0, len(lora_ctrls), 3): + enabled = lora_ctrls[i] + model = lora_ctrls[i + 1] + weight = lora_ctrls[i + 2] + if model and model != "None": + loras.append([enabled, model, weight]) + + if loras: + config["default_loras"] = loras + + config = {k: v for k, v in config.items() if v not in [None, "", [], "None"]} + + out_path = os.path.join("outputs", f"{filename}.json") + with open(out_path, "w") as f: + json.dump(config, f, indent=2) + + return out_path + + backup_button.click( + fn=backup_selected_settings, + inputs=[ + backup_name, + prompt, + negative_prompt, + aspect_ratio, + performance, + styles, + base_model, + refiner_model, + refiner_switch, + image_number, + ] + lora_ctrls, + outputs=[backup_file], + ) + + with gr.Tab(label="Restore"): + with gr.Row(): + restore_file = gr.File(label="Upload Config File (.json)", file_types=[".json"]) + restore_button = gr.Button(value="\u267B️ Restore to Presets Folder") + restore_status = gr.Textbox(label="Status", interactive=False) + + def restore_config_file(file_obj): + try: + if file_obj is None: + return "\u26A0 No file selected." + filename = os.path.basename(file_obj.name) + presets_dir = os.path.join("presets") + os.makedirs(presets_dir, exist_ok=True) + destination = os.path.join(presets_dir, filename) + shutil.copy(file_obj.name, destination) + return f"\u2705 Saved to presets/{filename}" + except Exception as e: + return f"\u274C Failed to restore: {e}" + + restore_button.click( + fn=restore_config_file, + inputs=[restore_file], + outputs=[restore_status] + ) + + gr.Markdown( + "You can backup your current settings and restore them later. " + "This is useful for saving configurations or sharing with others." + ) + + + others_tab.select( + fn=update_file_list, + inputs=[delete_folder_dropdown], + outputs=[file_list_dropdown], + queue=False, + show_progress=False, + )