mirror of https://github.com/bmaltais/kohya_ss
Refactor: Remove easygui and replace dialogs with notifications
Removed all usage of the `easygui` library.
- Replaced `easygui.msgbox` calls with Gradio notifications (`gr.Info`, `gr.Warning`, `gr.Error`) to display messages and errors directly in the UI.
- Replaced `easygui.ynbox` and `easygui.boolbox` confirmation dialogs with a default action of proceeding with the operation, accompanied by a notification. This affects:
- Model saving: Will now overwrite existing models by default, notifying the user.
- Dataset balancing: Enabling 'insecure folder renaming' will proceed without a second confirmation, with a warning displayed.
- Manual captioning: Importing tags will overwrite existing quick tags by default, with a notification.
- Removed `easygui` from all Python import statements.
- Removed `easygui` from `requirements.txt` and `pyproject.toml`.
Note: The `uv.lock` file has not been modified as part of this commit. It should be regenerated using the `uv` tool to reflect the dependency changes in `pyproject.toml` and `requirements.txt`.
pull/3306/head
parent
b48c86cbff
commit
0e82250c52
|
|
@ -12,7 +12,6 @@ try:
|
|||
except ImportError:
|
||||
visibility = False
|
||||
|
||||
from easygui import msgbox
|
||||
from threading import Thread, Event
|
||||
from .custom_logging import setup_logging
|
||||
from .common_gui import setup_environment
|
||||
|
|
@ -60,7 +59,7 @@ class TensorboardManager:
|
|||
self.log.error(
|
||||
"Error: logging folder does not exist or does not contain logs."
|
||||
)
|
||||
msgbox(msg="Error: logging folder does not exist or does not contain logs.")
|
||||
gr.Warning("Error: logging folder does not exist or does not contain logs.")
|
||||
return self.get_button_states(started=False)
|
||||
|
||||
run_cmd = [
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ try:
|
|||
from tkinter import filedialog, Tk
|
||||
except ImportError:
|
||||
pass
|
||||
from easygui import msgbox, ynbox
|
||||
from typing import Optional
|
||||
from .custom_logging import setup_logging
|
||||
from .sd_modeltype import SDModelType
|
||||
|
|
@ -123,24 +122,32 @@ def check_if_model_exist(
|
|||
"""
|
||||
if headless:
|
||||
log.info(
|
||||
"Headless mode, skipping verification if model already exist... if model already exist it will be overwritten..."
|
||||
"Headless mode: If model already exists, it will be overwritten by default."
|
||||
)
|
||||
return False
|
||||
# No change needed for headless, it already implies proceeding.
|
||||
|
||||
model_path_to_check = ""
|
||||
model_type_for_message = ""
|
||||
|
||||
if save_model_as in ["diffusers", "diffusers_safetendors"]:
|
||||
ckpt_folder = os.path.join(output_dir, output_name)
|
||||
if os.path.isdir(ckpt_folder):
|
||||
msg = f"A diffuser model with the same name {ckpt_folder} already exists. Do you want to overwrite it?"
|
||||
if not ynbox(msg, "Overwrite Existing Model?"):
|
||||
log.info("Aborting training due to existing model with same name...")
|
||||
return True
|
||||
model_path_to_check = ckpt_folder
|
||||
model_type_for_message = "diffuser model"
|
||||
|
||||
elif save_model_as in ["ckpt", "safetensors"]:
|
||||
ckpt_file = os.path.join(output_dir, output_name + "." + save_model_as)
|
||||
if os.path.isfile(ckpt_file):
|
||||
msg = f"A model with the same file name {ckpt_file} already exists. Do you want to overwrite it?"
|
||||
if not ynbox(msg, "Overwrite Existing Model?"):
|
||||
log.info("Aborting training due to existing model with same name...")
|
||||
return True
|
||||
model_path_to_check = ckpt_file
|
||||
model_type_for_message = "model file"
|
||||
|
||||
if model_path_to_check:
|
||||
message = f"Existing {model_type_for_message} found: {model_path_to_check}. It will be overwritten."
|
||||
log.warning(message)
|
||||
if not headless:
|
||||
gr.Warning(message)
|
||||
# Returning False means "don't abort", so the overwrite will proceed.
|
||||
return False
|
||||
else:
|
||||
log.info(
|
||||
'Can\'t verify if existing model exist when save model is set as "same as source model", continuing to train model...'
|
||||
|
|
@ -165,7 +172,7 @@ def output_message(msg: str = "", title: str = "", headless: bool = False) -> No
|
|||
if headless:
|
||||
log.info(msg)
|
||||
else:
|
||||
msgbox(msg=msg, title=title)
|
||||
gr.Info(msg)
|
||||
|
||||
|
||||
def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id):
|
||||
|
|
@ -867,7 +874,7 @@ def find_replace(
|
|||
# Validate the presence of caption files and the search text
|
||||
if not search_text or not has_ext_files(folder_path, caption_file_ext):
|
||||
# Display a message box indicating no files were found
|
||||
msgbox(
|
||||
gr.Info(
|
||||
f"No files with extension {caption_file_ext} were found in {folder_path}..."
|
||||
)
|
||||
log.warning(
|
||||
|
|
@ -931,7 +938,7 @@ def color_aug_changed(color_aug):
|
|||
"""
|
||||
# If color augmentation is enabled, disable cache latent and return a new checkbox
|
||||
if color_aug:
|
||||
msgbox(
|
||||
gr.Info(
|
||||
'Disabling "Cache latent" because "Color augmentation" has been selected...'
|
||||
)
|
||||
return gr.Checkbox(value=False, interactive=False)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import os
|
||||
import re
|
||||
import gradio as gr
|
||||
from easygui import msgbox, boolbox
|
||||
from .common_gui import get_folder_path, scriptdir, list_dirs, create_refresh_button
|
||||
|
||||
from .custom_logging import setup_logging
|
||||
|
|
@ -13,20 +12,20 @@ log = setup_logging()
|
|||
import os
|
||||
import re
|
||||
import logging as log
|
||||
from easygui import msgbox
|
||||
# from easygui import msgbox # easygui msgbox will be handled in step 2
|
||||
|
||||
def dataset_balancing(concept_repeats, folder, insecure):
|
||||
|
||||
if not concept_repeats > 0:
|
||||
# Display an error message if the total number of repeats is not a valid integer
|
||||
msgbox("Please enter a valid integer for the total number of repeats.")
|
||||
gr.Error("Please enter a valid integer for the total number of repeats.")
|
||||
return
|
||||
|
||||
concept_repeats = int(concept_repeats)
|
||||
|
||||
# Check if folder exist
|
||||
if folder == "" or not os.path.isdir(folder):
|
||||
msgbox("Please enter a valid folder for balancing.")
|
||||
gr.Error("Please enter a valid folder for balancing.")
|
||||
return
|
||||
|
||||
pattern = re.compile(r"^\d+_.+$")
|
||||
|
|
@ -93,19 +92,23 @@ def dataset_balancing(concept_repeats, folder, insecure):
|
|||
f"Skipping folder {subdir} because it does not match kohya_ss expected syntax..."
|
||||
)
|
||||
|
||||
msgbox("Dataset balancing completed...")
|
||||
gr.Info("Dataset balancing completed...")
|
||||
|
||||
|
||||
|
||||
def warning(insecure):
|
||||
if insecure:
|
||||
if boolbox(
|
||||
f"WARNING!!! You have asked to rename non kohya_ss <num>_<text> folders...\n\nAre you sure you want to do that?",
|
||||
choices=("Yes, I like danger", "No, get me out of here"),
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def warning(insecure_checked, headless=False): # Renamed insecure to insecure_checked for clarity
|
||||
if insecure_checked:
|
||||
message = "DANGER!!! Insecure folder renaming is active. Folders not matching the standard '<number>_<text>' pattern may be renamed."
|
||||
# Log the warning regardless of headless state, as it's a significant user choice
|
||||
log.warning(message)
|
||||
if not headless:
|
||||
gr.Warning(message)
|
||||
# Return the state of the checkbox. If it was checked, it remains checked.
|
||||
# The calling UI's .change(outputs=checkbox) will ensure this.
|
||||
return insecure_checked
|
||||
# If the checkbox was unchecked, or if it was checked and then logic above ran,
|
||||
# this ensures the checkbox state is correctly returned to Gradio.
|
||||
return insecure_checked
|
||||
|
||||
|
||||
def gradio_dataset_balancing_tab(headless=False):
|
||||
|
|
@ -168,7 +171,7 @@ def gradio_dataset_balancing_tab(headless=False):
|
|||
value=False,
|
||||
label="DANGER!!! -- Insecure folder renaming -- DANGER!!!",
|
||||
)
|
||||
insecure.change(warning, inputs=insecure, outputs=insecure)
|
||||
insecure.change(lambda val: warning(val, headless=headless), inputs=insecure, outputs=insecure)
|
||||
balance_button = gr.Button("Balance dataset")
|
||||
balance_button.click(
|
||||
dataset_balancing,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import gradio as gr
|
||||
from easygui import msgbox, boolbox
|
||||
from .common_gui import get_folder_path, scriptdir, list_dirs
|
||||
from math import ceil
|
||||
import os
|
||||
|
|
@ -48,7 +47,7 @@ def paginate_go(page, max_page):
|
|||
try:
|
||||
page = float(page)
|
||||
except:
|
||||
msgbox(f"Invalid page num: {page}")
|
||||
gr.Error(f"Invalid page num: {page}")
|
||||
return
|
||||
return paginate(page, max_page, 0)
|
||||
|
||||
|
|
@ -107,7 +106,7 @@ def update_image_tags(
|
|||
|
||||
|
||||
def import_tags_from_captions(
|
||||
images_dir, caption_ext, quick_tags_text, ignore_load_tags_word_count
|
||||
images_dir, caption_ext, quick_tags_text, ignore_load_tags_word_count, headless=False
|
||||
):
|
||||
"""
|
||||
Scans images directory for all available captions and loads all tags
|
||||
|
|
@ -119,23 +118,23 @@ def import_tags_from_captions(
|
|||
|
||||
# Check for images_dir
|
||||
if not images_dir:
|
||||
msgbox("Image folder is missing...")
|
||||
gr.Warning("Image folder is missing...")
|
||||
return empty_return()
|
||||
|
||||
if not os.path.exists(images_dir):
|
||||
msgbox("Image folder does not exist...")
|
||||
gr.Warning("Image folder does not exist...")
|
||||
return empty_return()
|
||||
|
||||
if not caption_ext:
|
||||
msgbox("Please provide an extension for the caption files.")
|
||||
gr.Warning("Please provide an extension for the caption files.")
|
||||
return empty_return()
|
||||
|
||||
if quick_tags_text:
|
||||
if not boolbox(
|
||||
f"Are you sure you wish to overwrite the current quick tags?",
|
||||
choices=("Yes", "No"),
|
||||
):
|
||||
return empty_return()
|
||||
overwrite_message = "Overwriting existing quick tags."
|
||||
if not headless:
|
||||
gr.Info(overwrite_message)
|
||||
log.info(overwrite_message)
|
||||
# Proceeding to overwrite by not returning early.
|
||||
|
||||
images_list = os.listdir(images_dir)
|
||||
image_files = [f for f in images_list if f.lower().endswith(IMAGE_EXTENSIONS)]
|
||||
|
|
@ -173,15 +172,15 @@ def load_images(images_dir, caption_ext, loaded_images_dir, page, max_page):
|
|||
|
||||
# Check for images_dir
|
||||
if not images_dir:
|
||||
msgbox("Image folder is missing...")
|
||||
gr.Warning("Image folder is missing...")
|
||||
return empty_return()
|
||||
|
||||
if not os.path.exists(images_dir):
|
||||
msgbox("Image folder does not exist...")
|
||||
gr.Warning("Image folder does not exist...")
|
||||
return empty_return()
|
||||
|
||||
if not caption_ext:
|
||||
msgbox("Please provide an extension for the caption files.")
|
||||
gr.Warning("Please provide an extension for the caption files.")
|
||||
return empty_return()
|
||||
|
||||
# Load Images
|
||||
|
|
@ -444,7 +443,7 @@ def gradio_manual_caption_gui_tab(headless=False, default_images_dir=None):
|
|||
|
||||
# Import tags button
|
||||
import_tags_button.click(
|
||||
import_tags_from_captions,
|
||||
lambda loaded_dir, cap_ext, q_text, ignore_wc: import_tags_from_captions(loaded_dir, cap_ext, q_text, ignore_wc, headless=headless),
|
||||
inputs=[
|
||||
loaded_images_dir,
|
||||
caption_ext,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ dependencies = [
|
|||
"bitsandbytes>=0.45.0",
|
||||
"dadaptation==3.2",
|
||||
"diffusers[torch]==0.32.2",
|
||||
"easygui==0.98.3",
|
||||
"einops==0.7.0",
|
||||
"fairscale==0.4.13",
|
||||
"ftfy==6.1.1",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ aiofiles==23.2.1
|
|||
altair==4.2.2
|
||||
dadaptation==3.2
|
||||
diffusers[torch]==0.32.2
|
||||
easygui==0.98.3
|
||||
einops==0.7.0
|
||||
fairscale==0.4.13
|
||||
ftfy==6.1.1
|
||||
|
|
|
|||
Loading…
Reference in New Issue