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
google-labs-jules[bot] 2025-06-23 00:23:36 +00:00
parent b48c86cbff
commit 0e82250c52
6 changed files with 54 additions and 48 deletions

View File

@ -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 = [

View File

@ -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)

View File

@ -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,

View File

@ -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,

View File

@ -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",

View File

@ -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