281 lines
11 KiB
Python
281 lines
11 KiB
Python
# 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,
|
||
)
|