import customtkinter
import tkinter as tk
from tkinter import font
from tkinter import Tk
from PIL import Image, ImageOps, ImageDraw, ImageFont,ImageTk
import os, sys
import ctypes
import pandas as pd
import numpy as np
import NAIA_search, NAIA_random_function_core, NAIA_Login, NAIA_generation
import json
import arti_list, tagbag, wlist, copyright_list_reformatted, remove_result_e, remove_result_qe, copyright_dict_0103
import character_dictionary as cd
import time
from datetime import datetime
import random
import threading, pyperclip
from ctypes import windll
from CTkListbox import *
from tkinter import filedialog
import io
from openpyxl import Workbook
from openpyxl.styles import Alignment
from openpyxl.drawing.image import Image as OpenpyxlImage
from collections import Counter
from artist_dictionary import artist_dict
import re
import requests
import base64
import queue
import webbrowser
import ctypes
from plyer import notification
import subprocess, copy
from tkinterdnd2 import TkinterDnD, DND_ALL
import gzip
from pathlib import Path

class Data:
    def __init__(self, wlist, tagbag, arti_list, copyright_list_reformatted, cd, remove_result_e, remove_result_qe):
        self.whitelist = wlist.whitelist
        self.bag_of_tags = tagbag.bag_of_tags
        self.afilter_30000 = arti_list.afilter_30000
        self.copyright_keys = copyright_list_reformatted.copyright_list
        self.character_keys = list(cd.character_dictionary.keys())
        nsfw_word = list(remove_result_e.keyword_counts.keys())
        questionable_word = list(remove_result_qe.keyword_counts.keys())
        self.qe_word = nsfw_word + questionable_word

    def get_qe_word(self):
        return self.qe_word

class AccountSetting(customtkinter.CTkToplevel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title("NAI Account Setting")
        self.attributes('-topmost', True)

        def on_close(self):
            self.withdraw()

        def NAI_connect(self):
            username = self.NAI_ID_entry.get().strip()
            password = self.NAI_PW_entry.get().strip()
            access_key = NAIA_Login.get_access_key(username, password)
            try:
                app.access_token = NAIA_Login.login(access_key)
                app.NAI_ID = username[:4]
                self.state_label.configure(text="(로그인 성공, 닫기 버튼을 눌러주세요.)", font=my_font)
                app.NAI_Account_Login.configure(state="disabled")
                app.NAI_Token_Remove.configure(state="normal")
                app.NAI_Account_State.configure(text="NAI Login : OK")
                app.image_generation_button.configure(state="normal")
            except Exception as e:
                print(e)
                self.state_label.configure(text="아이디 혹은 비밀번호 오류입니다.", font=my_font)

        self.button_frame = customtkinter.CTkFrame(self)
        self.button_frame.grid(row=0, padx=5, pady=5, sticky="nsew")
        self.button_frame.columnconfigure(0, weight=1)
        self.button_frame.columnconfigure(1, weight=4)

        my_font = customtkinter.CTkFont('Pretendard', 13)
        self.NAI_ID_label = customtkinter.CTkLabel(self.button_frame, text="NAI ID:", font=my_font)
        self.NAI_ID_label.grid(row = 0, column = 0, padx=5, pady=5, sticky="nsew")
        self.NAI_PW_label = customtkinter.CTkLabel(self.button_frame, text="NAI PW:", font=my_font)
        self.NAI_PW_label.grid(row = 1, column = 0, padx=5, pady=5, sticky="nsew")
        self.NAI_ID_entry = customtkinter.CTkEntry(self.button_frame)
        self.NAI_ID_entry.grid(row = 0, column = 1, padx=5, pady=5, sticky="nsew")
        self.NAI_PW_entry = customtkinter.CTkEntry(self.button_frame, show="*")
        self.NAI_PW_entry.grid(row = 1, column = 1, padx=5, pady=5, sticky="nsew")
        self.connect_button = customtkinter.CTkButton(self.button_frame, text="Connect", command=lambda:NAI_connect(self))
        self.connect_button.grid(row = 2, column = 0, columnspan=2, padx=5, pady=5, sticky="n")
        self.state_label = customtkinter.CTkLabel(self.button_frame, text="해당 접속기능은 정상적인 접속 패턴이 아닌점 참고 부탁드립니다.", font=my_font)
        self.state_label.grid(row = 3, column = 0, columnspan=2, padx=5, pady=5, sticky="nsew")

        self.protocol("WM_DELETE_WINDOW", lambda: on_close(self))

class Advanced_setting(customtkinter.CTkToplevel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title("기타 설정")
        self.resizable(width=False, height=False)
        self.geometry("270x250")
        self.attributes('-topmost', True)
        my_font = customtkinter.CTkFont('Pretendard', 13)

        def on_close(self):
                self.withdraw()

        def select_folder(self):
            folder_selected = filedialog.askdirectory()
            try:
                self.save_path.configure(state="normal")
                self.save_path.delete(0,"end")
                self.save_path.insert(0, folder_selected)
                self.save_path.configure(state="disabled")
                app.output_file_path_personal = True
                app.output_file_path = folder_selected
            except:
                pass

        def deselect_folder(self):
                self.save_path.configure(state="normal")
                app.output_file_path = f"output_NAI\\{app.start_time}\\txt2img"
                self.save_path.delete(0,"end")
                self.save_path.insert(0, app.output_file_path)
                self.save_path.configure(state="disabled")
                app.output_file_path_personal = True

        self.advanced_setting_frame = customtkinter.CTkFrame(self, width=250)
        self.advanced_setting_frame.grid(row=0, column=0, padx=10, pady=5, sticky="nsew")
        self.change_save_path_button = customtkinter.CTkButton(self.advanced_setting_frame, text="이미지 저장 경로 변경", command= lambda: select_folder(self), font=my_font, width=250)
        self.change_save_path_button.grid(row=0, column=0, pady=5,sticky="nsew")
        self.save_path = customtkinter.CTkEntry(self.advanced_setting_frame, font=my_font, width=250)
        self.save_path.insert(0, app.output_file_path)
        self.save_path.configure(state="disabled")
        self.save_path.grid(row=1, column=0, pady=5,sticky="nsew")
        self.change_save_path_button2 = customtkinter.CTkButton(self.advanced_setting_frame, text="경로 초기화", command= lambda: deselect_folder(self), font=my_font, width=250)
        self.change_save_path_button2.grid(row=2, column=0, pady=5,sticky="nsew")
        self.file_name_label = customtkinter.CTkLabel(self.advanced_setting_frame, text=" -- 파일명.png 규칙 설정 -- " , font=my_font, width=250)
        self.file_name_label.grid(row=3, column=0, pady=5,sticky="n")
        self.radio1 = customtkinter.CTkRadioButton(self.advanced_setting_frame, text="생성시간.png : 20231230_123001.png", variable=app.name_var, value="time", font=my_font)
        self.radio1.grid(row=4, column=0)
        self.radio2 = customtkinter.CTkRadioButton(self.advanced_setting_frame, text="생성순서.png : 00001.png,00002.png", variable=app.name_var, value="count", font=my_font)
        self.radio2.grid(row=5, column=0)
        self.file_name_label2 = customtkinter.CTkLabel(self.advanced_setting_frame, text="*생성순서 적용시 날짜_시간 폴더에 저장" , font=my_font, width=250)
        self.file_name_label2.grid(row=6, column=0, pady=5,sticky="n")

        self.protocol("WM_DELETE_WINDOW", lambda: on_close(self))

class Automation_setting(customtkinter.CTkToplevel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title("Automation 종료/지연 설정")

        self.var = customtkinter.StringVar()
        self.attributes('-topmost', True)
        my_font = customtkinter.CTkFont('Pretendard', 13)

        def show_option(self):
            if self.var.get() == 'timer':
                self.timer_label.grid(row=4, column=0, pady=5)
                self.timer_entry.grid(row=4, column=1, pady=5)
                self.windows_shutdown_check.grid(row=5, column=0, columnspan=3, sticky="n", pady=5)
                self.count_label.grid_forget()
                self.count_entry.grid_forget()
            elif self.var.get() == 'count':
                self.count_label.grid(row=4, column=0, pady=5)
                self.count_entry.grid(row=4, column=1, pady=5)
                self.windows_shutdown_check.grid(row=5, column=0, columnspan=3, sticky="n", pady=5)
                self.timer_label.grid_forget()
                self.timer_entry.grid_forget()
            else:
                self.timer_label.grid_forget()
                self.timer_entry.grid_forget()
                self.count_label.grid_forget()
                self.count_entry.grid_forget()
                self.windows_shutdown_check.grid_forget()

        def on_close(self):
            self.withdraw()

        self.upper_frame = customtkinter.CTkFrame(self, fg_color="#242424")
        self.upper_frame.grid(row=0, column=0, columnspan=3, sticky="n")

        self.label_time = customtkinter.CTkLabel(self.upper_frame, text="이미지 생성당 지연시간 추가 (초)", font = my_font)
        self.label_time.grid(row=0, column=0, columnspan=3, sticky="n")

        self.delay_entry = customtkinter.CTkEntry(self.upper_frame, font = my_font)
        self.delay_entry.grid(row=1, column=0,columnspan=3,  sticky="n")

        self.repeat_frame = customtkinter.CTkFrame(self, fg_color="#242424")
        self.repeat_frame.grid(row=2, column=0, columnspan=3, sticky="n")

        self.label_repeat = customtkinter.CTkLabel(self.repeat_frame, text="동일 이미지를 다음 횟수만큼 반복하여 생성 (Default=1)", font = my_font)
        self.label_repeat.grid(row=0, column=0, columnspan=3, sticky="n")

        self.repeat_entry = customtkinter.CTkEntry(self.repeat_frame, font = my_font, width=70)
        self.repeat_entry.grid(row=1, column=0,columnspan=3,  sticky="n")

        self.label_wildcard_repeat = customtkinter.CTkLabel(self.repeat_frame, text="와일드카드 *사전개봉*시 다음 횟수만큼 반복하여 생성 (Default=1)", font = my_font)
        self.label_wildcard_repeat.grid(row=2, column=0, columnspan=3, sticky="n")

        self.wildcard_repeat_entry = customtkinter.CTkEntry(self.repeat_frame, font = my_font, width=70)
        self.wildcard_repeat_entry.grid(row=3, column=0,columnspan=3,  sticky="n")

        self.label = customtkinter.CTkLabel(self.repeat_frame, text="자동화 종료 조건", font = my_font)
        self.label.grid(row=4, column=0, columnspan=3, sticky="n")

        self.radio1 = customtkinter.CTkRadioButton(self, text="무제한", variable=self.var, value="unlimited", command=lambda: show_option(self), font = my_font)
        self.radio1.grid(row=3, column=0)
        self.radio2 = customtkinter.CTkRadioButton(self, text="타이머", variable=self.var, value="timer", command=lambda: show_option(self), font = my_font)
        self.radio2.grid(row=3, column=1)
        self.radio3 = customtkinter.CTkRadioButton(self, text="생성카운트", variable=self.var, value="count", command=lambda: show_option(self), font = my_font)
        self.radio3.grid(row=3, column=2)

        self.timer_label = customtkinter.CTkLabel(self, text="자동화 동작 시간(분) : ", font = my_font)
        self.timer_entry = customtkinter.CTkEntry(self)

        self.count_label = customtkinter.CTkLabel(self, text="자동 생성 횟수 : ", font = my_font)
        self.count_entry = customtkinter.CTkEntry(self)

        self.windows_shutdown = customtkinter.IntVar()
        self.windows_shutdown_check = customtkinter.CTkCheckBox(self, text="자동화가 자동으로 끝나면 윈도우를 종료합니다.", variable=self.windows_shutdown, font = my_font)

        self.apply_button = customtkinter.CTkButton(self, text="적용", font = my_font, command=lambda: on_apply(self))
        self.stop_button = customtkinter.CTkButton(self, text="중단", font = my_font, command=lambda: on_stop(self))
        self.close_button = customtkinter.CTkButton(self, text="닫기", font = my_font, command=lambda: on_close(self))

        self.apply_button.grid(row=6, column=0, pady=5)
        self.stop_button.grid(row=6, column=1, pady=5)
        self.close_button.grid(row=6, column=2, pady=5)

        def on_apply(self):
            selected_option = self.var.get()
            if self.delay_entry.get():
                try:
                    app.delay_offset = round(float(self.delay_entry.get()), 1)
                    if app.delay_offset > 60:
                        app.delay_offset = 60
                    elif app.delay_offset < -8:
                        app.delay_offset = -8
                    app.automation_setting_button.configure(text=f"자동화 설정 ({str(round(app.delay_offset, 1))}초)")
                except ValueError as e:
                    print(e)
                    app.delay_offset = 0
            else:
                app.delay_offset = 0
                app.automation_setting_button.configure(text=f"자동화 설정")
            if self.repeat_entry.get():
                try:
                    app.image_generation_repeat = int(self.repeat_entry.get())
                except:
                    self.repeat_entry.delete(0, "end")
                    app.image_generation_repeat = 1
            if self.wildcard_repeat_entry.get():
                try:
                    app.wildcard_preopen_repeat = int(self.wildcard_repeat_entry.get())
                    app.wildcard_preopen_repeat_current = app.wildcard_preopen_repeat
                except:
                    self.wildcard_repeat_entry.delete(0, "end")
                    app.image_generation_repeat = 1
            if selected_option == "timer":
                app.auto_time_left_flag = True
                app.auto_count_left_flag = False
                try:
                    # 엔트리에서 입력된 시간을 분 단위에서 초 단위로 변환
                    app.auto_time_left = int(self.timer_entry.get()) * 60
                except ValueError:
                    # 잘못된 입력 처리
                    print("Invalid input for timer. Please enter a number.")
                    return
            elif selected_option == "count":
                app.auto_count_left_flag = True
                app.auto_time_left_flag = False
                try:
                    app.auto_count_left = int(self.count_entry.get())
                except ValueError:
                    # 잘못된 입력 처리
                    print("Invalid input for count. Please enter a number.")
                    return
            else:
                self.auto_time_left_flag = False
                self.auto_count_left_flag = False
            on_stop(self)  # 이전 스레드 종료
            start_auto_thread()  # 새 스레드 시작
            
        def show_shutdown_warning():
            def cancel_shutdown():
                os.system("shutdown -a")
                warning_window.destroy()

            def on_warning_window_close():
                if warning_window.after_id is not None:
                    app.after_cancel(warning_window.after_id)
                warning_window.destroy()

            app.deiconify()
            app.lift() 

            warning_window = customtkinter.CTkToplevel(app)
            warning_window.title("Shutdown Warning")
            warning_window.attributes("-topmost", True)
            warning_window.protocol("WM_DELETE_WINDOW", on_warning_window_close)
            warning_window.after_id = None

            label = customtkinter.CTkLabel(warning_window, text="     프로그램 및 컴퓨터가 90/120초 후에 종료됩니다.     ", font=my_font)
            label.pack(pady=15)

            cancel_button = customtkinter.CTkButton(warning_window, text="취소", command=cancel_shutdown, font=my_font)
            cancel_button.pack(pady=5)

            # 90초 후에 프로그램 종료
            warning_window.after_id = warning_window.after(90000, app.exit_program)

        def shutdown_computer():
            os.system("shutdown /s /t 120")
            show_shutdown_warning()

        def auto_time_thread(stop_event):
            def seconds_to_hms(seconds):
                h = seconds // 3600
                m = (seconds % 3600) // 60
                s = seconds % 60
                if h != 0:
                    if (s%2) == 0:
                        return f"{h:02d}:{m:02d}"
                    else: 
                        return f"{h:02d} {m:02d}"
                else:
                    if (s%2) == 0:
                        return f"{m:02d}:{s:02d}"
                    else: 
                        return f"{m:02d} {s:02d}"
            
            def update_label_for_time_finished():
                app.automation_button.configure(text="자동화 (종료됨)")
                app.auto_time_left_flag = False
                app.automation_button.deselect()
                if self.windows_shutdown.get() == 1:
                    shutdown_computer()
                else:
                    notification.notify(
                    title = '자동생성이 완료되었어요.',
                    message = '결과를 확인해 보세요.',
                    app_name = "NAIA",
                    app_icon = app.basedir+'/icoico.ico',
                    timeout = 5,  # seconds
                )

            while not stop_event.is_set() and app.auto_time_left > 0:
                time.sleep(1)
                app.auto_time_left -= 1
                remaining_time = seconds_to_hms(app.auto_time_left)
                app.after(0, lambda: app.automation_button.configure(text=f"자동화 ({remaining_time})"))

            if app.auto_time_left <= 0:
                app.after(0, update_label_for_time_finished)

            if app.stop_event.is_set():
                app.after(0, lambda: app.automation_button.configure(text="자동화"))
                app.auto_time_left_flag = False

        def auto_count_thread(stop_event):
            def update_label_for_count_finished():
                app.automation_button.configure(text="자동화 (종료됨)")
                app.auto_time_left_flag = False
                app.automation_button.deselect()
                if self.windows_shutdown.get() == 1:
                    shutdown_computer()
                else:
                    notification.notify(
                    title = '자동생성이 완료되었어요.',
                    message = '결과를 확인해 보세요.',
                    app_name = "NAIA",
                    app_icon = app.basedir+'/icoico.ico',
                    timeout = 5,  # seconds
                )

            while not stop_event.is_set():
                time.sleep(1)  # 주기적으로 확인
                app.after(0, lambda: app.automation_button.configure(text=f"자동화 ({app.auto_count_left})"))
                if app.auto_count_left <= 0:
                    app.after(0, update_label_for_count_finished)
                    break  # 루프 탈출
            if app.stop_event.is_set():
                app.after(0, lambda: app.automation_button.configure(text="자동화"))
                app.auto_count_left_flag = False

        # 스레드 시작 및 종료 함수
        def start_auto_thread():
            app.stop_event = threading.Event()
            app.auto_thread = None

            if app.auto_time_left_flag:
                app.auto_thread = threading.Thread(target=auto_time_thread, args=(app.stop_event,), daemon=True)
            elif app.auto_count_left_flag:
                app.auto_thread = threading.Thread(target=auto_count_thread, args=(app.stop_event,), daemon=True)

            if app.auto_thread is not None:
                app.auto_thread.start()

        def stop_auto_thread(self):
            if app.stop_event is not None:
                app.stop_event.set()

        def on_stop(self):
            stop_auto_thread(self)

        self.protocol("WM_DELETE_WINDOW", lambda: on_close(self))

class Character_search(customtkinter.CTkToplevel):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title("캐릭터 검색 및 사전")
        #self.resizable(width=False, height=False)
        self.app = app
        self.attributes('-topmost', True)
        my_font = customtkinter.CTkFont('Pretendard', 13)

        character_book_dict = {}
        try:
            if os.path.exists('Character_book.json'):
                with open('Character_book.json', 'r', encoding='utf-8') as f:
                    try:
                        character_book_dict = json.load(f)
                        self.dictionary_parity = True
                    except:
                        character_book_dict = {}
        except FileNotFoundError:
            character_book_dict = {}

        def lost_top_most(self):
            self.attributes('-topmost', False)

        def on_close(self):
                self.withdraw()

        frame_head = customtkinter.CTkFrame(self, width=750, height=40)
        frame_head.grid(row =0, column =0, columnspan=5, padx=5, pady=5, sticky="nsew")
        frame_left = customtkinter.CTkFrame(self, width=300, height=520)
        frame_left.grid(row =1, column =0, padx=5, pady=5, sticky="nsew")
        frame_right = customtkinter.CTkFrame(self, width=450, height=520)
        frame_right.grid(row =1, column =2, padx=5, pady=5, sticky="nsew")

        search_word = customtkinter.StringVar()
        search_entry = customtkinter.CTkEntry(frame_head, font=my_font, textvariable=search_word)

        character_prompt_frame = customtkinter.CTkFrame(frame_right)
        character_prompt_frame.grid(row=0, column=0, padx=10, pady=5, sticky="nsew")
        prompt_label = customtkinter.CTkLabel(character_prompt_frame, text="캐릭터 프롬프트: ", font=my_font)
        prompt_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")

        def generate_character(self):
            prompt = character_prompt.get("0.0", "end-1c")
            prompt_cos = cosplay_prompt.get("0.0", "end-1c")
            concat_entry = generate_entry.get() + ", {{face focus, upper body}}"
            keywords = [item.strip() for item in prompt.split(',')]
            if len(keywords) >= 2:
                keyword = keywords[1]
                keywords[1] = '{{'+keyword+'}}'
                keywords.insert(2, concat_entry)
            else:
                keyword = keywords[0]
                keywords[0] = "{{" + keywords[0] + "}}"
            request_prompt = ', '.join(keywords)
            instant_image_generation_book(self, request_prompt, keyword, prompt, prompt_cos)

        character_prompt_generation = customtkinter.CTkButton(character_prompt_frame, font=my_font, text="즉시생성", fg_color="grey", hover_color="grey10", command=lambda: generate_character(self))
        character_prompt_generation.grid(row=0, column=1, padx=5, pady=5, sticky="w")
        continuous_generation = customtkinter.IntVar()
        continuous_generation_button = customtkinter.CTkCheckBox(character_prompt_frame, font=my_font, text="빈 도감 자동채우기", variable=continuous_generation)
        continuous_generation_button.grid(row=0, column=2, padx=5, pady=5, sticky="w")

        character_prompt = customtkinter.CTkTextbox(frame_right, font=customtkinter.CTkFont('Pretendard', 15), width=450)
        character_prompt.grid(row=1, column=0, padx=10, pady=5, sticky="w")

        cosplay_prompt_frame = customtkinter.CTkFrame(frame_right)
        cosplay_prompt_frame.grid(row=2, column=0, padx=10, pady=5, sticky="nsew")
        prompt_label = customtkinter.CTkLabel(cosplay_prompt_frame, text="캐릭터(Cosplay)):", font=my_font)
        prompt_label.grid(row=0, column=0, padx=10, pady=5, sticky="w")
        #cosplay_prompt_generation = customtkinter.CTkButton(cosplay_prompt_frame, font=my_font, text="즉시생성", fg_color="grey", hover_color="grey10", command=lambda: app.instant_image_generation_book())
        #cosplay_prompt_generation.grid(row=0, column=1, padx=5, pady=5, sticky="w")
        cosplay_prompt = customtkinter.CTkTextbox(frame_right, font=customtkinter.CTkFont('Pretendard', 15), width=450)
        cosplay_prompt.grid(row=3, column=0, padx=10, pady=5, sticky="w")
        image_label = customtkinter.CTkLabel(frame_right, text="")
        image_label.grid(row=0, rowspan=4, column=1, padx=10, pady=5, sticky="w")
        white_image = Image.new('RGB', (384, 512), 'white')
        white_photo = customtkinter.CTkImage(white_image, size=(384,512))
        image_label.configure(image=white_photo)
        generate_label = customtkinter.CTkLabel(self, text="Portrait 생성시 적용할 선행 고정 프롬프트 : ", font=my_font)
        generate_label.grid(row=2, column=0, padx=5, pady=5, sticky="w")
        generate_entry = customtkinter.CTkEntry(self, font=my_font)
        generate_entry.grid(row=2, column=1, columnspan=2, padx=5, pady=5, sticky="nsew")

        if character_book_dict != None and 'user_fix_prompt' in character_book_dict and character_book_dict['user_fix_prompt'] != None:
            generate_entry.delete(0, "end")
            generate_entry.insert(0, character_book_dict['user_fix_prompt'])

        def instant_image_generation_book(self, request_prompt, character_name, p1, p2):
            if app.running_flag == False and app.automation_button.get() == 0:
                character_prompt_generation.configure(state="disabled")
                #cosplay_prompt_generation.configure(state="disabled")
                app.running_flag == True
                try:
                    scale_pre = float(scale_pre)
                except:
                    scale_pre = 5.0
                    app.cfg_scale_var.set("5.0")
                rescale_pre = app.prompt_guidance_rescale_entry.get()
                try:
                    rescale_pre = float(rescale_pre)
                except:
                    rescale_pre = 0
                    app.prompt_guidance_rescale_var.set("0")
                uncond_pre = app.uncond_strength_entry.get()
                try:
                    uncond_pre = float(uncond_pre)
                    uncond_pre = round(uncond_pre / 0.05) * 0.05
                    if (uncond_pre > 1.5):
                        uncond_pre = 1.5
                        app.uncond_strength_entry.delete(0, "end")
                        app.uncond_strength_entry.insert(0, "1.5")
                except:
                    uncond_pre = 1.0
                    app.uncond_strength_entry.delete(0, "end")
                    app.uncond_strength_entry.insert(0, "1.0")
                gen_request = {
                        "width":896,
                        "height":1152,
                        "quality_toggle":app.auto_quality_toggle.get(),
                        "seed":random.randint(0,9999999999),
                        "sampler":app.sampler_button.get(),
                        "scale":scale_pre,
                        "sema":app.sema_button.get(),
                        "sema_dyn": app.dyn_button.get(),
                        "cfg_rescale": rescale_pre,
                        "uncond_scale":uncond_pre,
                        "prompt": request_prompt,
                        "negative":app.negative_prompt_input.get("0.0", "end-1c"),
                        "user_screen_size": app.get_max_size(),
                        "start_time": app.start_time,
                        "access_token": app.access_token,
                        "save_folder": app.output_file_path,
                        "png_rule": app.name_var.get(),
                        "type": "normal"
                    }
                def run_generation():
                        if gen_request["png_rule"] == "count":
                            app.generation_count += 1
                            gen_request["count"] =app.generation_count
                        app.state_label.configure(text ="state : 도감 이미지 요청됨 ", text_color = "#FFFF97")
                        result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request)
                        app.running_flag == False
                        character_prompt_generation.configure(state="normal")
                        #cosplay_prompt_generation.configure(state="normal")
                        app.state_label.configure(text ="state : 도감 이미지 요청 반환됨", text_color = "#DCE4EE")
                        if info:
                            temp = info.get('Comment', '')
                            temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','')
                        else:
                            temp = result_prompt
                        app.image_label_report.configure(state="normal")
                        app.image_label_report.delete("0.0", "end")
                        app.image_label_report.configure(text_color="#DCE4EE")
                        app.image_label_report.insert("0.0", temp)
                        app.image_label_report.configure(state="disabled")
                        if result_image:
                            image_bytes = io.BytesIO()
                            book_image = Image.open(filename).resize((384,512))
                            book_image = book_image.convert('RGB')
                            book_image.save(image_bytes, format='JPEG', quality=90)
                            image_bytes = base64.b64encode(image_bytes.getvalue()).decode('utf-8')
                            character_book_dict[character_name] = [0, p1, p2, image_bytes]
                            character_book_dict['user_fix_prompt'] = generate_entry.get()
                            with open('Character_book.json', 'w', encoding='utf-8') as f:
                                json.dump(character_book_dict, f, ensure_ascii=False, indent=4)
                            image_stream = io.BytesIO(base64.b64decode(image_bytes))
                            reloaded_image = Image.open(image_stream)
                            image_label.configure(image=customtkinter.CTkImage(reloaded_image, size=(384,512)))
                            if app.state() != 'zoomed':
                                instant_result_image = customtkinter.CTkImage(result_image, size=(620,620))
                            else:
                                current_image = Image.open(filename)
                                original_width, original_height = current_image.size
                                max_size = app.winfo_screenheight()-100
                                if original_width > max_size or original_height > max_size:
                                    new_image = Image.new("RGB", (max_size, max_size), "black")
                                    new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                                    instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                                else:
                                    instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                            app.image_label.configure(image=instant_result_image)
                            app.ext_set_image_to_queue(result_image, result_prompt, str(result_seed), filename)
                            if continuous_generation.get() == 1:
                                listbox.focus()
                                app.after(500, move_selection_down(self))
                        else:
                            if continuous_generation.get() == 1:
                                app.after(500, generate_character(self))
                generation_thread = threading.Thread(target=run_generation, daemon=True)
                generation_thread.start()

        def move_selection_down(self):
            selected_indices = listbox.curselection()
            if selected_indices:
                current_index = selected_indices[0]
                next_index = current_index + 1

                # 리스트의 끝을 넘어가지 않도록 확인
                if next_index < listbox.size():
                    listbox.selection_clear(current_index)
                    listbox.selection_set(next_index)
                    listbox.see(next_index)
                else:
                    continuous_generation_button.deselect()
                keyword_with_count = listbox.get(next_index).strip()
                keyword = keyword_with_count.split(' - ')[0].strip()
                if keyword not in character_book_dict and continuous_generation.get() == 1:
                    on_search()
                    app.after(500, generate_character(self))
                elif continuous_generation.get() == 1:
                    app.after(500, move_selection_down(self))

        def on_key_release(event):
            search_keyword = search_entry.get()
            update_listbox(search_keyword)

        def on_search():
            # 검색 버튼 이벤트 처리 함수
            selected_indices = listbox.curselection()
            if not selected_indices:  # If there is no selection
                print("No selection made.")
                return
        
            # Assuming the first selected index (single selection mode)
            selected_index = selected_indices[0]
            # Get the keyword from the listbox, split by '-', and trim whitespace
            keyword_with_count = listbox.get(selected_index).strip()
            keyword = keyword_with_count.split(' - ')[0].strip()
        
            # Call the analyze function with the selected keyword
            print(f"Analyzing keyword: {keyword}")
            character, cosplay = analyze_keywords_in_data('csdataset.parquet', keyword)
            character_prompt.delete("0.0", "end")
            character_prompt.insert("0.0", character)
            cosplay_prompt.delete("0.0", "end")
            cosplay_prompt.insert("0.0", cosplay)

        def analyze_keywords_in_data(parquet_file, keyword):
            # Parquet 파일 읽기
            df = pd.read_parquet(parquet_file)
        
            bag_of_tags = ['penis', 'character name', 'upper body','holding','full body', 'artist name', 'male focus', 'open mouth', 'mature male', 'muscular', 'muscular male', 'closed mouth','closed eyes', 'white background', 'solo', 'breasts', 'simple background', 'smile', 'looking at viewer', 'flat chest', 'small breasts', 'medium breasts', 'large breasts', 'huge breasts','aqua eyes', 'black eyes', 'blue eyes', 'brown eyes', 'green eyes', 'grey eyes', 'orange eyes', 'purple eyes', 'pink eyes', 'red eyes', 'white eyes', 'yellow eyes', 'amber eyes', 'heterochromia', 'multicolored eyes', 'aqua pupils', 'blue pupils', 'brown pupils', 'green pupils', 'grey pupils', 'orange pupils', 'pink pupils', 'purple pupils', 'red pupils', 'white pupils', 'yellow pupils', 'pointy ears', 'long pointy ears', 'aqua hair', 'black hair', 'blonde hair', 'blue hair', 'light blue hair', 'dark blue hair', 'brown hair', 'light brown hair', 'green hair', 'dark green hair', 'light green hair', 'grey hair', 'orange hair', 'pink hair', 'purple hair', 'light purple hair', 'red hair', 'white hair', 'multicolored hair', 'colored inner hair', 'colored tips', 'roots (hair)', 'gradient hair', 'print hair', 'rainbow hair', 'split-color hair', 'spotted hair', 'streaked hair', 'two-tone hair', 'very short hair', 'short hair', 'medium hair', 'long hair', 'very long hair', 'absurdly long hair', 'big hair', 'bald', 'bald girl', 'bob cut', 'inverted bob', 'bowl cut', 'buzz cut', 'chonmage', 'crew cut', 'flattop', 'okappa', 'pixie cut', 'undercut', 'flipped hair', 'wolf cut', 'cornrows', 'dreadlocks', 'hime cut', 'mullet', 'bow-shaped hair', 'braid', 'braided bangs', 'front braid', 'side braid', 'french braid', 'crown braid', 'single braid', 'multiple braids', 'twin braids', 'low twin braids', 'tri braids', 'quad braids', 'flower-shaped hair', 'hair bun', 'braided bun', 'single hair bun', 'double bun', 'cone hair bun', 'doughnut hair bun', 'heart hair bun', 'triple bun', 'cone hair bun', 'hair rings', 'single hair ring', 'half updo', 'one side up', 'two side up', 'low-braided long hair', 'low-tied long hair', 'mizura', 'multi-tied hair', 'nihongami', 'ponytail', 'folded ponytail', 'front ponytail', 'high ponytail', 'short ponytail', 'side ponytail', 'split ponytail', 'star-shaped hair', 'topknot', 'twintails', 'low twintails', 'short twintails', 'uneven twintails', 'tri tails', 'quad tails', 'quin tails', 'twisted hair', 'afro', 'huge afro', 'beehive hairdo', 'crested hair', 'pompadour', 'quiff', 'shouten pegasus mix mori', 'curly hair', 'drill hair', 'twin drills', 'tri drills', 'hair flaps', 'messy hair', 'pointy hair', 'ringlets', 'spiked hair', 'straight hair', 'wavy hair', 'bangs', 'arched bangs', 'asymmetrical bangs', 'bangs pinned back', 'blunt bangs', 'crossed bangs', 'diagonal bangs', 'dyed bangs', 'fanged bangs', 'hair over eyes', 'hair over one eye', 'long bangs', 'parted bangs', 'curtained hair', 'ribbon bangs', 'short bangs', 'swept bangs', 'hair between eyes', 'hair intakes', 'single hair intake', 'sidelocks', 'asymmetrical sidelocks', 'drill sidelocks', 'low-tied sidelocks', 'sidelocks tied back', 'single sidelock', 'ahoge', 'heart ahoge', 'huge ahoge', 'antenna hair', 'heart antenna hair', 'comb over', 'hair pulled back', 'hair slicked back', 'mohawk', 'oseledets', 'lone nape hair', 'hair bikini', 'hair censor', 'hair in own mouth', 'hair over breasts', 'hair over one breast', 'hair over crotch', 'hair over shoulder', 'hair scarf', 'alternate hairstyle', 'hair down', 'hair up', 'asymmetrical hair', 'sidecut', 'blunt ends', 'dark skin', 'dark-skinned female', 'pale skin', 'sun tatoo', 'black skin', 'blue skin', 'green skin', 'grey skin', 'orange skin', 'pink skin', 'purple skin', 'red skin', 'white skin', 'yellow skin', 'colored skin', 'multiple tails', 'demon tail', 'dragon tail', 'ghost tail', 'pikachu tail', 'snake head tail', 'fiery tail', 'bear tail', 'rabbit tail', 'cat tail', 'cow tail', 'deer tail', 'dog tail', 'ermine tail', 'fox tail', 'horse tail', 'leopard tail', 'lion tail', 'monkey tail', 'mouse tail', 'pig tail', 'sheep tail', 'squirrel tail', 'tiger tail', 'wolf tail', 'crocodilian tail', 'fish tail', 'scorpion tail', 'snake tail', 'tadpole tail']
            mini_bag_of_tags = ['penis', 'character name', 'upper body', 'full body',  'alternate costume','artist name', 'male focus', 'open mouth', 'mature male', 'muscular', 'muscular male', 'closed mouth','closed eyes','white background', 'solo', 'breasts', 'simple background', 'smile', 'looking at viewer']
            # 'character' 열에서 keyword에 해당하는 행만 필터링
            filtered_df = df[df['character'] == keyword]
            filtered_df = filtered_df[~filtered_df['character'].str.contains(',', na=False)]
            if filtered_df.empty:
                filtered_df = df[df['character'].str.contains(keyword, na=False, regex=False)]
            filtered_df = filtered_df[~(filtered_df['rating'] == 'e')]
            #print(len(filtered_df))
            # keyword:count 형태로 데이터 집계할 딕셔너리 생성
            keyword_count_dict = {}
        
            # 각 행의 'general' 열 처리
            for general in filtered_df['general']:
                # 문자열 분할
                tags = [tag.strip() for tag in general.split(',')]
                
                # 딕셔너리에 각 태그의 count 추가
                for tag in tags:
                    keyword_count_dict[tag] = keyword_count_dict.get(tag, 0) + 1
        
            # 특정 키워드 제외
            exclude_keywords = bag_of_tags
            keyword_count_dict1 = keyword_count_dict.copy()
            keyword_count_dict1 = {k: v for k, v in keyword_count_dict1.items() if k not in mini_bag_of_tags}
            keyword_count_dict = {k: v for k, v in keyword_count_dict.items() if k not in exclude_keywords}
        
            # 가장 높은 count 값 찾기
            highest_count = max(keyword_count_dict.values()) if keyword_count_dict else 0
            highest_count1 = max(keyword_count_dict1.values()) if keyword_count_dict1 else 0
        
            if(len(filtered_df)) < 10:
                weight = 0.6
            elif(len(filtered_df)) < 30:
                weight = 0.5
            elif(len(filtered_df)) < 80:
                weight = 0.45
            elif(len(filtered_df)) < 160:
                weight = 0.35
            elif(len(filtered_df)) < 280:
                weight = 0.3
            else:
                weight = 0.2
            
            result_list = []
            result_list1 = []
            # count가 highest_count*0.4 이상인 키워드 출력
            for k, v in keyword_count_dict.items():
                if '|' in k: continue
                if v >= highest_count * weight:
                    result_list.append(k)
        
            for k, v in keyword_count_dict1.items():
                if '|' in k: continue
                if v >= highest_count1 * weight:
                    result_list1.append(k)
        
            result_list1.insert(1, keyword)
            result_list.insert(1, "alternative costume, ["+keyword+" (cosplay)]")
            return ", ".join(result_list1),", ".join(result_list)

        def update_listbox(search_keyword):
            # Clear the listbox
            if listbox.size() > 0:
                listbox.delete(0, "end")

            # List to hold all matching keywords and counts
            all_matching_keywords = []

            # Set to track added keywords to avoid duplicates
            added_keywords = set()

            # Check if the search keyword is not empty and has at least 3 characters
            if search_keyword and len(search_keyword) >= 3:
                # Search in copyright_dict first
                for key, keywords in copyright_dict_0103.copyright_dict.items():
                    if search_keyword.lower() in key.lower():
                        for keyword in keywords:
                            count = cd.character_dictionary.get(keyword, 0)
                            if count > 50 and keyword not in added_keywords:
                                all_matching_keywords.append((keyword, count))
                                added_keywords.add(keyword)

                # Then search in character_dictionary
                matching_keywords = [
                    (k, v) for k, v in cd.character_dictionary.items()
                    if search_keyword.lower() in k.lower() and v > 50 and k not in added_keywords
                ]
                all_matching_keywords.extend(matching_keywords)

            else:
                # Sort all keywords by count in descending order
                all_matching_keywords = [
                    (k, v) for k, v in cd.character_dictionary.items() if v > 50 and k not in added_keywords
                ]

            # Now sort all matching keywords by count in descending order and insert into listbox
            all_matching_keywords.sort(key=lambda item: item[1], reverse=True)
            for keyword, count in all_matching_keywords:
                listbox.insert("end", f"{keyword} - {count}")

        search_entry.grid(row =0, column =0, padx=5, pady=5, sticky="nsew")
        search_entry.bind("<KeyRelease>", on_key_release) 
        search_label = customtkinter.CTkLabel(frame_head, text="◀ 검색 대상 copyright/character 입력 (English) | 성능 이슈로 Danbooru 50장 이상만 표시", font=my_font)
        search_label.grid(row =0, column =1, padx=5, pady=5, sticky="w")
        self.after(2500, lambda: self.attributes('-topmost', False))

        def show_image(event):
            highlight_tags = ["aqua","black","blonde","blue","brown","cyan","green","grey","orange","pink","purple","red","violet","white","yellow","mouth", "eyes", " cap", " ears", " girl", " ornament", " hat", "beret", " ear "]

            def insert_with_color(cs_text_input, current_lookup):
                words = [word.strip() for word in current_lookup.split(',')]
                for index, word in enumerate(words):
                    highlight = False
                    start_index = cs_text_input.index("end-1c")
                    if index == len(words) - 1:  # 마지막 원소인 경우
                        cs_text_input.insert("end", word)
                    else:
                        cs_text_input.insert("end", word + ", ")
                    end_index = cs_text_input.index("end-1c")

                    for tag in highlight_tags:
                        if tag in word:
                            highlight = True
                    if word == "hat": highlight = True
                    # 조건 확인
                    if word == keyword or word in tagbag.bag_of_tags[5:] or 'tail' in word or 'pupil' in word:
                        cs_text_input.tag_add(word, start_index, end_index)
                        cs_text_input.tag_config(word, foreground="#FFFF97")
                    elif highlight:
                        cs_text_input.tag_add(word, start_index, end_index)
                        cs_text_input.tag_config(word, foreground="#AED395")
            selected_indices = listbox.curselection()
            selected_index = selected_indices[0]
            keyword_with_count = listbox.get(selected_index).strip()
            keyword = keyword_with_count.split(' - ')[0].strip()
            if keyword in character_book_dict:
                try:
                    image_stream = io.BytesIO(base64.b64decode(character_book_dict[keyword][3]))
                    reloaded_image = Image.open(image_stream)
                    image_label.configure(image=customtkinter.CTkImage(reloaded_image, size=(384,512)))
                    character_prompt.delete("0.0", "end")
                    insert_with_color(character_prompt, character_book_dict[keyword][1])
                    cosplay_prompt.delete("0.0", "end")
                    insert_with_color(cosplay_prompt, character_book_dict[keyword][2])
                except:
                    return
            else:
                if character_prompt.get("0.0","end") != None:
                    character_prompt.delete("0.0", "end")
                if cosplay_prompt.get("0.0","end") != None:
                    cosplay_prompt.delete("0.0", "end")
                image_label.configure(image=white_photo)

        listbox = tk.Listbox(frame_left, width=32, height=30, font = font.Font(family='Pretendard', size=13), bg='#2B2B2B', fg='#F8F8F8', borderwidth=2, highlightbackground='lightgrey')
        listbox.bind('<<ListboxSelect>>', show_image)
        listbox.grid(row = 0, column=0, padx=5, pady=5, sticky="nsew")

        search_button = customtkinter.CTkButton(self, font=my_font, text="조회", fg_color="grey", hover_color="grey10", command=on_search)
        search_button.grid(row = 1, column=1, padx=5, pady=150, sticky="w")

        all_keywords = sorted(
                    ((k, v) for k, v in cd.character_dictionary.items() if v > 50),
                    key=lambda item: item[1],
                    reverse=True
                )
        for keyword, count in all_keywords:
            listbox.insert("end", f"{keyword} - {count}")
        
        self.protocol("WM_DELETE_WINDOW", lambda: on_close(self))

        collection_button = customtkinter.CTkButton(frame_head, text="Copyright 도감", font=my_font, fg_color="grey", hover_color="grey10", command=lambda: open_collection(self))
        collection_button.grid(row =0, column =2, padx=50, pady=5, sticky="e")

        #add_custom_character_button = customtkinter.CTkButton(frame_head, text="Copyright 도감", font=my_font, fg_color="grey", hover_color="grey10", command=lambda: open_collection(self))
        #add_custom_character_button.grid(row =0, column =3, padx=50, pady=5, sticky="e")

        def open_collection(self):
            self.attributes('-topmost', False)
            collection_window = customtkinter.CTkToplevel()
            collection_window.title("도감")
            collection_window.attributes('-topmost', True)
            collection_window.resizable(width=False, height=False)

            _height = app.winfo_screenheight()
            print(_height)
            if _height < 1152:
                yview = 660
                ylist = 46
            else:
                yview = 700
                ylist = 50

            collection_frame_head = customtkinter.CTkFrame(collection_window, width=1220, height=40)
            collection_frame_head.grid(row =0, column =0, columnspan=5, padx=5, pady=5, sticky="nsew")

            collection_label1 = customtkinter.CTkLabel(collection_frame_head, font=my_font, text="이름을 눌러 특징을 복사합니다.")
            collection_label1.grid(row = 0, column=0, padx=5, pady=5, sticky="nsew")

            collection_frame_left = customtkinter.CTkFrame(collection_window, width=300, height=yview)
            collection_frame_left.grid(row =1, column =0, padx=5, pady=5, sticky="nsew")
            collection_frame_right = customtkinter.CTkScrollableFrame(collection_window, width=900, height=yview)
            collection_frame_right.grid(row =1, column =2, padx=5, pady=5, sticky="nsew")

            show_window = []

            def copy_character_info(key):
                text = character_book_dict[key][1].split(',')
                text_list = [keyword.strip() for keyword in text]
                charactersitics = []
                charactersitics.append("{"+key+"}")
                count = 0
                for texts in text_list: 
                    if count < 4 and texts in tagbag.bag_of_tags[5:]  and 'tail' not in texts and 'pupil' not in texts and '1girl' not in texts and '1boy' not in texts and '1other' not in texts:
                        charactersitics.append(texts)
                        count += 1
                texts = ', '.join(charactersitics)
                pyperclip.copy(texts)
                collection_label1.configure(text=f"선택하신 {texts}가 클립보드에 복사되었습니다.", text_color="#FFFF97")




            def spread_image(event, show_window):
                collection_frame_right._parent_canvas.yview_moveto(0)
                selected_indices = collection_listbox.curselection()
                selected_index = selected_indices[0]
                collection_listbox.configure(state="disabled")
                if show_window:
                    for i in show_window:
                        i.destroy()
                keyword_with_count = collection_listbox.get(selected_index).strip()
                keyword = ' '.join(keyword_with_count.split('%')[1].split()).strip()
                try:
                    key_in_book = split_dict[keyword]
                    # 나머지 코드...
                except KeyError:
                    print(f"KeyError: '{keyword}' not found in the split dictionary.")
                count = 0
                for key in key_in_book:
                    _row = count//3
                    _column = count%3
                    if key in character_book_dict:
                        f = customtkinter.CTkFrame(collection_frame_right, width = 298, height=394)
                        f.grid(row=_row, column=_column, padx=5, pady=5, sticky="nsew")
                        name = key
                        if len(key) > 45:
                            name = key[:44]
                        b = customtkinter.CTkButton(f, font=my_font,text=name, state="disabled" if len(key) > 45 else "normal", fg_color="grey10", hover_color="grey10", text_color_disabled="white", command=lambda name=name: copy_character_info(name))
                        b.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
                        image_stream = io.BytesIO(base64.b64decode(character_book_dict[key][3]))
                        reloaded_image = Image.open(image_stream)
                        i = customtkinter.CTkLabel(f, text="", image=customtkinter.CTkImage(reloaded_image, size=(288,384)))
                        i.grid(row=1, column=0, padx=5, pady=5, sticky="nsew")
                        show_window.append(f)
                        count += 1
                collection_listbox.configure(state="normal")
                collection_listbox.selection_clear(selected_index)

            collection_listbox = tk.Listbox(collection_frame_left, width=32, height=ylist, font = font.Font(family='Pretendard', size=13), bg='#2B2B2B', fg='#F8F8F8', borderwidth=2, highlightbackground='lightgrey')
            collection_listbox.bind('<<ListboxSelect>>',lambda event:  spread_image(event, show_window))
            collection_listbox.grid(row = 0, column=0, padx=5, pady=5, sticky="nsew")

            

            all_collections = sorted(
                ((k, v) for k, v in copyright_dict_0103.copyright_dict.items()),
                key=lambda item: len(item[1]),
                reverse=True
            )

            split_dict = {}
            for keyword, value in all_collections:
                key_in_book = copyright_dict_0103.copyright_dict[keyword]
                cover = sum(key in character_book_dict for key in key_in_book)
                coverage = f"{round((cover / len(key_in_book)) * 100, 1) if cover else 0}%"
                
                # key_in_book의 길이가 90을 초과하는 경우 처리
                if len(key_in_book) > 96:
                    for i in range(0, len(key_in_book), 96):
                        part_key = f"{keyword} ({i//96 + 1})"
                        split_dict[part_key] = key_in_book[i:i+96]
                        cover_part = sum(key in character_book_dict for key in split_dict[part_key])
                        coverage_part = f"{round((cover_part / len(split_dict[part_key])) * 100, 1) if cover_part else 0}%"
                        collection_listbox.insert("end", f"{coverage_part:<7s}{keyword} ({i//96 + 1})")
                else:
                    split_dict[keyword] = key_in_book
                    collection_listbox.insert("end", f"{coverage:<7s}{keyword}")


class Preset_open(customtkinter.CTkToplevel):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title("프롬프트 검색/설정 프리셋")
        self.attributes('-topmost', True)
        self.resizable(width=False, height=False)

        my_font = customtkinter.CTkFont('Pretendard', 13)

        presets ={}
        items = 0
        preset_frame_left = customtkinter.CTkFrame(self, width=250, height=520)
        preset_frame_left.grid(row =1, rowspan=10, column =0, padx=5, pady=5, sticky="nsew")
        preset_frame_right = customtkinter.CTkFrame(self, width=700, height=520)
        preset_frame_right.grid(row =1, rowspan=10, column =1, columnspan = 2, padx=5, pady=5, sticky="nsew")
        preset_insert_right_frame = customtkinter.CTkFrame(self)
        preset_insert_right_frame.grid(row =0, column =0, columnspan=2, padx=5, pady=5, sticky="nsew")
        preset_insert_button = customtkinter.CTkButton(preset_insert_right_frame, text="프리셋 추가", font=my_font, command=lambda: add_preset(self, presets))
        preset_insert_button.grid(row =0, column =0, padx=5, pady=5, sticky="nsew")
        preset_insert_name = customtkinter.CTkLabel(preset_insert_right_frame, text="프리셋 명칭 : ", font=my_font)
        preset_insert_name.grid(row =0, column =1, padx=5, pady=5, sticky="w")
        preset_insert_name_entry = customtkinter.CTkEntry(preset_insert_right_frame,width=200, font=my_font)
        preset_insert_name_entry.grid(row =0, column =2, padx=5, pady=5, sticky="w")
        preset_insert_description = customtkinter.CTkLabel(preset_insert_right_frame, text=" 설명 : ", font=my_font)
        preset_insert_description.grid(row =0, column =3, padx=5, pady=5, sticky="w")
        preset_insert_description_entry = customtkinter.CTkEntry(preset_insert_right_frame, width=420, font=my_font)
        preset_insert_description_entry.grid(row =0, column =4, padx=5, pady=5, sticky="w")
        preset_frame_bottom = customtkinter.CTkFrame(self)
        preset_frame_bottom.grid(row =11, column =0, columnspan=2, padx=5, pady=5, sticky="nsew")
        preset_label = customtkinter.CTkLabel(preset_frame_bottom, text="생성기 내 좌측 패널의 값들을 프리셋으로 저장할 수 있습니다.", font=my_font)
        preset_label.grid(row =0, column=0,sticky="n" )

        def _yield(selected_option):
            ypreset = self.presets[selected_option]
            yield_preset_description.configure(text=ypreset['description'])
            yield_preset_search.configure(text=ypreset['search'])
            yield_preset_exclude.configure(text=ypreset['exclude'])
            yield_preset_prompt.configure(state="normal")
            yield_preset_prompt.delete("0.0", "end")
            yield_preset_prompt.insert("0.0", ypreset['prompt'])
            yield_preset_prompt.configure(state="disabled")
            _text = ""
            if ypreset['explicit'] == 1:
                _text += "Explicit "
            if ypreset['nsfw'] == 1:
                _text += "NSFW "
            if ypreset['sensitive'] == 1:
                _text += "Sensitive "
            if ypreset['general'] == 1:
                _text += "General"
            yield_activated_ratings.configure(text = _text)
            yield_prefix.configure(state="normal")
            yield_prefix.delete("0.0", "end")
            yield_prefix.insert("0.0", ypreset['fix'])
            yield_prefix.configure(state="disabled")
            yield_postfix.configure(state="normal")
            yield_postfix.delete("0.0", "end")
            yield_postfix.insert("0.0", ypreset['fix_after'])
            yield_postfix.configure(state="disabled")
            yield_negative.configure(state="normal")
            yield_negative.delete("0.0", "end")
            yield_negative.insert("0.0", ypreset['negative'])
            yield_negative.configure(state="disabled")
            yield_autohide.configure(state="normal")
            yield_autohide.delete("0.0", "end")
            yield_autohide.insert("0.0", ypreset['auto_hide'])
            yield_autohide.configure(state="disabled")
            _text = ""
            if ypreset['rm_artist'] == 1:
                _text += "작가명제거 "
            if ypreset['rm_copyright'] == 1:
                _text += "작품명제거 "
            if ypreset['rm_character'] == 1:
                _text += "캐릭터특징제거"
            yield_rm.configure(text = _text)



        preset_list = CTkListbox(preset_frame_left, height=570, font=my_font, command= _yield)
        preset_list.grid(row = 0, column=0, padx=5, pady=5, sticky="nsew")

        show_preset_description = customtkinter.CTkButton(preset_frame_right, text="Description", font=my_font, width=150, fg_color="grey10", text_color_disabled="white",state="disabled")
        show_preset_description.grid(row = 0, column = 0, padx=5, pady=5, sticky="w")
        yield_preset_description = customtkinter.CTkLabel(preset_frame_right, text="", font=my_font, width=550)
        yield_preset_description.grid(row = 0, column = 1, padx=5, pady=5, sticky="w")
        
        def insert_search():
            if preset_list.get():
                app.search_label_entry.delete(0, "end")
                app.search_label_entry.insert(0, yield_preset_search.cget("text"))
        show_preset_search = customtkinter.CTkButton(preset_frame_right, text="Search Keyword", font=my_font, width=150, fg_color="grey10", hover_color="grey", command=insert_search)
        show_preset_search.grid(row = 1, column = 0, padx=5, pady=5, sticky="w")
        yield_preset_search = customtkinter.CTkLabel(preset_frame_right, text="", font=my_font, width=550)
        yield_preset_search.grid(row = 1, column = 1, padx=5, pady=5, sticky="w")
        def insert_exclude():
            if preset_list.get():
                app.exclude_label_entry.delete(0, "end")
                app.exclude_label_entry.insert(0, yield_preset_exclude.cget("text"))
        show_preset_exclude = customtkinter.CTkButton(preset_frame_right, text="Exclude Keyword", font=my_font, width=150, fg_color="grey10", hover_color="grey", command=insert_exclude)
        show_preset_exclude.grid(row = 2, column = 0, padx=5, pady=5, sticky="w")
        yield_preset_exclude = customtkinter.CTkLabel(preset_frame_right, text="", font=my_font, width=550)
        yield_preset_exclude.grid(row = 2, column = 1, padx=5, pady=5, sticky="w")
        def insert_prompt():
            if preset_list.get():
                app.text_input.delete("0.0","end")
                app.text_input.insert("0.0", yield_preset_prompt.get("0.0", "end"))
        show_preset_prompt = customtkinter.CTkButton(preset_frame_right, text="Prompt", font=my_font, width=150, height=100, fg_color="grey10", hover_color="grey", command=insert_prompt)
        show_preset_prompt.grid(row = 3, column = 0, padx=5, pady=5, sticky="w")
        yield_preset_prompt = customtkinter.CTkTextbox(preset_frame_right, font=my_font, state="disabled",width=550, height=100, fg_color='#2B2B2B')
        yield_preset_prompt.grid(row = 3, column = 1, padx=5, pady=5, sticky="w")
        def insert_ratings():
            if preset_list.get():
                app.rating_select_explicit.deselect()
                app.rating_select_nsfw.deselect()
                app.rating_select_sensitive.deselect()
                app.rating_select_general.deselect()
                _text = yield_activated_ratings.cget("text")
                if "Explicit" in _text:
                    app.rating_select_explicit.select()
                if "NSFW" in _text:
                    app.rating_select_nsfw.select()   
                if "Sensitive" in _text:
                    app.rating_select_sensitive.select()   
                if "General" in _text:
                    app.rating_select_general.select()   
        show_activated_ratings = customtkinter.CTkButton(preset_frame_right, text="Ratings", font=my_font, width=150, fg_color="grey10", hover_color="grey", command=insert_ratings)
        show_activated_ratings.grid(row = 4, column = 0, padx=5, pady=5, sticky="w")
        yield_activated_ratings = customtkinter.CTkLabel(preset_frame_right, text="", font=my_font, width=550)
        yield_activated_ratings.grid(row = 4, column = 1, padx=5, pady=5, sticky="w")

        #선행고정
        def insert_prefix():
            if preset_list.get():
                app.fixed_prompt_input.delete("0.0","end")
                app.fixed_prompt_input.insert("0.0", yield_prefix.get("0.0", "end"))
        show_prefix = customtkinter.CTkButton(preset_frame_right, text="Pre-fix", font=my_font, width=150, height=50, fg_color="grey10", hover_color="grey", command=insert_prefix)
        show_prefix.grid(row = 5, column = 0, padx=5, pady=5, sticky="w")
        yield_prefix = customtkinter.CTkTextbox(preset_frame_right, font=my_font, state="disabled",width=550, height=50, fg_color='#2B2B2B')
        yield_prefix.grid(row = 5, column = 1, padx=5, pady=5, sticky="w")
        def insert_postfix():
            if preset_list.get():
                app.fixed_prompt_after_input.delete("0.0","end")
                app.fixed_prompt_after_input.insert("0.0", yield_postfix.get("0.0", "end"))
        show_postfix = customtkinter.CTkButton(preset_frame_right, text="Post-fix", font=my_font, width=150, height=50, fg_color="grey10", hover_color="grey", command=insert_postfix)
        show_postfix.grid(row = 6, column = 0, padx=5, pady=5, sticky="w")
        yield_postfix = customtkinter.CTkTextbox(preset_frame_right, font=my_font, state="disabled",width=550, height=50, fg_color='#2B2B2B')
        yield_postfix.grid(row = 6, column = 1, padx=5, pady=5, sticky="w")
        def insert_negative():
            if preset_list.get():
                app.negative_prompt_input.delete("0.0","end")
                app.negative_prompt_input.insert("0.0", yield_negative.get("0.0", "end"))
        show_negative = customtkinter.CTkButton(preset_frame_right, text="Negative prompt", font=my_font, width=150, height=70, fg_color="grey10", hover_color="grey", command=insert_negative)
        show_negative.grid(row = 7, column = 0, padx=5, pady=5, sticky="w")
        yield_negative = customtkinter.CTkTextbox(preset_frame_right, font=my_font, state="disabled",width=550, height=70, fg_color='#2B2B2B')
        yield_negative.grid(row = 7, column = 1, padx=5, pady=5, sticky="w")
        def insert_autohide():
            if preset_list.get():
                app.auto_hide_keyword_input.delete("0.0","end")
                app.auto_hide_keyword_input.insert("0.0", yield_autohide.get("0.0", "end"))
        show_autohide = customtkinter.CTkButton(preset_frame_right, text="Hidden keyword", font=my_font, width=150, height=70, fg_color="grey10", hover_color="grey", command=insert_autohide)
        show_autohide.grid(row = 8, column = 0, padx=5, pady=5, sticky="w")
        yield_autohide = customtkinter.CTkTextbox(preset_frame_right, font=my_font, state="disabled",width=550, height=70, fg_color='#2B2B2B')
        yield_autohide.grid(row = 8, column = 1, padx=5, pady=5, sticky="w")
        

        def insert_rm():
            if preset_list.get():
                app.rm_artist_name_button.deselect()
                app.rm_copyright_name_button.deselect()
                app.rm_characteristic_button.deselect()
                _text = yield_rm.cget("text")
                if "작가명제거" in _text:
                    app.rm_artist_name_button.select()
                if "작품명제거" in _text:
                    app.rm_copyright_name_button.select()   
                if "캐릭터특징제거" in _text:
                    app.rm_characteristic_button.select()   
        show_rm = customtkinter.CTkButton(preset_frame_right, text="Options", font=my_font, width=150, fg_color="grey10", hover_color="grey", command=insert_rm)
        show_rm.grid(row = 9, column = 0, padx=5, pady=5, sticky="w")
        yield_rm = customtkinter.CTkLabel(preset_frame_right, text="", font=my_font, width=550)
        yield_rm.grid(row = 9, column = 1, padx=5, pady=5, sticky="w")
        def apply_all():
            if preset_list.get():
                insert_search()
                insert_exclude()
                insert_prompt()
                insert_ratings()
                insert_prefix()
                insert_postfix()
                insert_negative()
                insert_autohide()
                insert_rm()
        apply_all = customtkinter.CTkButton(preset_frame_right, text="일괄설정", font=my_font, width=150, command=apply_all)
        apply_all.grid(row = 10, column = 0, padx=5, pady=5, sticky="w")
        def remove_preset(self):
            presets = self.presets
            preset_name = preset_list.get()
            if preset_name in presets:
                del presets[preset_name]
                save_preset(presets)
                self.presets = load_preset()
                update_list(self, self.presets)
        remove_preset_button = customtkinter.CTkButton(preset_frame_right, text="이 프리셋을 삭제", font=my_font, fg_color="grey10", hover_color="grey", command=lambda: remove_preset(self))
        remove_preset_button.grid(row = 10, column =1, padx=5, pady=5, sticky="nsew")
        


        def add_preset(self, presets):
            preset_name = preset_insert_name_entry.get()
            if len(preset_name.strip()) < 1:
                preset_label.configure(text="프리셋 이름을 정확히 입력해주세요.", text_color="#FFFF97")
            else:
                preset = {
                    'preset_name':preset_name,
                    'description':preset_insert_description_entry.get(),
                    'search':app.search_label_entry.get(),
                    'exclude':app.exclude_label_entry.get(),
                    'prompt':app.text_input.get("0.0", "end-1c"),
                    'fix':app.fixed_prompt_input.get("0.0", "end-1c"),
                    'fix_after':app.fixed_prompt_after_input.get("0.0", "end-1c"),
                    'negative':app.negative_prompt_input.get("0.0", "end-1c"),
                    'auto_hide':app.auto_hide_keyword_input.get("0.0", "end-1c"),
                    'rm_artist':app.rm_artist_name_button.get(),
                    'rm_character':app.rm_characteristic_button.get(),
                    'rm_copyright':app.rm_copyright_name_button.get(),
                    'explicit':app.rating_select_explicit.get(),
                    'nsfw':app.rating_select_nsfw.get(),
                    'sensitive':app.rating_select_sensitive.get(),
                    'general':app.rating_select_general.get()
                }
                updated_preset = {preset_name: preset}
                if self.presets:
                    updated_preset.update(self.presets)
                else:
                    self.presets = updated_preset
                save_preset(updated_preset)
                self.presets = load_preset()
                update_list(self, self.presets)

        def update_list(self, presets):
            if preset_list.size() != 0:
                preset_list.delete(0, "END")
            if presets:
                for i, names in enumerate(presets.keys()):
                    preset_list.insert(i, names)
            self.presets = presets

        def save_preset(presets):
            with open('NAIA_preset.json', 'w', encoding='utf-8') as f:
                json.dump(presets, f, ensure_ascii=False, indent=4)

        def load_preset():
            try:
                if os.path.exists('NAIA_preset.json'):
                    with open('NAIA_preset.json', 'r', encoding='utf-8') as f:
                        return json.load(f)
            except FileNotFoundError:
                return {}

        def on_close(self):
            self.withdraw()

        presets = load_preset()
        update_list(self, presets)
        self.protocol("WM_DELETE_WINDOW", lambda: on_close(self))




class App(customtkinter.CTk, TkinterDnD.DnDWrapper):
    access_token = None
    NAI_ID = None
    data = Data(wlist, tagbag, arti_list, copyright_list_reformatted, cd, remove_result_e, remove_result_qe)

    def __init__(self):
        super().__init__()
        self.TkdndVersion = TkinterDnD._require(self)

        if getattr(sys, 'frozen', False):
            basedir = sys._MEIPASS
        else:
            basedir = os.path.dirname(__file__)
        self.basedir = basedir
        ctypes.windll.gdi32.AddFontResourceW(os.path.abspath(os.path.join(basedir,"Pretendard-Bold.otf")))
        ctypes.windll.gdi32.AddFontResourceW(os.path.abspath(os.path.join(basedir,"Pretendard-Regular.otf")))
        my_font = customtkinter.CTkFont('Pretendard', 13)
        large_font = customtkinter.CTkFont('Pretendard', 13)
        v_large_font = customtkinter.CTkFont('Pretendard', 14, weight="normal")

        #For Automation 
        self.auto_time_left = 0
        self.auto_time_left_flag = False
        self.auto_count_left = 0
        self.auto_count_left_flag = False
        self.delay_offset = 0
        self.auto_thread = None
        self.stop_event = None

        #For Generation
        self.current_prompt_rating = None

        #json file
        self.dictionary_parity = False

        self.start_time_prime = datetime.now()
        self.start_time = self.start_time_prime.strftime('%Y%m%d_%H%M')
        self.xy_plot_count = 0
        self.import_image_negative = {}

        self.title("NAIA Beta v1")
        self.grid_rowconfigure(0, weight=1)
        self.columnconfigure(2, weight=1)

        windll.shcore.SetProcessDpiAwareness(1)
        #디자인: 상용 프로그램의 스타일과 유사하도록 UI를 새롭게 개편한다.
        self.left_frame = customtkinter.CTkScrollableFrame(self, width=510, height=960)
        self.left_frame.grid(row=0, column=0, sticky="nsew")
        self.right_frame = customtkinter.CTkScrollableFrame(self, width=768,height=960)
        self.right_frame.grid(row=0, column=1, sticky="nsew")
        self.hidden_frame = customtkinter.CTkFrame(self, width=250)
        self.hidden_frame.grid(row=0, column=2, sticky="nsew")
        self.image_label_report_sub = customtkinter.CTkTextbox(self.hidden_frame,width=250, height=500, font=large_font)
        self.image_label_report_sub.grid(row=2, column=0, columnspan=2, pady=5, padx=5, sticky="nsew")
        self.image_label_report_sub.configure(state="disabled")
        self.state_label2 = customtkinter.CTkLabel(self.hidden_frame, text="state : idle", font=my_font)
        self.state_label2.grid(row=8, column=0, columnspan=2, pady=5, padx=5, sticky="n")
        self.hidden_frame.grid_forget()

        def sync_text():
            content = self.image_label_report.get("0.0", "end-1c").rstrip()
            label = self.state_label.cget("text").rstrip()
            label_sub = self.state_label2.cget("text").rstrip()
            content_sub = self.image_label_report_sub.get("0.0", "end-1c").rstrip()
            if content != content_sub:
                self.image_label_report_sub.configure(state="normal")
                self.image_label_report_sub.delete("0.0", "end")
                self.image_label_report_sub.insert("0.0", content)
                self.image_label_report_sub.configure(text_color=self.image_label_report.cget("text_color"),state="disabled")
            if label != label_sub:
                self.state_label2.configure(text=label, text_color=self.image_label_report.cget("text_color"))
            self.after(500, sync_text)

        #검색 키워드 창 관리 프레임
        self.search_frame = customtkinter.CTkFrame(self.left_frame)
        self.search_frame.grid(row=0, column=0, sticky="nsew")

        def open_AccountSetting(self):
            if self.AccountSetting is None:
                self.AccountSetting = AccountSetting(self)
            else:
                if self.AccountSetting.state() == 'withdrawn':
                    self.AccountSetting.deiconify()
                else:
                    self.AccountSetting.NAI_ID_entry.focus()

        def NAI_token_remove(self):
            app.access_token = None
            app.NAI_ID = None
            if self.running_flag or self.automation_button.get()==1 or self.image_generation_button.cget("state") == "disabled":
                self.image_label_report.configure(state="normal")
                self.image_label_report.delete("0.0", "end")
                self.image_label_report.insert("0.0", "<UserAttention> NAI 토큰의 제거가 가능한 상태가 아닙니다. 모든 작업/자동화 설정을 마치고 시도 해주세요.")
                self.image_label_report.configure(text_color="#FFFF97")
                self.image_label_report.configure(state="disabled")
            else:
                app.NAI_Account_Login.configure(state="disabled")
                app.NAI_Token_Remove.configure(state="disabled")
                app.NAI_Account_State.configure(text="NAI Logout", text_color="red")
                app.image_generation_button.configure(state="disabled")
                self.image_label_report.configure(state="normal")
                self.image_label_report.delete("0.0", "end")
                self.image_label_report.insert("0.0", "<UserAttention> NAI 토큰 제거 완료(Logout). 프로그램을 정상적으로 종료 후 재실행해야 반영됩니다.")
                self.image_label_report.configure(text_color="#FFFF97")
                self.image_label_report.configure(state="disabled")

            
        self.AccountSetting = None
        #NAI 계정 관리 프레임
        self.NAI_Account_Frame = customtkinter.CTkFrame(self.search_frame, width=440, height=50, bg_color="transparent")
        self.NAI_Account_Frame.grid(row=0, column=0, padx=8, pady=5,sticky="nsew")
        self.NAI_Account_Frame.columnconfigure(0, weight=6)
        self.NAI_Account_Frame.columnconfigure(1, weight=4)
        self.NAI_Account_Frame.columnconfigure(2, weight=4)

        #NAI 계정 로그인 상태
        self.NAI_Account_State = customtkinter.CTkLabel(self.NAI_Account_Frame, text="NAI Login : **** ", font=my_font)
        #print(self.NAI_Account_State .cget("font"))
        self.NAI_Account_State.grid(row=0, column=0, padx=20, sticky="w")
        #NAI 계정 로그인 버튼
        self.NAI_Account_Login = customtkinter.CTkButton(self.NAI_Account_Frame, text="NAI 계정연결", font=my_font, command=lambda: open_AccountSetting(self))
        self.NAI_Account_Login.grid(row=0, column=1, padx=20, sticky="ew")
        #NAI 토큰 해제 버튼
        self.NAI_Token_Remove = customtkinter.CTkButton(self.NAI_Account_Frame, text="NAI 토큰제거", state="disabled", fg_color="#848484", font=my_font, command=lambda: NAI_token_remove(self))
        self.NAI_Token_Remove.grid(row=0, column=2,padx=20, sticky="ew")

        #검색,제외 키워드 창
        self.search_label = customtkinter.CTkLabel(self.search_frame, text="검색 키워드 입력 : keyword, *keyword, {keyword1|keyword2}", font=my_font)
        self.search_label.grid(row=1, column=0, padx=8, sticky="w")
        search_hyperlink = customtkinter.CTkLabel(self.search_frame, text="가이드 열기 (arca.live)", font=customtkinter.CTkFont('Pretendard', 13),text_color="lightblue", cursor="hand2")
        search_hyperlink.grid(row=1, column=0, padx=8, sticky="e")
        search_hyperlink.bind("<Button-1>", lambda e: webbrowser.open_new("https://arca.live/b/aiart/96006690"))
        self.search_label_entry = customtkinter.CTkEntry(self.search_frame, width=490)
        self.search_label_entry.grid(row=2, column=0, padx=8, sticky="w")
        self.exclude_label = customtkinter.CTkLabel(self.search_frame, text="제외 키워드 입력 : keyword, ~keyword", font=my_font)
        self.exclude_label.grid(row=3, column=0, padx=8, sticky="w")
        self.exclude_label_entry = customtkinter.CTkEntry(self.search_frame, width=490)
        self.exclude_label_entry.grid(row=4, column=0, padx=8, sticky="w")

        #검색 수위 관리 창
        self.select_rating_frame = customtkinter.CTkFrame(self.search_frame, width=490)
        self.select_rating_frame.grid(row=6, column=0, padx=8, pady=10, sticky="nsew")
        
        #검색 수위 체크박스
        self.rating_select_var_explicit = customtkinter.IntVar(value=1)
        self.rating_select_var_nsfw = customtkinter.IntVar(value=1)
        self.rating_select_var_sensitive = customtkinter.IntVar(value=1)
        self.rating_select_var_general = customtkinter.IntVar(value=1)
        self.rating_select_explicit = customtkinter.CTkCheckBox(self.select_rating_frame, width=85, text="Explicit", variable= self.rating_select_var_explicit, font=my_font)
        self.rating_select_explicit.grid(row=0, column=0, sticky="ew")
        self.rating_select_nsfw = customtkinter.CTkCheckBox(self.select_rating_frame, width=80,text="NSFW", variable= self.rating_select_var_nsfw, font=my_font)
        self.rating_select_nsfw.grid(row=0, column=1, sticky="ew")
        self.rating_select_sensitive = customtkinter.CTkCheckBox(self.select_rating_frame,width=90, text="Sensitive", variable= self.rating_select_var_sensitive, font=my_font)
        self.rating_select_sensitive.grid(row=0, column=2, sticky="ew")
        self.rating_select_general = customtkinter.CTkCheckBox(self.select_rating_frame,width=85, text="General", variable= self.rating_select_var_general, font=my_font)
        self.rating_select_general.grid(row=0, column=3, sticky="e")

        self.cached_rows = None
        self.searching_flag = False
        self.search_thread = None
        self.freezed_cached_rows = None

        def fav_check(id):
            return id in self.fav_id_list

        def null_prompt_attention():
            self.text_input.delete("0.0", "end")
            self.text_input.insert("0.0", "현재 조건에 맞는 프롬프트가 없습니다.")

        def prompt_search():
            if not self.control_pressed:
                self.searching_flag = True
                self.search_button.configure(text="검색 (작업중)", state="disabled")
                search_thread = threading.Thread(target=perform_search, daemon=True)
                self.search_thread = search_thread
                search_thread.start()
            else:
                depth_search()

        def depth_search():
            depth_search_window = customtkinter.CTkToplevel()
            depth_search_window.title("심층검색")
            depth_search_window.attributes('-topmost', True)
            depth_search_window.resizable(width=False, height=False)
            self.freezed_cached_rows = self.cached_rows.copy()

            def perform_depth_search():
                self.search_button.configure(text="심층검색중", state="disabled")
                self.searching_flag = True
                df = self.cached_rows
                df = NAIA_search.search(df, search_label_entry.get(), exclude_label_entry.get())
                
                if df is None:
                    null_prompt_attention() # 문자열 비었다고 경고
                else:
                    self.cached_rows = df
                    df.reset_index(drop=True, inplace=True)
                    update_labels(df)
                self.searching_flag = False
                depth_search_execute.configure(text="남은 프롬프트 행에서 재검색 : "+str(len(self.cached_rows)))
                prompt_rollback.configure(text="이전 프롬프트행 복원 : "+str(len(self.freezed_cached_rows)))
                self.search_button.configure(text="검색", state="normal")
                prompt_rollback.configure(state="normal")

            def rollback():
                self.cached_rows = self.freezed_cached_rows.copy()
                update_labels(self.cached_rows)
                depth_search_execute.configure(text="남은 프롬프트 행에서 재검색 : "+str(len(self.cached_rows)))
                prompt_rollback.configure(state="disabled")

            def depth_search_close():
                self.freezed_cached_rows = None
                depth_search_window.destroy()

            search_label = customtkinter.CTkLabel(depth_search_window, text="검색 키워드 입력 : keyword, *keyword, {keyword1|keyword2}", font=my_font)
            search_label.grid(row=1, column=0, columnspan=2, padx=8, pady=5, sticky="w")
            search_label_entry = customtkinter.CTkEntry(depth_search_window, width=490)
            search_label_entry.grid(row=2, column=0, columnspan=2, padx=8, pady=5, sticky="w")
            exclude_label = customtkinter.CTkLabel(depth_search_window, text="제외 키워드 입력 : keyword, ~keyword", font=my_font)
            exclude_label.grid(row=3, column=0, columnspan=2,  padx=8, pady=5, sticky="w")
            exclude_label_entry = customtkinter.CTkEntry(depth_search_window, width=490)
            exclude_label_entry.grid(row=4, column=0, columnspan=2, padx=8, pady=5, sticky="w")
            depth_search_execute = customtkinter.CTkButton(depth_search_window, text="남은 프롬프트 행에서 재검색 : "+str(len(self.cached_rows)), font=my_font, command=perform_depth_search)
            depth_search_execute.grid(row=5, column=0, padx=5,pady=5,  sticky="n")
            prompt_rollback = customtkinter.CTkButton(depth_search_window, text="이전 프롬프트행 복원 : "+str(len(self.freezed_cached_rows)), font=my_font, fg_color="#7030A0", hover_color="#481F67", command=rollback, state="disabled")
            prompt_rollback.grid(row=5, column=1, padx=5,pady=5,  sticky="n")
            depth_search_window.protocol("WM_DELETE_WINDOW", depth_search_close)

        def perform_search():
            df = pd.read_parquet(os.path.join(basedir, "tags.parquet"), engine="pyarrow")
            df = NAIA_search.search(df, self.search_label_entry.get(), self.exclude_label_entry.get(), self.rating_select_explicit.get(), self.rating_select_nsfw.get(), self.rating_select_sensitive.get(), self.rating_select_general.get())
            
            if df is None:
                null_prompt_attention() # 문자열 비었다고 경고
            else:
                self.cached_rows = df
                df.reset_index(drop=True, inplace=True)
                update_labels(df)
            self.searching_flag = False
            self.search_button.configure(text="검색", state="normal")

        def update_labels(df):
            self.searched_prompt_label.configure(text="검색 프롬프트 행 : " + str(len(self.cached_rows)))
            self.cached_prompt_label.configure(text="남은 프롬프트 행 : " + str(len(self.cached_rows)))
            print(df.info(memory_usage="deep"))

        #검색 버튼
        self.search_button = customtkinter.CTkButton(self.select_rating_frame, text="검색", font=my_font, command=prompt_search, width=130)
        self.search_button.grid(row=0, column=4,padx=5, sticky="w")
        
        #검색 결과 관리 창
        self.searched_prompt_frame = customtkinter.CTkFrame(self.search_frame)
        self.searched_prompt_frame.grid(row=7, column=0, padx=8, pady=5, sticky="nsew")
        self.searched_prompt_frame.columnconfigure(0, weight= 1)
        self.searched_prompt_frame.columnconfigure(1, weight= 1)
        self.searched_prompt_frame.columnconfigure(2, weight= 1)
        self.searched_prompt_label = customtkinter.CTkLabel(self.searched_prompt_frame, text="검색 프롬프트 행 : 0", font=my_font)
        self.searched_prompt_label.grid(row=0, column=0, sticky="ew")
        self.cached_prompt_label = customtkinter.CTkLabel(self.searched_prompt_frame, text="남은 프롬프트 행 : 0", font=my_font)
        self.cached_prompt_label.grid(row=0, column=1, sticky="ew")
        fdf = None

        self.Preset_open = None
        def open_Preset(self):
            if self.Preset_open is None:
                self.Preset_open = Preset_open(self)
            else:
                if self.Preset_open.state() == 'withdrawn':
                    self.Preset_open.deiconify()
                else:
                    self.Preset_open.focus()

        def open_favorite():
            favorite_window = customtkinter.CTkToplevel()
            favorite_window.title("선호 프롬프트")
            favorite_window.attributes('-topmost', True)
            favorite_window.resizable(width=False, height=False)
            self.freezed_cached_rows = self.cached_rows.copy()

            global fdf
            fdf = pd.read_parquet("favorite_prompt.parquet", engine="pyarrow")
            odf = fdf.copy()
            max_page = [1 + len(fdf) // 5]

            def perform_favorite_search():
                global fdf
                fdf = NAIA_search.search(odf, search_label_entry.get(), exclude_label_entry.get())
                
                if type(fdf) == type(None):
                    assign_row.configure(text="검색 결과 없음")
                    return 
                
                assign_row.configure(text="랜덤 프롬프트에 삽입 "+str(len(fdf)))
                prompt_rollback.configure(text="이전 프롬프트행 복원 : "+str(len(self.freezed_cached_rows)))
                self.search_button.configure(text="검색", state="normal")
                max_page[0] = 1 + len(fdf) // 5
                current_page[0] = 0
                page.configure(text=f" 1 / {max_page[0]} ")
                prev_button.configure(state="disabled")


                if max_page[0] == 1:
                    next_button.configure(state="disabled")
                else:
                    next_button.configure(state="normal")
                update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font)

            def import_prompt():
                global fdf
                if fdf is None:
                    null_prompt_attention() # 문자열 비었다고 경고
                else:
                    self.cached_rows = fdf.copy()
                    fdf.reset_index(drop=True, inplace=True)
                    update_labels(fdf)
                prompt_rollback.configure(state="normal")

            def rollback():
                global fdf
                self.cached_rows = self.freezed_cached_rows.copy()
                update_labels(self.cached_rows)
                assign_row.configure(text="랜덤 프롬프트에 삽입 "+str(len(fdf)))
                prompt_rollback.configure(state="disabled")

            def favorite_search_close():
                self.freezed_cached_rows = None
                favorite_window.destroy()

            search_frame =  customtkinter.CTkFrame(favorite_window, width=990)
            search_frame.grid(row=0, column=0, padx=5,pady=5,  sticky="nsew")
            search_label = customtkinter.CTkLabel(search_frame, text="검색 키워드 입력 : keyword, *keyword, {keyword1|keyword2}", font=my_font)
            search_label.grid(row=0, column=0, columnspan=2, padx=8, pady=5, sticky="nsew")
            search_label_entry = customtkinter.CTkEntry(search_frame, width=485)
            search_label_entry.grid(row=1, column=0, columnspan=2, padx=8, pady=5, sticky="nsew")
            exclude_label = customtkinter.CTkLabel(search_frame, text="제외 키워드 입력 : keyword, ~keyword", font=my_font)
            exclude_label.grid(row=0, column=2, columnspan=2,  padx=8, pady=5, sticky="nsew")
            exclude_label_entry = customtkinter.CTkEntry(search_frame, width=485)
            exclude_label_entry.grid(row=1, column=2, columnspan=2, padx=8, pady=5, sticky="nsew")

            depth_search_execute = customtkinter.CTkButton(search_frame, text="선호 프롬프트내 검색", font=my_font, command=perform_favorite_search)
            depth_search_execute.grid(row=2, column=0, padx=5,pady=5,  sticky="n")

            assign_row = customtkinter.CTkButton(search_frame, text="랜덤 프롬프트에 삽입 "+str(len(fdf)), font=my_font, fg_color="#CDCDCD", text_color="black", hover_color="#848484", command=import_prompt)
            assign_row.grid(row=2, column=1, padx=5,pady=5,  sticky="n")

            prompt_rollback = customtkinter.CTkButton(search_frame, text="이전 프롬프트행 복원 : "+str(len(self.freezed_cached_rows)), font=my_font, fg_color="#7030A0", hover_color="#481F67", command=rollback, state="disabled")
            prompt_rollback.grid(row=2, column=2, padx=5,pady=5,  sticky="n")

            page_frame = customtkinter.CTkFrame(search_frame)
            page_frame.grid(row=2, column=3, padx=5,pady=5 ,sticky="nsew")

            def prev_pressed():
                current_page[0] -= 1
                if current_page[0] <= 0:
                    prev_button.configure(state="disabled")
                if current_page[0] < max_page[0]:
                    next_button.configure(state="normal")
                page.configure( text=f"{1+current_page[0]} / {max_page[0]} ")
                update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font)

            def next_pressed():
                current_page[0] += 1
                if current_page[0] >= max_page[0]-1:
                    next_button.configure(state="disabled")
                prev_button.configure(state="normal")
                page.configure( text=f"{1+current_page[0]} / {max_page[0]} ")
                update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font)


            page = customtkinter.CTkLabel(page_frame, text=f" 1 / {max_page[0]} ", font=my_font, width=70)
            page.grid(row=0, column=1,  padx=5, sticky="nsew")
            prev_button = customtkinter.CTkButton(page_frame, text=" ◀ Prev ", font=my_font, width=70, state="disabled", command=prev_pressed)
            prev_button.grid(row=0, column=0,  padx=5 ,sticky="nsew")
            next_button = customtkinter.CTkButton(page_frame, text=" Next ▶ ", font=my_font, width=70, command=next_pressed)
            next_button.grid(row=0, column=2,  padx=5,  sticky="nsew")
            if max_page[0] == 1:
                next_button.configure(state="disabled")



            favorite_window.protocol("WM_DELETE_WINDOW", favorite_search_close)

            headers = ['↙', 'character', 'copyright', 'artist', 'general prompts', 'image', 'delete']
            headers_width = [60, 120, 120, 120, 360, 120, 60]
            header_frame = customtkinter.CTkFrame(favorite_window)
            header_frame.grid(row=6, column=0, padx=5,pady=5,  sticky="nsew")
            empty_image = customtkinter.CTkImage(Image.new('RGB', size=(192,192), color="#2B2B2B"), size=(120, 120))

            for i, header in enumerate(headers):
                label = customtkinter.CTkLabel(header_frame, text=header, width=headers_width[i], font=my_font)
                label.grid(row=0, column=i, sticky="nsew", padx=5)

            ui_elements = []  # UI 요소 저장용 이중 리스트

            for i in range(5):  # DataFrame 길이를 고려
                row_elements = []
                if i < len(fdf):
                    row = fdf.iloc[i]
                row_frame = customtkinter.CTkFrame(favorite_window)
                row_frame.grid(row=i+7, column=0, sticky="nsew", padx=5, pady=5)

                for j, header in enumerate(['↙', 'character', 'copyright', 'artist', 'general', 'image', 'delete']):
                    if header == '↙':
                        button = customtkinter.CTkButton(
                            row_frame, width=headers_width[j], font=my_font,
                            text="↙", height=28, state="disabled"
                        )
                        button.grid(row=0, padx=5, column=j, sticky="nsew")
                        element = button
                    elif header == 'delete':
                        delete_button = customtkinter.CTkButton(
                            row_frame, width=headers_width[j], font=my_font, text="✖",
                            height=28, fg_color="grey", hover_color="grey10", state="disabled"
                        )
                        delete_button.grid(row=0, padx=5, column=j, sticky="nsew")
                        element = delete_button
                    elif header == 'image':
                        label = customtkinter.CTkLabel(row_frame, width=headers_width[j], font=my_font, text=" ", height=120)
                        label.grid(row=0, padx=5, column=j, sticky="nsew")
                        element = label
                    else:
                        text = customtkinter.CTkTextbox(row_frame, width=headers_width[j], font=my_font, height=120)
                        text.grid(row=0, padx=5, column=j, sticky="nsew")
                        element = text
                    row_elements.append(element)
                    
                ui_elements.append(row_elements)  # 각 행의 UI 요소를 추가

            # 이미지 삭제 함수
            def delete_image(image_path):
                try:
                    os.remove(image_path)
                except OSError as e:
                    print(f"Error deleting file {image_path}: {e.strerror}")

            # DataFrame 행 삭제 및 업데이트 함수
            def delete_row(fdf, idx, image_path, basedir):
                # DataFrame에서 특정 id 값을 가진 행을 'deleted'로 표시
                fdf.loc[fdf['id'] == idx, 'deleted'] = 'deleted'
                
                # DataFrame에서 특정 행 삭제
                fdf.drop(fdf[fdf['id'] == idx].index, inplace=True)
                
                # 변경된 DataFrame을 parquet 파일로 저장
                fdf.to_parquet("favorite_prompt.parquet", engine='pyarrow')

                # 이미지 파일 삭제
                delete_image(image_path)

                update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font)

            # 삭제 버튼 클릭 시 실행될 함수를 생성하는 함수
            def make_delete_command(fdf, idx, image_path, basedir):
                def command():
                    delete_row(fdf, idx, image_path, basedir)
                return command

            def make_select_command(dataframe, row_id):
                """
                특정 DataFrame 행의 'id' 값을 출력하는 커맨드를 생성하는 함수.
                이 함수는 람다 함수를 사용하여 버튼에 할당될 커맨드를 반환합니다.
                """
                def command():
                    popped_row = dataframe.loc[dataframe['id'] == row_id]
                    if not popped_row.empty:
                        popped_row_series = popped_row.iloc[0]  # 첫 번째 행을 Series로 변환
                        # 얻은 Series에 random_function을 적용합니다.
                        random_function(popped_row_series)
                return command

            def update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font):
                global fdf
                base_image_path = "favorite_prompts"
                rows_per_page = 5
                start_index = current_page[0] * rows_per_page  # current_page[0]에서 수정됨, current_page가 이미 정수라고 가정
                end_index = min(start_index + rows_per_page, len(fdf))

                for i in range(5):  # 최대 5개의 행을 처리
                    # 현재 페이지에 표시할 데이터가 있는 경우
                    if i < end_index - start_index:
                        row = fdf.iloc[start_index + i]
                        for j, header in enumerate(['↙', 'character', 'copyright', 'artist', 'general', 'image', 'delete']):
                            element = ui_elements[i][j]  # 기존 UI 요소에 접근
                            if header == '↙':
                                # '↙' 버튼의 커맨드 업데이트
                                element.configure(state="normal", command=make_select_command(fdf, row['id']))
                            elif header == 'delete':
                                # 'delete' 버튼의 커맨드 업데이트
                                image_path = f"{base_image_path}/{row['id']}.jpg"
                                element.configure(state="normal", command=make_delete_command(fdf, row['id'], image_path, basedir))
                            elif header == 'image':
                                try:
                                    image_path = f"{base_image_path}/{row['id']}.jpg"
                                    if os.path.exists(image_path):
                                        _image = customtkinter.CTkImage(Image.open(image_path), size=(120, 120))
                                        element.configure(image=_image)
                                    else:
                                        raise FileNotFoundError
                                except FileNotFoundError:
                                    element.configure(text="Image Not Found")
                            else:
                                # 텍스트박스의 텍스트 업데이트
                                text_value = row[header] if pd.notna(row[header]) else ""
                                element.delete("0.0", "end")
                                element.insert("0.0", text_value)
                    else:
                        # 현재 페이지에 표시할 데이터가 없는 경우, 비어 있는 행의 내용을 초기화
                        for j, element in enumerate(ui_elements[i]):
                            if isinstance(element, customtkinter.CTkLabel):
                                element.configure(text=" ", image=empty_image)
                                element.image = empty_image
                            elif isinstance(element, customtkinter.CTkTextbox):
                                element.delete("0.0", "end")
                            elif isinstance(element, customtkinter.CTkButton):
                                element.configure(state="disabled")



            # 현재 페이지를 0으로 설정 (0부터 시작)
            current_page = [0]

            # UI 업데이트 함수 호출
            update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font)
            favorite_window.after(1500, lambda: favorite_window.attributes('-topmost', False))



        self.prompt_preset_button = customtkinter.CTkButton(self.searched_prompt_frame, width=80, text="프리셋", fg_color="#848484", font=my_font, command= lambda: open_Preset(self))
        self.prompt_preset_button.grid(row=0, column=2, sticky="w")

        self.fav_button = customtkinter.CTkButton(self.searched_prompt_frame, width=40, text=" ★ ", font=my_font, fg_color="#7030A0", hover_color="#481F67",  command= open_favorite)
        self.fav_button.grid(row=0, column=2, padx=15, sticky="e")

        try:
            temp_df = pd.read_parquet("favorite_prompt.parquet", engine="pyarrow")
            self.fav_id_list = []
            if 'id' in temp_df.columns:
                self.fav_id_list.extend(temp_df['id'].tolist())
            del(temp_df)        
        except:
            self.fav_id_list = []
            #여기서 오류남 이따 고치셈
            self.fav_button.configure(state="disabled")

        def on_enter_pressed(event):
            if self.control_pressed:
                NAIA_generate(self)
                return "break"
            else:
                pass

        def on_tab_pressed(event):
            if self.toggle_prompt_fix_button.get() == 0:
                time.sleep(0.2)
                random_function()

        #텍스트 입력
        self.text_input_frame = customtkinter.CTkFrame(self.searched_prompt_frame)
        self.text_input_frame.grid(row=1, column=0, columnspan=3, sticky="nsew")
        self.text_input_label = customtkinter.CTkLabel(self.text_input_frame, text=" ----------------------------- 프롬프트 ----------------------------- ", font=large_font)
        self.text_input_label.grid(row = 0, sticky="n" )
        self.text_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, font=v_large_font, undo=True)
        self.text_input.grid(row=1, column=0, pady=5, sticky="nsew")
        self.text_input.bind("<Return>", on_enter_pressed)
        self.text_input.bind("<Tab>", on_tab_pressed)
        self.current_popped_row = None

        def random_function(edf = None):
            if(self.random_function_pressed) == False:
                self.random_function_pressed = True
                self.random_function_button.configure(state="disabled")
                if type(edf) == type(None):
                    if self.toggle_prompt_fix.get()==0 and type(self.cached_rows) == type(None):
                        self.text_input.delete("0.0", "end")
                        self.text_input.insert("0.0", "먼저 키워드 검색을 해 주세요.")
                        self.random_function_button.configure(state="normal")
                        self.random_function_pressed = False
                        return
                    if self.toggle_prompt_fix.get()==1 and type(self.cached_rows) == type(None):
                        self.random_function_pressed = False
                        return
                    elif self.toggle_prompt_fix.get()==0 and self.cached_rows.empty:
                        if (self.automation_button.get() == 0):
                            self.text_input.delete("0.0", "end")
                            self.text_input.insert("0.0", "먼저 키워드 검색을 해 주세요.")
                            self.random_function_button.configure(state="normal")
                            self.random_function_pressed = False
                            return
                        elif type(self.freezed_cached_rows) != type(None):
                            self.text_input.delete("0.0", "end")
                            self.text_input.insert("0.0", "기존 프롬프트를 복원합니다.")
                            self.cached_rows = self.freezed_cached_rows.copy()
                            time.sleep(1)
                            self.random_function_button.configure(state="normal")
                            self.random_function_pressed = False
                            app.after(0, random_function)
                            return
                        else:
                            self.text_input.delete("0.0", "end")
                            self.text_input.insert("0.0", "재검색을 수행합니다.")
                            prompt_search()
                            while(self.cached_rows.empty):
                                time.sleep(1)
                            self.random_function_button.configure(state="normal")
                            self.random_function_pressed = False
                            app.after(0, random_function)
                            return
                if self.toggle_prompt_fix.get():
                    self.random_function_pressed = False
                    return
                else:
                    if self.random_artist_button.get() == 1:
                        try:
                            if self.random_artist_prefix.get() == "artist:":
                                random_artist_name = "artist:"+ random.choice(self.random_artist)
                            elif self.random_artist_prefix.get() == "(artist)":
                                random_artist_name = random.choice(self.random_artist)+" (artist)"
                            else:
                                random_artist_name = random.choice(self.random_artist)
                        except:
                            random_artist_name = ""
                        magic_word = {
                            "random_artist":True,
                            "random_artist_name": random_artist_name
                        }
                    else:
                        magic_word = {
                            "random_artist":False
                        }
                    if self.cond_prompt_button_var.get() == 1:
                        magic_word["cond"] = self.conditional_prompt_input.get("0.0", "end-1c") if len(self.conditional_prompt_input.get("0.0", "end-1c")) > 4 else None
                    if type(edf) == type(None):
                        random_index = np.random.choice(self.cached_rows.index)
                        popped_row = self.cached_rows.loc[random_index]
                        self.current_popped_row = popped_row.copy()
                        self.cached_rows.drop(random_index, inplace=True)
                        self.cached_prompt_label.configure(text = "남은 프롬프트 행 : "+str(len(self.cached_rows)))
                    else:
                        popped_row = edf.copy()
                        self.current_popped_row = popped_row.copy()
                    if(self.toggle_wildcard_preopen.get()==1):
                        if(self.wildcard_preopen_repeat_current >= self.wildcard_preopen_repeat):
                            self.wildcard_preopen_repeat_current = 0
                            #와일드카드 개봉 구현 
                            temp_fixed = self.fixed_prompt_input.get("0.0", "end")
                            temp_fixed = [item.strip() for item in temp_fixed.split(',')]
                            global_temp = []
                            if '<' in self.fixed_prompt_input.get("0.0", "end"):
                                wildcard_present = True
                                itc = 0
                                while (wildcard_present and  itc < 10):
                                    wildcard_present = False
                                    #### 단계 1 : 인스턴트 와일드카드 처리 ###
                                    for i, keyword in enumerate(temp_fixed):
                                        if keyword.startswith('<') and keyword.endswith('>'):
                                            wildcard_present = True
                                            vbar_check = keyword[1:-1]
                                            if '|' in vbar_check:
                                                choices = vbar_check.split('|')  # '|'를 기준으로 split
                                                choice_dic = {}
                                                for choice in choices:
                                                    match = re.match(r'(\d*\.?\d+):(.+)', choice)
                                                    if match:
                                                        value, keyword = float(match.group(1)), match.group(2).strip()
                                                    else:
                                                        value, keyword = 1, choice.strip()
                                                    choice_dic[keyword] = value
                                                keywords = list(choice_dic.keys())
                                                weights = list(choice_dic.values())
                                                selected_instant_wildcard = random.choices(keywords, weights=weights, k=1)[0]
                                                temp_fixed[i] = selected_instant_wildcard
                                    #### 단계 2 : 글로벌 와일드카드 처리 ###
                                    for i, keyword in enumerate(temp_fixed):
                                        if "<" in keyword and ">" in keyword:
                                            wildcard_present = True
                                            input_str = keyword.strip('<>').strip()
                                            if("__" in input_str):
                                                adjectives = re.findall(r'__(.*?)__', input_str)
                                                last_keyword = re.split(r'__.*?__', input_str)[-1]
                                                adjective_string = ""
                                                for adjective in adjectives:
                                                    adjective_string += (self.get_wildcard(adjective) + " ")
                                                temp_fixed[i] = adjective_string + self.get_wildcard(last_keyword)
                                            else:
                                                out_wildcard = self.get_wildcard(input_str)
                                                if ',' in out_wildcard:
                                                    split_wc = [item.strip() for item in out_wildcard.split(',')]
                                                    temp = []
                                                    for _key in split_wc[1:]:
                                                        if "{" not in _key and "}" not in _key and "[" not in _key and "]" not in _key:
                                                            temp.append(_key)
                                                    if temp:
                                                        for _key in temp:
                                                            split_wc.remove(_key)
                                                            global_temp.append(_key)
                                                    if len(split_wc) == 2 and '{' not in split_wc[1] and '[' not in split_wc[1] and (split_wc[1].endswith('}') or split_wc[1].endswith(']')):
                                                        wc_post = split_wc[1].replace(']','').replace('}','')
                                                        global_temp.append(wc_post)
                                                        split_wc[0] += split_wc[1].replace(wc_post, '')
                                                        split_wc.pop()
                                                    out_wildcard = ', '.join(split_wc)
                                                temp_fixed[i] = out_wildcard
                                    itc += 1
                                    if not wildcard_present:
                                        break
                            temp_fixed_result = ', '.join(temp_fixed)
                            if global_temp: temp_fixed_result += ', '+', '.join(global_temp)
                            self.previous_fix_prompt = temp_fixed_result
                        else:
                            temp_fixed_result = self.previous_fix_prompt
                        self.wildcard_preopen_repeat_current += 1
                        prompt, self.current_prompt_rating = NAIA_random_function_core.RFP(popped_row, temp_fixed_result, self.fixed_prompt_after_input.get("0.0", "end"), self.auto_hide_keyword_input.get("0.0", "end")
                                                                ,self.rm_artist_name_button.get(), self.rm_copyright_name_button.get(),self.rm_characteristic_button.get(), self.rm_not_nsfw_button.get(), self.data, magic_word)
                    else:
                        prompt, self.current_prompt_rating = NAIA_random_function_core.RFP(popped_row, self.fixed_prompt_input.get("0.0", "end"), self.fixed_prompt_after_input.get("0.0", "end"), self.auto_hide_keyword_input.get("0.0", "end")
                                                                ,self.rm_artist_name_button.get(), self.rm_copyright_name_button.get(),self.rm_characteristic_button.get(), self.rm_not_nsfw_button.get(), self.data, magic_word)
                    self.text_input.delete("0.0", "end")
                    self.text_input.insert("0.0", prompt)
                app.after(100, lambda: self.random_function_button.configure(state="normal"))
                self.random_function_pressed = False

        self.random_function_pressed = False
        self.running_flag = False
        self.error_count = 0
        self.turbo_fail_count = 0
        self.anlas_request = False
        self.image_generation_repeat_prompt = ""

        def NAIA_generate(self):
            if self.seed_fix_button.get() == 0:
                self.entry_seed_value.set(random.randint(0,9999999999))
            if self.random_resolution_button.get() == 1:
                resolutions = ["1024 x 1024", "960 x 1088", "896 x 1152", "832 x 1216", "1088 x 960", "1152 x 896", "1216 x 832"]
                random_resolution = random.choice(resolutions)
                self.resolution_button.set(random_resolution)
            if self.cached_rows is None and self.toggle_prompt_fix_button.get() == 0 and self.automation_button.get() == 1:
                self.state_label.configure(text ="state : 자동화 전 프롬프트 검색을 수행하는 중 입니다", text_color = "#FFFF97")
                prompt_search()
            if self.turbo_button.get() == 1:
                origin = self.text_input.get("0.0", "end-1c")
                pretest = [keyword.strip() for keyword in origin.split(',')]
                if ('*(split nsfw)' in pretest or '*(split nsfw)-rand' in pretest):
                    pass
                elif (('sex' not in pretest and 'group sex' not in pretest) or ('1girl' not in pretest and 'girls' not in origin[:20]) or ('1boy' not in pretest and 'boys' not in origin[:20])):
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<UserAttention> Explicit Turbo 기능은 프롬프트 내에 1girl/girls, 1boy/boys, sex/group sex가 존재할 때 사용 가능합니다.")
                    self.turbo_fail_count += 1
                    if self.turbo_fail_count >= 20:
                        self.turbo_button.deselect()
                    self.image_label_report.configure(text_color="#FFFF97")
                    self.image_label_report.configure(state="disabled")
                    if self.automation_button.get() == 1 and self.toggle_prompt_fix_button.get() == 0:
                        random_function()
                        time.sleep(0.5)  
                        if self.searching_flag == True:
                            self.search_thread.join()
                        return self.event_generate(GENERATE_EVENT, when="tail")
                    elif self.automation_button.get() == 1 and self.toggle_prompt_fix_button.get() == 1:
                        self.automation_button.deselect()
                        return
                    else:
                        return
                self.turbo_fail_count = 0

            if not self.running_flag:
                self.image_generation_button.configure(state="disabled")
                self.running_flag = True
                NAI_width, NAI_height = self.resolution_button.get().split(' x ')
                NAI_width = str((int(NAI_width) // 64) * 64)
                NAI_height = str((int(NAI_height) // 64) * 64)
                if int(NAI_height) * int(NAI_width) > 1048576:
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<UserAttention> Anlas가 소모되는 해상도 요청입니다.")
                    self.image_label_report.configure(text_color="#FFFF97")
                    self.image_label_report.configure(state="disabled")
                    self.anlas_request = True
                scale_pre = self.cfg_scale_entry.get()
                try:
                    scale_pre = float(scale_pre)
                except:
                    scale_pre = 5.0
                    self.cfg_scale_var.set("5.0")
                rescale_pre = self.prompt_guidance_rescale_entry.get()
                try:
                    rescale_pre = float(rescale_pre)
                except:
                    rescale_pre = 0
                    self.prompt_guidance_rescale_var.set("0")
                uncond_pre = self.uncond_strength_entry.get()
                try:
                    uncond_pre = float(uncond_pre)
                    uncond_pre = round(uncond_pre / 0.05) * 0.05
                    if (uncond_pre > 1.5):
                        uncond_pre = 1.5
                        self.uncond_strength_entry.delete(0, "end")
                        self.uncond_strength_entry.insert(0, "1.5")
                except:
                    uncond_pre = 1.0
                    self.uncond_strength_entry.delete(0, "end")
                    self.uncond_strength_entry.insert(0, "1.0")
                #### 여기서부터 와일드카드 처리 구문 ####
                if self.image_generation_repeat_flag == False:
                    before_wildcard = self.text_input.get("0.0", "end-1c")
                    before_wildcard = [item.strip() for item in before_wildcard.split(',')]
                    if '<' in self.text_input.get("0.0", "end-1c"):
                        wildcard_present = True
                        itc = 0
                        while (wildcard_present and  itc < 10):
                            wildcard_present = False
                            #### 단계 1 : 인스턴트 와일드카드 처리 ###
                            for i, keyword in enumerate(before_wildcard):
                                if keyword.startswith('<') and keyword.endswith('>'):
                                    wildcard_present = True
                                    vbar_check = keyword[1:-1]
                                    if '|' in vbar_check:
                                        choices = vbar_check.split('|')  # '|'를 기준으로 split
                                        choice_dic = {}
                                        for choice in choices:
                                            match = re.match(r'(\d*\.?\d+):(.+)', choice)
                                            if match:
                                                value, keyword = float(match.group(1)), match.group(2).strip()
                                            else:
                                                value, keyword = 1, choice.strip()
                                            choice_dic[keyword] = value
                                        keywords = list(choice_dic.keys())
                                        weights = list(choice_dic.values())
                                        selected_instant_wildcard = random.choices(keywords, weights=weights, k=1)[0]
                                        before_wildcard[i] = selected_instant_wildcard
                            #### 단계 2 : 글로벌 와일드카드 처리 ###
                            for i, keyword in enumerate(before_wildcard):
                                if "<" in keyword and ">" in keyword:
                                    wildcard_present = True
                                    input_str = keyword.strip('<>').strip()
                                    if("__" in input_str):
                                        adjectives = re.findall(r'__(.*?)__', input_str)
                                        last_keyword = re.split(r'__.*?__', input_str)[-1]
                                        adjective_string = ""
                                        for adjective in adjectives:
                                            adjective_string += (self.get_wildcard(adjective) + " ")
                                        before_wildcard[i] = adjective_string + self.get_wildcard(last_keyword)
                                    else:
                                        before_wildcard[i] = self.get_wildcard(input_str)
                            itc += 1
                            if not wildcard_present:
                                break
                    else:
                        after_wildcard = self.text_input.get("0.0", "end-1c")
                    after_wildcard = ', '.join(before_wildcard)
                if self.image_generation_repeat > 1:
                    if self.image_generation_repeat_flag == False:
                        self.image_generation_repeat_flag = True
                        self.image_generation_repeat_prompt = after_wildcard
                        self.image_generation_repeat_current = 1
                    else:
                        after_wildcard = self.image_generation_repeat_prompt
                        self.image_generation_repeat_current += 1
                ##############################
                gen_request = {
                    "width":NAI_width,
                    "height":NAI_height,
                    "quality_toggle":self.auto_quality_toggle.get(),
                    "seed":self.seed_entry.get(),
                    "sampler":self.sampler_button.get(),
                    "scale":scale_pre,
                    "uncond_scale":uncond_pre,
                    "sema":self.sema_button.get(),
                    "sema_dyn": self.dyn_button.get(),
                    "cfg_rescale": rescale_pre,
                    "prompt": after_wildcard,
                    "negative":self.negative_prompt_input.get("0.0", "end-1c"),
                    "user_screen_size": self.get_max_size(),
                    "start_time": self.start_time,
                    "access_token": self.access_token,
                    "save_folder": self.output_file_path,
                    "png_rule": self.name_var.get(),
                    "type": "normal",
                    "rating":self.current_prompt_rating
                }
                if self.cond_negative_button_var.get() == 1:
                    gen_request["cond_negative"] = self.conditional_negative_input.get("0.0", "end-1c")

                if self.turbo_button.get() == 1 and "*(split nsfw)"in gen_request["prompt"]:
                    request_list = []
                    pre_prompt = gen_request["prompt"]
                    pre_prompt = [keyword.strip() for keyword in pre_prompt.split(',')]
                    fix_words = self.fixed_prompt_input.get("0.0", "end-1c")+", "+self.fixed_prompt_after_input.get("0.0", "end-1c")
                    fix_words = [keyword.strip() for keyword in fix_words.split(',')]
                    if "*(split nsfw)-rand" in pre_prompt:
                        pre_prompt.remove("*(split nsfw)-rand")
                        random_seed = True
                    else:
                        pre_prompt.remove("*(split nsfw)")
                        random_seed = False
                    nsfw_word = []
                    colors = ['black','blond','silver','gray','yellow','blue','purple','red','pink','brown','orange','green','aqua','gradient']
                    qe_word = app.data.get_qe_word() + ['cross-section', 'x-ray']
                    for keyword in pre_prompt: #전처리
                        if 'mouth' in keyword or 'eyes' in keyword:
                            if keyword not in fix_words:
                                pre_prompt.remove(keyword)
                    for keyword in pre_prompt:
                        if '{' not in keyword and '[' not in keyword and keyword in qe_word and any(color not in keyword for color in colors) :
                            nsfw_word.append(keyword)
                    if len(nsfw_word) != 0:
                        basket = []
                        for keyword in nsfw_word:
                            if 'cross-section' in keyword or 'x-ray' in keyword:
                                if keyword not in basket: basket.append(keyword)
                        for keyword in nsfw_word:
                            if 'internal cumshot' in keyword or 'ejaculation' in keyword:
                                if keyword not in basket: basket.append(keyword)
                        for keyword in nsfw_word:
                            if 'cum' in keyword or 'ahegao' in keyword:
                                if keyword not in basket: basket.append(keyword)
                        for keyword in nsfw_word:
                            if 'after ' in keyword:
                                if keyword not in basket: basket.append(keyword)
                        for keyword in basket:
                            if keyword in nsfw_word:
                                nsfw_word.remove(keyword)
                        nsfw_word += basket
                        words = []
                        if len(nsfw_word) > 13:
                            max_val = len(nsfw_word) // 4
                            if len(nsfw_word) % 4 > 0: max_val += 1
                            for i in range(max_val):
                                current_word = []
                                if i < max_val - 1:
                                    words.append(nsfw_word[i*4])
                                    words.append(nsfw_word[i*4+1])
                                    words.append(nsfw_word[i*4+2])
                                    words.append(nsfw_word[i*4+3])
                                    current_word.append(nsfw_word[i*4])
                                    current_word.append(nsfw_word[i*4+1])
                                    current_word.append(nsfw_word[i*4+2])
                                    current_word.append(nsfw_word[i*4+3])
                                else:
                                    if len(nsfw_word) % 4 == 0:
                                        words.append(nsfw_word[i*4])
                                        words.append(nsfw_word[i*4+1])
                                        words.append(nsfw_word[i*4+2])
                                        words.append(nsfw_word[i*4+3])
                                        current_word.append(nsfw_word[i*4])
                                        current_word.append(nsfw_word[i*4+1])
                                        current_word.append(nsfw_word[i*4+2])
                                        current_word.append(nsfw_word[i*4+3])
                                    elif len(nsfw_word) % 4 == 3:
                                        words.append(nsfw_word[i*4])
                                        words.append(nsfw_word[i*4+1])
                                        words.append(nsfw_word[i*4+2])
                                        current_word.append(nsfw_word[i*4])
                                        current_word.append(nsfw_word[i*4+1])
                                        current_word.append(nsfw_word[i*4+2])
                                    elif len(nsfw_word) % 4 == 2:
                                        words.append(nsfw_word[i*4])
                                        words.append(nsfw_word[i*4+1])
                                        current_word.append(nsfw_word[i*4])
                                        current_word.append(nsfw_word[i*4+1])
                                    else:
                                        words.append(nsfw_word[i*4])
                                        current_word.append(nsfw_word[i*4])
                                gen_request_sub = copy.deepcopy(gen_request)
                                temp_prompt = []+pre_prompt
                                for keyword in nsfw_word:
                                    if keyword not in words:
                                        if random_seed == False:
                                            temp_prompt[temp_prompt.index(keyword)] = " "*len(keyword)
                                        else:
                                            temp_prompt.remove(keyword)
                                    elif keyword in current_word:
                                        temp_prompt[temp_prompt.index(keyword)] = "{"+keyword+"}"
                                gen_request_sub["prompt"] = ', '.join(temp_prompt)
                                if random_seed:
                                    gen_request_sub["seed" ] = random.randint(0,9999999999)
                                request_list.append(copy.deepcopy(gen_request_sub))
                        elif len(nsfw_word) > 8:
                            max_val = len(nsfw_word) // 3
                            if len(nsfw_word) % 3 > 0: max_val += 1
                            for i in range(max_val):
                                current_word = []
                                if i < max_val - 1:
                                    words.append(nsfw_word[i*3])
                                    words.append(nsfw_word[i*3+1])
                                    words.append(nsfw_word[i*3+2])
                                    current_word.append(nsfw_word[i*3])
                                    current_word.append(nsfw_word[i*3+1])
                                    current_word.append(nsfw_word[i*3+2])
                                else:
                                    if len(nsfw_word) % 3 == 0:
                                        words.append(nsfw_word[i*3])
                                        words.append(nsfw_word[i*3+1])
                                        words.append(nsfw_word[i*3+2])
                                        current_word.append(nsfw_word[i*3])
                                        current_word.append(nsfw_word[i*3+1])
                                        current_word.append(nsfw_word[i*3+2])
                                    elif len(nsfw_word) % 3 == 2:
                                        words.append(nsfw_word[i*3])
                                        words.append(nsfw_word[i*3+1])
                                        current_word.append(nsfw_word[i*3])
                                        current_word.append(nsfw_word[i*3+1])
                                    else:
                                        words.append(nsfw_word[i*3])
                                        current_word.append(nsfw_word[i*3])
                                gen_request_sub = copy.deepcopy(gen_request)
                                temp_prompt = []+pre_prompt
                                for keyword in nsfw_word:
                                    if keyword not in words:
                                        if random_seed == False:
                                            temp_prompt[temp_prompt.index(keyword)] = " "*len(keyword)
                                        else:
                                            temp_prompt.remove(keyword)
                                    elif keyword in current_word:
                                        temp_prompt[temp_prompt.index(keyword)] = "{"+keyword+"}"
                                gen_request_sub["prompt"] = ', '.join(temp_prompt)
                                if random_seed:
                                    gen_request_sub["seed" ] = random.randint(0,9999999999)
                                request_list.append(copy.deepcopy(gen_request_sub))
                        elif len(nsfw_word) > 3:
                            max_val = len(nsfw_word) // 2 + len(nsfw_word) % 2
                            for i in range(max_val):
                                current_word = []
                                if i < max_val - 1:
                                    words.append(nsfw_word[i*2])
                                    words.append(nsfw_word[i*2+1])
                                    current_word.append(nsfw_word[i*2])
                                    current_word.append(nsfw_word[i*2+1])
                                else:
                                    if len(nsfw_word) % 2 == 0:
                                        words.append(nsfw_word[i*2])
                                        words.append(nsfw_word[i*2+1])
                                        current_word.append(nsfw_word[i*2])
                                        current_word.append(nsfw_word[i*2+1])
                                    else:
                                        words.append(nsfw_word[i*2])
                                        current_word.append(nsfw_word[i*2])
                                gen_request_sub = copy.deepcopy(gen_request)
                                temp_prompt = []+pre_prompt
                                for keyword in nsfw_word:
                                    if keyword not in words:
                                        if random_seed == False:
                                            temp_prompt[temp_prompt.index(keyword)] = " "*len(keyword)
                                        else:
                                            temp_prompt.remove(keyword)
                                    elif keyword in current_word:
                                        temp_prompt[temp_prompt.index(keyword)] = "{"+keyword+"}"
                                gen_request_sub["prompt"] = ', '.join(temp_prompt)
                                if random_seed:
                                    gen_request_sub["seed" ] = random.randint(0,9999999999)
                                request_list.append(copy.deepcopy(gen_request_sub))
                        else:
                            for word in nsfw_word:
                                words.append(word)
                                gen_request_sub = copy.deepcopy(gen_request)
                                temp_prompt = []+pre_prompt
                                for keyword in nsfw_word:
                                    if keyword not in words:
                                        if random_seed == False:
                                            temp_prompt[temp_prompt.index(keyword)] = " "*len(keyword)
                                        else:
                                            temp_prompt.remove(keyword)
                                    elif keyword == word:
                                        temp_prompt[temp_prompt.index(keyword)] = "{"+word+"}"
                                gen_request_sub["prompt"] = ', '.join(temp_prompt)
                                if random_seed:
                                    gen_request_sub["seed" ] = random.randint(0,9999999999)
                                request_list.append(copy.deepcopy(gen_request_sub))
                    else:
                        request_list.append(gen_request)
                elif self.turbo_button.get() == 1:
                    request_list = []
                    try:
                        treq_0, treq_1, treq_2, treq_3 = NAIA_generation.make_turbo_prompt(gen_request)
                        request_list.append(gen_request)
                        request_list.append(treq_0)
                        request_list.append(treq_1)
                        request_list.append(treq_2)
                        request_list.append(treq_3)
                    except:
                        request_list.append(gen_request)
                else:
                    pre_prompt = gen_request["prompt"]
                    pre_prompt = [keyword.strip() for keyword in pre_prompt.split(',')]
                    if "*(split nsfw)-rand" in pre_prompt:
                        pre_prompt.remove("*(split nsfw)-rand")
                    gen_request["prompt"] = ', '.join(pre_prompt)

                def run_generation():
                    if gen_request["png_rule"] == "count":
                        self.generation_count += 1
                        gen_request["count"] =self.generation_count
                    if app.auto_count_left_flag == True:
                        app.auto_count_left -= 1
                    if self.image_generation_repeat_flag == True:
                        gen_request["repeat"] = self.image_generation_repeat_current -1
                        gen_request["repeat_max"] = self.image_generation_repeat
                    app.image_generation_button.configure(border_width = 2)
                    pass_bit = False
                    retry_count = 0
                    while(not pass_bit):
                        self.state_label.configure(text ="state : NAI 이미지 생성 대기중 ... ", text_color = "#FFFF97")
                        result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request)
                        self.state_label.configure(text ="state : idle", text_color = "#DCE4EE")
                        app.image_generation_button.configure(border_width = 0)
                        if self.anlas_request:
                            self.anlas_request = False
                            self.get_anlas()
                        if info:
                            self.error_count = 0
                            temp = info.get('Comment', '')
                            temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','')
                            pass_bit = True
                        else:
                            self.error_count += 1
                            retry_count += 1
                            if self.error_count >= 10:
                                self.automation_button.deselect()
                            temp = result_prompt
                            if self.automation_button.get() == 1:
                                instant_wait = random.uniform(3.5, 5.5) + self.delay_offset
                                if instant_wait < 0 : instant_wait = 0.5
                                time.sleep(instant_wait)
                            else:
                                time.sleep(1)
                            if self.automation_button.get() == 0 or retry_count >= 5:
                                break
                    self.running_flag = False
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.configure(text_color="#DCE4EE")
                    self.image_label_report.insert("0.0", temp)
                    self.image_label_report.configure(state="disabled")
                    if result_image:
                        if app.state() != 'zoomed':
                            instant_result_image = customtkinter.CTkImage(result_image, size=(620,620))
                        else:
                            current_image = Image.open(filename)
                            original_width, original_height = current_image.size
                            max_size = app.winfo_screenheight()-100
                            if original_width > max_size or original_height > max_size:
                                new_image = Image.new("RGB", (max_size, max_size), "black")
                                new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                                instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                            else:
                                instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                        self.image_label.configure(image=instant_result_image)
                        set_image_to_queue(result_image, result_prompt, result_seed, filename)
                    #자동화 체크
                    if self.automation_button.get() == 1:
                        instant_wait = random.uniform(3.5, 5.5) + self.delay_offset
                        if instant_wait < 0 : instant_wait = 0.5
                        if self.image_generation_repeat_flag == False or (self.image_generation_repeat <= self.image_generation_repeat_current):
                            self.image_generation_repeat_current = 0
                            self.image_generation_repeat_flag = False
                            if self.toggle_prompt_fix_button.get() == 0:
                                random_function()
                        #반복생성 처리구문, 트래킹 필요
                        while(instant_wait > 0):
                            self.image_generation_button.configure(text=f"NAI 이미지 생성 ({round(instant_wait)})")
                            if instant_wait >= 1:
                                time.sleep(1)
                            else:
                                time.sleep(instant_wait)
                            instant_wait -= 1
                        self.image_generation_button.configure(text="NAI 이미지 생성")
                        if self.automation_button.get() == 1:
                            self.event_generate(GENERATE_EVENT, when="tail")
                        else:
                            self.image_generation_button.configure(state="normal")
                    else:
                        self.image_generation_repeat_current = 0
                        self.image_generation_repeat_flag = False
                        self.image_generation_button.configure(state="normal")
                def run_generation_turbo(gen_request):
                    if gen_request["png_rule"] == "count":
                        self.generation_count += 1
                        gen_request["count"] =self.generation_count
                    if app.auto_count_left_flag == True:
                        app.auto_count_left -= 1
                    app.image_generation_button.configure(border_width = 2)
                    pass_bit = False
                    retry_count = 0
                    while(not pass_bit):
                        self.state_label.configure(text ="state : NAI 이미지 생성 대기중 (EXP.turbo) ... ", text_color = "#FFFF97")
                        result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request)
                        self.state_label.configure(text ="state : idle", text_color = "#DCE4EE")
                        app.image_generation_button.configure(border_width = 0)
                        if info:
                            self.error_count = 0
                            temp = info.get('Comment', '')
                            temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','')
                            pass_bit = True
                        else:
                            self.error_count += 1
                            retry_count += 1
                            if self.error_count >= 10:
                                self.automation_button.deselect()
                                self.turbo_button.deselect()
                            temp = result_prompt
                            if self.automation_button.get() == 1:
                                instant_wait = random.uniform(4.5, 8.5) + self.delay_offset
                                if instant_wait < 0 : instant_wait = 0.5
                                time.sleep(instant_wait)
                            else:
                                time.sleep(1)
                            if self.turbo_button.get() == 0 or retry_count >= 5:
                                break
                    self.running_flag = False
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.configure(text_color="#DCE4EE")
                    self.image_label_report.insert("0.0", temp)
                    self.image_label_report.configure(state="disabled")
                    if result_image:
                        if app.state() != 'zoomed':
                            instant_result_image = customtkinter.CTkImage(result_image, size=(620,620))
                        else:
                            current_image = Image.open(filename)
                            original_width, original_height = current_image.size
                            max_size = app.winfo_screenheight()-100
                            if original_width > max_size or original_height > max_size:
                                new_image = Image.new("RGB", (max_size, max_size), "black")
                                new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                                instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                            else:
                                instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                        self.image_label.configure(image=instant_result_image)
                        set_image_to_queue(result_image, result_prompt, str(result_seed), filename)
                    instant_wait = random.uniform(4.5, 8.5) + self.delay_offset
                    if instant_wait < 0 : instant_wait = 0.5
                    while(instant_wait > 0):
                        self.image_generation_button.configure(text=f"NAI 이미지 생성 ({round(instant_wait)})")
                        if instant_wait >= 1:
                            time.sleep(1)
                        else:
                            time.sleep(instant_wait)
                        instant_wait -= 1
                    self.image_generation_button.configure(text="NAI 이미지 생성")

            def turbo_process_request():
                turbo_count = 0
                while(request_list):
                    gen_request = request_list.pop(0) #length=5
                    generation_thread = threading.Thread(target=run_generation_turbo, args=(gen_request,), daemon=True)
                    generation_thread.start()
                    generation_thread.join()
                    turbo_count += 1
                    if app.turbo_button.get() == 0:
                        app.state_label.configure(text =f"state : 사용자에 의한 터보요청 중단 ({turbo_count})", text_color = "#FFFF97")
                        break
                if self.automation_button.get() == 1:
                    if self.toggle_prompt_fix_button.get() == 0:
                        random_function()
                    self.event_generate(GENERATE_EVENT, when="tail")
                else:
                    self.image_generation_button.configure(state="normal")

            if self.turbo_button.get() == 0:
                generation_thread = threading.Thread(target=run_generation, daemon=True)
                generation_thread.start()
            else:
                turbo_process_request_thread = threading.Thread(target=turbo_process_request, daemon=True)
                turbo_process_request_thread.start()

        def open_AutomationSetting(self):
            if self.Automation_setting is None:
                self.Automation_setting = Automation_setting(self)
            else:
                if self.Automation_setting.state() == 'withdrawn':
                    self.Automation_setting.deiconify()  # 숨겨진 윈도우를 다시 화면에 표시
                else:
                    self.Automation_setting.focus()  

        def show_advanced_settings(self):
            if self.Advanced_setting is None:
                self.Advanced_setting = Advanced_setting(self)
            else:
                if self.Advanced_setting.state() == 'withdrawn':
                    self.Advanced_setting.deiconify()
                else:
                    self.Advanced_setting.focus()  

        def open_Character_search(self):
            if self.Character_search is None:
                if not os.path.exists("csdataset.parquet"):
                    make_parquet(self)
                self.Character_search = Character_search(self)
            else:
                if self.Character_search.state() == 'withdrawn':
                    self.Character_search.deiconify()
                else:
                    self.Character_search.focus()  

        def make_parquet(self):
            filtered_dfs = []
            df = pd.read_parquet(os.path.join(basedir, "tags.parquet"),engine="pyarrow")
            filtered_df = df[df['general'].str.contains(' solo,',  na=False) & ~df['general'].str.contains('monochrome',  na=False)]
            filtered_dfs.append(filtered_df)
            final_df = pd.concat(filtered_dfs, ignore_index=True)
            final_df.to_parquet("csdataset.parquet")



        self.Advanced_setting = None
        self.Automation_setting = None
        self.Character_search = None
        #이미지 생성 프레임
        self.image_generation_frame = customtkinter.CTkFrame(self.text_input_frame)
        self.image_generation_frame.grid(row=2, column=0, sticky="nsew")
        self.image_generation_frame.columnconfigure(0, weight= 1)
        self.image_generation_frame.columnconfigure(1, weight= 1)
        self.image_generation_frame.columnconfigure(2, weight= 1)
        self.random_function_button = customtkinter.CTkButton(self.image_generation_frame, text="랜덤/다음 프롬프트", font=my_font, command=random_function)
        self.random_function_button.grid(row=0, column=0, pady=5, sticky="nsew")
        self.automation_setting_button = customtkinter.CTkButton(self.image_generation_frame, text="자동화 설정", fg_color="#CDCDCD", text_color="black", hover_color="#848484", font=my_font, command=lambda: open_AutomationSetting(self))
        self.automation_setting_button.grid(row=0, column=1, padx=15, sticky="ew")
        self.image_generation_button = customtkinter.CTkButton(self.image_generation_frame, text="NAI 이미지 생성", fg_color="#ED7D31", hover_color="#CC5D12", font=my_font, state="disabled", command=lambda: NAIA_generate(self), text_color_disabled="black")
        self.image_generation_button.grid(row=0, column=2, pady=5, sticky="nsew")

        def hold_prompt():
            if self.toggle_prompt_fix_button.get() == 1:
                if self.unlock_hold_prompt_var.get() == 0:
                    self.fixed_prompt_input.configure(state="disabled", text_color="#A2B8D2")
                    self.fixed_prompt_after_input.configure(state="disabled", text_color="#A2B8D2")
                self.random_function_button.configure(state="disabled")
                self.rm_not_nsfw_button.deselect()
                self.rm_not_nsfw_button.configure(state="disabled")
                self.random_artist_button.deselect()
                self.random_artist_button.configure(state="disabled")
                self.unlock_hold_prompt.configure(state="normal")
            else:
                self.fixed_prompt_input.configure(state="normal", text_color="#DCE4EE")
                self.fixed_prompt_after_input.configure(state="normal", text_color="#DCE4EE")
                self.random_function_button.configure(state="normal")
                self.rm_not_nsfw_button.configure(state="normal")
                self.random_artist_button.configure(state="normal")

        def explicit_user_attention():
            if self.turbo_button.get() == 1:
                self.image_label_report.configure(state="normal")
                self.image_label_report.delete("0.0","end")
                self.image_label_report.insert("0.0", "<UserAttention> Explicit turbo 생성 도중 중단 희망시 체크박스를 해제 하시기 바랍니다.")
                self.image_label_report.configure(text_color="#FFFF97")
                self.image_label_report.configure(state="disabled")
            else:
                self.image_label_report.configure(text_color="#DCE4EE")

        self.toggle_prompt_fix = customtkinter.IntVar()
        self.toggle_prompt_fix_button = customtkinter.CTkCheckBox(self.image_generation_frame, text="프롬프트 고정", variable=self.toggle_prompt_fix, font=my_font, command=hold_prompt)
        self.toggle_prompt_fix_button.grid(row=1, column=0, sticky="ew", padx=15, pady=5)
        self.automation = customtkinter.IntVar()
        self.automation_button = customtkinter.CTkCheckBox(self.image_generation_frame, text="자동화", variable=self.automation, font=my_font)
        self.automation_button.grid(row=1, column=1, sticky="ew", padx=15)
        self.turbo = customtkinter.IntVar()
        self.turbo_button = customtkinter.CTkCheckBox(self.image_generation_frame, text="연속 이미지 생성(Explicit)", variable=self.turbo, font=my_font, command=explicit_user_attention)
        self.turbo_button.grid(row=1, column=2, sticky="ew")
        self.fixed_prompt_label = customtkinter.CTkLabel(self.text_input_frame, text=" ----------------------------- 선행 고정 프롬프트 ----------------------------- ", font=large_font)
        self.fixed_prompt_label.grid(row = 3, column=0, sticky="n" )
        self.fixed_prompt_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=100, font=v_large_font, undo=True)
        self.fixed_prompt_input.grid(row=4, column=0, pady=5, sticky="nsew")
        
        #작가명 제거 및 기타 기능
        self.check_box_frame = customtkinter.CTkFrame(self.text_input_frame)
        self.check_box_frame.grid(row=5, column=0, pady=5, columnspan=3, sticky="nsew")
        self.rm_artist_name_var = customtkinter.IntVar()
        self.rm_artist_name_button = customtkinter.CTkCheckBox(self.check_box_frame, text="작가명 제거", variable=self.rm_artist_name_var, font=my_font)
        self.rm_artist_name_button.grid(row=0, column=0, pady=5, padx=10, sticky="nsew")
        self.rm_copyright_name_var = customtkinter.IntVar()
        self.rm_copyright_name_button = customtkinter.CTkCheckBox(self.check_box_frame, text="작품명 제거", variable=self.rm_copyright_name_var, font=my_font)
        self.rm_copyright_name_button.grid(row=0, column=1, pady=5, sticky="nsew")
        self.rm_characteristic_var = customtkinter.IntVar()
        self.rm_characteristic_button = customtkinter.CTkCheckBox(self.check_box_frame, text="캐릭터 특징 제거", variable=self.rm_characteristic_var, font=my_font)
        self.rm_characteristic_button.grid(row=0, column=2, padx=10, pady=5, sticky="nsew")
        self.rm_not_nsfw_var = customtkinter.IntVar()
        self.rm_not_nsfw_button = customtkinter.CTkCheckBox(self.check_box_frame, text="NSFW Only", variable=self.rm_not_nsfw_var, font=my_font)
        self.rm_not_nsfw_button.grid(row=0, column=3, padx=15, pady=5, sticky="nsew")

        self.fixed_prompt_after_label = customtkinter.CTkLabel(self.text_input_frame, text=" ----------------------------- 후행 고정 프롬프트 ----------------------------- ", font=large_font)
        self.fixed_prompt_after_label.grid(row = 6, column=0, sticky="n" )
        self.fixed_prompt_after_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=60, font=v_large_font, undo=True)
        self.fixed_prompt_after_input.grid(row=7, column=0, pady=5, sticky="nsew")
        self.negative_prompt_label_frame = customtkinter.CTkFrame(self.text_input_frame, fg_color="#2B2B2B")
        self.negative_prompt_label_frame.grid(row = 8, column=0, sticky="nsew" )
        self.negative_prompt_label = customtkinter.CTkLabel(self.negative_prompt_label_frame, text="          ----------------------------- 네거티브 프롬프트 ------------- Strength : ", font=large_font)
        self.negative_prompt_label.grid(row = 0, column=0, sticky="w" )
        self.uncond_strength_entry = customtkinter.CTkEntry(self.negative_prompt_label_frame, font=my_font, width=50)
        self.uncond_strength_entry.grid(row = 0, column=1, sticky="e" )
        self.uncond_strength_entry.insert(0, "1.00")
        self.negative_prompt_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=100, font=v_large_font, undo=True)
        self.negative_prompt_input.insert("0.0", "lowres, jpeg artifacts, worst quality, watermark, blurry, very displeasing")
        self.negative_prompt_input.grid(row=9, column=0, pady=5, sticky="nsew")
        self.auto_hide_label = customtkinter.CTkLabel(self.text_input_frame, text="-----------------------------  자동숨김 키워드  -----------------------------", font=my_font)
        self.auto_hide_label.grid(row = 10, column=0, sticky="n" )
        self.auto_hide_keyword_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=100, font=v_large_font, undo=True)
        self.auto_hide_keyword_input.grid(row=11, column=0, pady=5, sticky="nsew")
        self.auto_quality_toggle_var = customtkinter.IntVar()
        self.auto_quality_toggle =customtkinter.CTkCheckBox(self.text_input_frame, text="Auto Quality Tag 활성화 (Undesired Content Preset은 제외)", font=my_font, variable=self.auto_quality_toggle_var)
        self.auto_quality_toggle.grid(row = 12, column = 0, pady=5, sticky="w")
        self.auto_quality_toggle.select()
        self.unlock_hold_prompt_var = customtkinter.IntVar()

        def unlock_hold():
            if self.unlock_hold_prompt_var.get() == 1:
                self.fixed_prompt_input.configure(state="normal", text_color="#DCE4EE")
                self.fixed_prompt_after_input.configure(state="normal", text_color="#DCE4EE")
            elif self.unlock_hold_prompt_var.get() == 0 and self.toggle_prompt_fix_button.get() == 1:
                self.fixed_prompt_input.configure(state="disabled", text_color="#A2B8D2")
                self.fixed_prompt_after_input.configure(state="disabled", text_color="#A2B8D2")

        def reset_wildcard_preopen():
            if self.toggle_wildcard_preopen_var.get() == 1:
                self.wildcard_preopen_repeat_current = self.wildcard_preopen_repeat
        
        self.unlock_hold_prompt = customtkinter.CTkCheckBox(self.text_input_frame, text="프롬프트 고정: 선행/후행/랜덤 프롬프트 잠금 강제해제 ", font=my_font, variable=self.unlock_hold_prompt_var, state="disabled", command=unlock_hold)
        self.unlock_hold_prompt.grid(row = 13, column = 0, pady=5, sticky="w")
        self.unlock_hold_prompt.deselect()
        self.toggle_wildcard_preopen_var = customtkinter.IntVar()
        self.toggle_wildcard_preopen = customtkinter.CTkCheckBox(self.text_input_frame, text="선행프롬의 와일드카드를 랜덤 프롬프트에서 먼저 오픈", font=my_font, variable=self.toggle_wildcard_preopen_var, command=reset_wildcard_preopen)
        self.toggle_wildcard_preopen.deselect()
        self.toggle_wildcard_preopen.grid(row = 14, column = 0, pady=5, sticky="w")

        self.conditional_frame = customtkinter.CTkFrame(self.text_input_frame, fg_color="#2B2B2B")
        self.conditional_frame.grid(row = 15, column=0, sticky="w", pady=5)

        self.cond_prompt_button_var = customtkinter.IntVar()
        self.cond_prompt_button = customtkinter.CTkCheckBox(self.conditional_frame,text="조건부 프롬프트 활성화", variable=self.cond_prompt_button_var,font=my_font )
        self.cond_prompt_button.grid(row = 0, column = 0, sticky="w")

        self.cond_negative_button_var = customtkinter.IntVar()
        self.cond_negative_button = customtkinter.CTkCheckBox(self.conditional_frame,text="조건부 네거티브 활성화", variable=self.cond_negative_button_var, font=my_font )
        self.cond_negative_button.grid(row = 0, column = 1, sticky="w", padx=5)

        self.conditional_prompt_label = customtkinter.CTkLabel(self.text_input_frame, text="------------------------  조건부 프롬프트 (랜덤시 적용) ------------------------", font=my_font)
        self.conditional_prompt_label.grid(row = 16, column=0, sticky="n" )
        self.conditional_prompt_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=100, font=v_large_font, undo=True)
        self.conditional_prompt_input.grid(row=17, column=0, pady=5, sticky="nsew")

        self.conditional_negative_label = customtkinter.CTkLabel(self.text_input_frame, text="------------------------  조건부 네거티브 (생성시 적용) ------------------------", font=my_font)
        self.conditional_negative_label.grid(row = 18, column=0, sticky="n" )
        self.conditional_negative_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=100, font=v_large_font, undo=True)
        self.conditional_negative_input.grid(row=19, column=0, pady=5, sticky="nsew")

        #이미지 히스토리
        self.image_history_frame = customtkinter.CTkFrame(self.right_frame)
        self.image_history_frame.grid(row=0, column=0, columnspan=2, rowspan=15, padx=5, pady=5, sticky="n")

        def show_context_menu(event):
            if len(app.image_queue) != 0:
                self.image_label_context_menu.tk_popup(event.x_root, event.y_root)

        def copy_file(event=None):
            focused_widget = self.focus_get()
            if focused_widget == self:
                file_path = self.image_queue[self.current_window][3]
                command = f"powershell -command \"Get-Item '{file_path}' | Set-Clipboard\""
                subprocess.run(command, shell=True)
            self.control_pressed = False

        def copy_file_instant(event=None):
            file_path = self.image_queue[self.current_window][3]
            command = f"powershell -command \"Get-Item '{file_path}' | Set-Clipboard\""
            subprocess.run(command, shell=True)

        #이미지 레이블
        self.image_label = customtkinter.CTkLabel(self.image_history_frame, text="")
        self.image_label.grid(row=1, column=0, rowspan=14, padx=10, pady=5, sticky="w")
        self.image_label.bind("<Button-3>", show_context_menu)

        self.image_label_context_menu = tk.Menu(self, tearoff=0, font=v_large_font)
        self.image_label_context_menu.add_command(label="이미지를 클립보드에 복사", command=copy_file_instant)

        
        self.image_label_report = customtkinter.CTkTextbox(self.right_frame, width=740, height=100, font=large_font)
        #image_label_report.insert("0.0", "1girl, {{minato aqua, ahoge, blue hair, braid, colored inner hair}}, artist:healthyman, [[[[[[[[[[artist:mikozin]]]]]]]]]], [[[artist:lakilolom]]], [[[[artist:crumbles]]]], [[artist:tianliang_duohe_fangdongye]], breasts, dutch angle, gloves, groin, gun, handgun, looking at viewer, nipples, no panties, one eye closed, skirt, smile, solo, topless, weapon, commentary request, highres, nsfw, great quality, aesthetic, absurdres, retouched, smooth lines, excellent color, suitable texture (SEED:22222222222), This text is sample, not an output of the actual generated result.")
        self.image_label_under_frame = customtkinter.CTkFrame(self.image_history_frame)
        self.image_label_under_frame.grid(row=0, column=0, padx=10, pady=5, sticky="ew")
        self.open_save_folder = customtkinter.CTkButton(self.image_label_under_frame, text="폴더 열기", font=my_font, fg_color="transparent", width=60,command=lambda: open_file_explorer(self))
        self.open_save_folder.grid(row=0, column=0,padx=5, pady=5, sticky="nsew")
        self.window_label = customtkinter.CTkLabel(self.image_label_under_frame, text="0 / 0", font=my_font, width=60)
        self.window_label.grid(row=0, column=4,padx=5, pady=5, sticky="nsew")
        self.my_anlas = customtkinter.IntVar(value=0)
        self.anlas_label = customtkinter.CTkLabel(self.image_label_under_frame, text="Anlas : 0", font=my_font)
        self.anlas_label.grid(row=0, column=5,padx=5, pady=5, sticky="nsew")
        self.request_upper_size_button = customtkinter.CTkButton(self.image_label_under_frame, text="img2img (trial)",fg_color="transparent", hover_color="grey10", text_color="#FFFF97", font=my_font,state="disabled",  command=lambda: img2img(self), width=110)
        self.request_upper_size_button.grid(row=0, column=6,padx=5, pady=5, sticky="nsew")
        #self.canvas_mode = customtkinter.CTkButton(self.image_label_under_frame, text="Inpaint", font=my_font, text_color="#0E0F21",fg_color="#F5F3C2", hover_color="#F2F2F2",width=50)
        #self.canvas_mode.grid(row=0, column=9,padx=5, pady=5, sticky="nsew")
        self.open_in_file_explorer = customtkinter.CTkButton(self.image_label_under_frame, text="파일 위치 열기", font=my_font, fg_color="transparent", width=80,command=lambda: open_in_file_explorer(self))
        self.open_in_file_explorer.grid(row=0, column=7,padx=5, pady=5, sticky="nsew")
        self.open_save_folder.grid(row=0, column=0,padx=5, pady=5, sticky="nsew")
        self.image_label_report.grid(row=16, column=0, padx=10, pady=5, sticky="ew")
        self.image_label_report.configure(state="disabled")
        white_image = Image.new('RGB', (768, 768), 'white')
        #white_image =Image.open("sample_image.jpg")
        white_photo = customtkinter.CTkImage(white_image, size=(620,620))
        self.image_label.configure(image=white_photo)
        self.image_label.image = white_photo

        self.image_queue = []
        self.window = 0

        #image history 버튼
        self.image_history_sub_frame = customtkinter.CTkFrame(self.image_history_frame, width=100, height=550)
        self.image_history_sub_frame.grid(row=1, rowspan=12, column=1, sticky="n")

        self.output_file_path = f"output_NAI\\{self.start_time}\\txt2img"
        self.import_image_count = 0

        def open_file_explorer(self):
            if not os.path.exists(self.output_file_path):
                os.makedirs(self.output_file_path)
            os.startfile(self.output_file_path)

        def open_in_file_explorer(self):
            filename = self.image_queue[self.current_window][3]
            explorer_command = f'explorer /select,"{os.path.abspath(filename)}"'
            subprocess.run(explorer_command)

        def up_button_pressed():
            if self.image_history_button_down.cget("state") == "disabled":
                self.image_history_button_down.configure(state="normal")
            if self.control_pressed:
                self.window = len(self.image_queue)
            else:
                self.window+=1
            update()
            show_text = str(self.window)+" / "+ str(len(self.image_queue))
            self.window_label.configure(text=show_text)
            if self.window >= len(self.image_queue):
                self.image_history_button_up.configure(state="disabled")
            self.control_pressed = False
            image_history_0_yield()

        def down_button_pressed():
            if self.image_history_button_up.cget("state") == "disabled":
                self.image_history_button_up.configure(state="normal")
            if self.control_pressed:
                if self.window >= 105:
                    self.window -= 100
                else:
                    self.window = 5
            else:
                self.window-=1
            update()
            show_text = str(self.window)+" / "+ str(len(self.image_queue))
            self.window_label.configure(text=show_text)
            if self.window <= 5:
                self.image_history_button_down.configure(state="disabled")
            self.control_pressed = False
            image_history_4_yield()

        highlight_tags = ["aqua","black","blonde","blue","brown","cyan","green","grey","orange","pink","purple","red","violet","white","yellow","mouth", "eyes", " cap", " ears", " girl", " ornament", " hat", "beret", " ear "]

        def insert_with_color(cs_text_input, current_lookup):
                words = [word.strip() for word in current_lookup.split(',')]
                for index, word in enumerate(words):
                    highlight = False
                    start_index = cs_text_input.index("end-1c")
                    if index == len(words) - 1:  # 마지막 원소인 경우
                        cs_text_input.insert("end", word)
                    else:
                        cs_text_input.insert("end", word + ", ")
                    end_index = cs_text_input.index("end-1c")

                    for tag in highlight_tags:
                        if tag in word:
                            highlight = True
                    if word == "hat": highlight = True
                    # 조건 확인
                    if word in cd.character_dictionary or word in tagbag.bag_of_tags[5:] or 'tail' in word or 'pupil' in word:
                        cs_text_input.tag_add(word, start_index, end_index)
                        cs_text_input.tag_config(word, foreground="#FFFF97")
                    elif highlight:
                        cs_text_input.tag_add(word, start_index, end_index)
                        cs_text_input.tag_config(word, foreground="#AED395")

        self.current_window = None
        def set_image_to_queue(imagen, prompt, seed, filename):
            if type(self.current_popped_row) != type(None) and not self.current_popped_row.empty:
                self.image_queue.append([imagen, prompt, seed, filename, self.current_popped_row.copy()])
            else:
                self.image_queue.append([imagen, prompt, seed, filename])
            #self.history_export.configure(text=f"export ({len(self.image_queue)})")
            self.request_upper_size_button.configure(state="normal")
            self.current_window = self.window
            if self.window == len(self.image_queue)-1:
                self.window+=1
                update()
            show_text = str(self.window)+" / "+ str(len(self.image_queue))
            
            self.window_label.configure(text=show_text)
 
        def image_history_0_yield(event=None):
            if len(self.image_queue) < 1:
                return
            if self.control_pressed:
                if self.toggle_prompt_fix_button.get() == 0:
                    self.text_input.delete("0.0", "end")
                    insert_with_color(self.text_input, self.image_queue[self.window-1][1])
                else:
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<UserAttention> 프롬프트 고정 상태에서는 사용 할 수 없습니다.")
                    self.image_label_report.configure(text_color="#FFFF97")
                    self.image_label_report.configure(state="disabled")
            else:
                self.current_window = self.window-1
                if app.state() != 'zoomed':
                    self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(620,620)))
                else:
                    current_image = Image.open(self.image_queue[self.window-1][3])
                    original_width, original_height = current_image.size
                    max_size = app.winfo_screenheight()-100
                    if original_width > max_size or original_height > max_size:
                        new_image = Image.new("RGB", (max_size, max_size), "black")
                        new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                        instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                    else:
                        instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                    self.image_label.configure(image=instant_result_image)
                self.image_label_report.configure(state="normal")
                self.image_label_report.delete("0.0", "end")
                self.image_label_report.configure(text_color="#DCE4EE")
                self.image_label_report.insert("0.0", self.image_queue[self.window-1][1] + " seed : " + str(self.image_queue[self.window-1][2]))
                self.image_label_report.configure(state="disabled")
                if len(self.image_queue[self.window-1]) >= 5 and 'id' in self.image_queue[self.window-1][4].index:
                    if fav_check(self.image_queue[self.window-1][4]['id']):
                        self.history_export.configure(text="+ FAV (★)", state="disabled")
                    else:
                        self.history_export.configure(text="+ FAV (☆)", state="normal")
                else:
                    self.history_export.configure(state="disabled")

        def image_history_1_yield(event=None):
            if len(self.image_queue) < 2:
                return
            if self.control_pressed:
                if self.toggle_prompt_fix_button.get() == 0:
                    self.text_input.delete("0.0", "end")
                    insert_with_color(self.text_input, self.image_queue[self.window-2][1])
                else:
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<UserAttention> 프롬프트 고정 상태에서는 사용 할 수 없습니다.")
                    self.image_label_report.configure(text_color="#FFFF97")
                    self.image_label_report.configure(state="disabled")
            else:
                self.current_window = self.window-2
                if app.state() != 'zoomed':
                    self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(620,620)))
                else:
                    current_image = Image.open(self.image_queue[self.window-2][3])
                    original_width, original_height = current_image.size
                    max_size = app.winfo_screenheight()-100
                    if original_width > max_size or original_height > max_size:
                        new_image = Image.new("RGB", (max_size, max_size), "black")
                        new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                        instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                    else:
                        instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                    self.image_label.configure(image=instant_result_image)
                self.image_label_report.configure(state="normal")
                self.image_label_report.delete("0.0", "end")
                self.image_label_report.configure(text_color="#DCE4EE")
                self.image_label_report.insert("0.0", self.image_queue[self.window-2][1] + " seed : " + str(self.image_queue[self.window-2][2]))
                self.image_label_report.configure(state="disabled")
                if len(self.image_queue[self.window-2]) >= 5 and 'id' in self.image_queue[self.window-2][4].index:
                    if fav_check(self.image_queue[self.window-2][4]['id']):
                        self.history_export.configure(text="+ FAV (★)", state="disabled")
                    else:
                        self.history_export.configure(text="+ FAV (☆)", state="normal")
                else:
                    self.history_export.configure(state="disabled")
        def image_history_2_yield(event=None):
            if len(self.image_queue) < 3:
                return
            if self.control_pressed:
                if self.toggle_prompt_fix_button.get() == 0:
                    self.text_input.delete("0.0", "end")
                    insert_with_color(self.text_input, self.image_queue[self.window-3][1])
                else:
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<UserAttention> 프롬프트 고정 상태에서는 사용 할 수 없습니다.")
                    self.image_label_report.configure(text_color="#FFFF97")
                    self.image_label_report.configure(state="disabled")
            else:
                self.current_window = self.window-3
                if app.state() != 'zoomed':
                    self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(620,620)))
                else:
                    current_image = Image.open(self.image_queue[self.window-3][3])
                    original_width, original_height = current_image.size
                    max_size = app.winfo_screenheight()-100
                    if original_width > max_size or original_height > max_size:
                        new_image = Image.new("RGB", (max_size, max_size), "black")
                        new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                        instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                    else:
                        instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                    self.image_label.configure(image=instant_result_image)
                self.image_label_report.configure(state="normal")
                self.image_label_report.delete("0.0", "end")
                self.image_label_report.configure(text_color="#DCE4EE")
                self.image_label_report.insert("0.0", self.image_queue[self.window-3][1] + " seed : " + str(self.image_queue[self.window-3][2]))
                self.image_label_report.configure(state="disabled")
                if len(self.image_queue[self.window-3]) >= 5 and 'id' in self.image_queue[self.window-3][4].index:
                    if fav_check(self.image_queue[self.window-3][4]['id']):
                        self.history_export.configure(text="+ FAV (★)", state="disabled")
                    else:
                        self.history_export.configure(text="+ FAV (☆)", state="normal")
                else:
                    self.history_export.configure(state="disabled")
        def image_history_3_yield(event=None):
            if len(self.image_queue) < 4:
                return
            if self.control_pressed:
                if self.toggle_prompt_fix_button.get() == 0:
                    self.text_input.delete("0.0", "end")
                    insert_with_color(self.text_input, self.image_queue[self.window-4][1])
                else:
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<UserAttention> 프롬프트 고정 상태에서는 사용 할 수 없습니다.")
                    self.image_label_report.configure(text_color="#FFFF97")
                    self.image_label_report.configure(state="disabled")
            else:
                self.current_window = self.window-4
                if app.state() != 'zoomed':
                    self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(620,620)))
                else:
                    current_image = Image.open(self.image_queue[self.window-4][3])
                    original_width, original_height = current_image.size
                    max_size = app.winfo_screenheight()-100
                    if original_width > max_size or original_height > max_size:
                        new_image = Image.new("RGB", (max_size, max_size), "black")
                        new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                        instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                    else:
                        instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                    self.image_label.configure(image=instant_result_image)
                self.image_label_report.configure(state="normal")
                self.image_label_report.delete("0.0", "end")
                self.image_label_report.configure(text_color="#DCE4EE")
                self.image_label_report.insert("0.0", self.image_queue[self.window-4][1] + " seed : " + str(self.image_queue[self.window-4][2]))
                self.image_label_report.configure(state="disabled")
                if len(self.image_queue[self.window-4]) >= 5 and 'id' in self.image_queue[self.window-4][4].index:
                    if fav_check(self.image_queue[self.window-4][4]['id']):
                        self.history_export.configure(text="+ FAV (★)", state="disabled")
                    else:
                        self.history_export.configure(text="+ FAV (☆)", state="normal")
                else:
                    self.history_export.configure(state="disabled")
        def image_history_4_yield(event=None):
            if len(self.image_queue) < 5:
                return
            if self.control_pressed:
                if self.toggle_prompt_fix_button.get() == 0:
                    self.text_input.delete("0.0", "end")
                    insert_with_color(self.text_input, self.image_queue[self.window-5][1])
                else:
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<UserAttention> 프롬프트 고정 상태에서는 사용 할 수 없습니다.")
                    self.image_label_report.configure(text_color="#FFFF97")
                    self.image_label_report.configure(state="disabled")
            else:
                self.current_window = self.window-5
                if app.state() != 'zoomed':
                    self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-5][0], size=(620,620)))
                else:
                    current_image = Image.open(self.image_queue[self.window-5][3])
                    original_width, original_height = current_image.size
                    max_size = app.winfo_screenheight()-100
                    if original_width > max_size or original_height > max_size:
                        new_image = Image.new("RGB", (max_size, max_size), "black")
                        new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                        instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                    else:
                        instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                    self.image_label.configure(image=instant_result_image)
                self.image_label_report.configure(state="normal")
                self.image_label_report.delete("0.0", "end")
                self.image_label_report.configure(text_color="#DCE4EE")
                self.image_label_report.insert("0.0", self.image_queue[self.window-5][1] + " seed : " + str(self.image_queue[self.window-5][2]))
                self.image_label_report.configure(state="disabled")
                if len(self.image_queue[self.window-5]) >= 5 and 'id' in self.image_queue[self.window-5][4].index:
                    if fav_check(self.image_queue[self.window-5][4]['id']):
                        self.history_export.configure(text="+ FAV (★)", state="disabled")
                    else:
                        self.history_export.configure(text="+ FAV (☆)", state="normal")
                else:
                    self.history_export.configure(state="disabled")

        def update():
            if len(self.image_queue) <= 5:
                if len(self.image_queue) >= 1:
                    self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
                    if len(self.image_queue[self.window-1]) >= 5:
                        button_item_0 = self.image_queue[self.window-1][4].copy()
                        self.image_history_0.bind("<Button-3>", lambda event: on_right_click(event, button_item_0))
                if len(self.image_queue) >= 2:
                    self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
                    if len(self.image_queue[self.window-1]) >= 5:
                        button_item_0 = self.image_queue[self.window-1][4].copy()
                        self.image_history_0.unbind("<Button-3>")
                        self.image_history_0.bind("<Button-3>", lambda event: on_right_click(event, button_item_0))
                    self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100)))
                    if len(self.image_queue[self.window-2]) >= 5:
                        button_item_1 = self.image_queue[self.window-2][4].copy()
                        self.image_history_1.bind("<Button-3>", lambda event: on_right_click(event, button_item_1))
                if len(self.image_queue) >= 3:
                    self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
                    if len(self.image_queue[self.window-1]) >= 5:
                        button_item_0 = self.image_queue[self.window-1][4].copy()
                        self.image_history_0.unbind("<Button-3>")
                        self.image_history_0.bind("<Button-3>", lambda event: on_right_click(event, button_item_0))
                    self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100)))
                    if len(self.image_queue[self.window-2]) >= 5:
                        button_item_1 = self.image_queue[self.window-2][4].copy()
                        self.image_history_1.unbind("<Button-3>")
                        self.image_history_1.bind("<Button-3>", lambda event: on_right_click(event, button_item_1))
                    self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100)))
                    if len(self.image_queue[self.window-3]) >= 5:
                        button_item_2 = self.image_queue[self.window-3][4].copy()
                        self.image_history_2.bind("<Button-3>", lambda event: on_right_click(event, button_item_2))
                if len(self.image_queue) >= 4:
                    self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
                    if len(self.image_queue[self.window-1]) >= 5:
                        button_item_0 = self.image_queue[self.window-1][4].copy()
                        self.image_history_0.unbind("<Button-3>")
                        self.image_history_0.bind("<Button-3>", lambda event: on_right_click(event, button_item_0))
                    self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100)))
                    if len(self.image_queue[self.window-2]) >=5:
                        button_item_1 = self.image_queue[self.window-2][4].copy()
                        self.image_history_1.unbind("<Button-3>")
                        self.image_history_1.bind("<Button-3>", lambda event: on_right_click(event, button_item_1))
                    self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100)))
                    if len(self.image_queue[self.window-3]) >= 5:
                        button_item_2 = self.image_queue[self.window-3][4].copy()
                        self.image_history_2.unbind("<Button-3>")
                        self.image_history_2.bind("<Button-3>", lambda event: on_right_click(event, button_item_2))
                    self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100)))
                    if len(self.image_queue[self.window-4]) >= 5:
                        button_item_3 = self.image_queue[self.window-4][4].copy()
                        self.image_history_3.bind("<Button-3>", lambda event: on_right_click(event, button_item_3))
                if len(self.image_queue) == 5:
                    self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
                    if len(self.image_queue[self.window-1]) >= 5:
                        button_item_0 = self.image_queue[self.window-1][4].copy()
                        self.image_history_0.unbind("<Button-3>")
                        self.image_history_0.bind("<Button-3>", lambda event: on_right_click(event, button_item_0))
                    self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100)))
                    if len(self.image_queue[self.window-2]) >= 5:
                        button_item_1 = self.image_queue[self.window-2][4].copy()
                        self.image_history_1.unbind("<Button-3>")
                        self.image_history_1.bind("<Button-3>", lambda event: on_right_click(event, button_item_1))
                    self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100)))
                    if len(self.image_queue[self.window-3]) >= 5:
                        button_item_2 = self.image_queue[self.window-3][4].copy()
                        self.image_history_2.unbind("<Button-3>")
                        self.image_history_2.bind("<Button-3>", lambda event: on_right_click(event, button_item_2))
                    self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100)))
                    if len(self.image_queue[self.window-4]) >= 5:
                        button_item_3 = self.image_queue[self.window-4][4].copy()
                        self.image_history_3.unbind("<Button-3>")
                        self.image_history_3.bind("<Button-3>", lambda event: on_right_click(event, button_item_3))
                    self.image_history_4.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-5][0], size=(100,100)))
                    if len(self.image_queue[self.window-5]) >= 5:
                        button_item_4 = self.image_queue[self.window-5][4].copy()
                        self.image_history_4.bind("<Button-3>", lambda event: on_right_click(event, button_item_4))
            else:
                self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
                if len(self.image_queue[self.window-1]) >= 5:
                    button_item_0 = self.image_queue[self.window-1][4].copy()
                    self.image_history_0.unbind("<Button-3>")
                    self.image_history_0.bind("<Button-3>", lambda event: on_right_click(event, button_item_0))
                self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100)))
                if len(self.image_queue[self.window-2]) >= 5:
                    button_item_1 = self.image_queue[self.window-2][4].copy()
                    self.image_history_1.unbind("<Button-3>")
                    self.image_history_1.bind("<Button-3>", lambda event: on_right_click(event, button_item_1))
                self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100)))
                if len(self.image_queue[self.window-3]) >= 5:
                        button_item_2 = self.image_queue[self.window-3][4].copy()
                        self.image_history_2.unbind("<Button-3>")
                        self.image_history_2.bind("<Button-3>", lambda event: on_right_click(event, button_item_2))
                self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100)))
                if len(self.image_queue[self.window-4]) >= 5:
                        button_item_3 = self.image_queue[self.window-4][4].copy()
                        self.image_history_3.unbind("<Button-3>")
                        self.image_history_3.bind("<Button-3>", lambda event: on_right_click(event, button_item_3))
                self.image_history_4.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-5][0], size=(100,100)))
                if len(self.image_queue[self.window-5]) >= 5:
                    button_item_4 = self.image_queue[self.window-5][4].copy()
                    self.image_history_4.unbind("<Button-3>")
                    self.image_history_4.bind("<Button-3>", lambda event: on_right_click(event, button_item_4))
            if len(self.image_queue) == 6:
                self.image_history_button_down.configure(state="normal")

        def some_command(item):
            print(item)
            random_function(item)

        def on_right_click(event, button_item):
            context_menu.delete(0, tk.END)  # 기존 메뉴 항목을 모두 삭제
            context_menu.add_command(label="Requeue", command=lambda: some_command(button_item))  # 새 커맨드 추가
            context_menu.tk_popup(event.x_root, event.y_root)
                
        context_menu = tk.Menu(self, tearoff=0, font=v_large_font, fg="black")

        black_image = Image.new('RGB', (100, 100), '#2B2B2B')
        self.image_history_0 = customtkinter.CTkButton(self.image_history_sub_frame, width=100, height=100, corner_radius=8,text="", fg_color="transparent", image=customtkinter.CTkImage(black_image, size=(100,100)), command=image_history_0_yield)
        self.image_history_0.grid(row=0, column=1, padx=5, pady=1, sticky="n")

        self.image_history_1 = customtkinter.CTkButton(self.image_history_sub_frame, width=100, height=100, corner_radius=8,text="", fg_color="transparent", image=customtkinter.CTkImage(black_image, size=(100,100)), command=image_history_1_yield)
        self.image_history_1.grid(row=1, column=1, padx=5, pady=1, sticky="n")
        self.image_history_2 = customtkinter.CTkButton(self.image_history_sub_frame, width=100, height=100, corner_radius=8,text="", fg_color="transparent",image=customtkinter.CTkImage(black_image, size=(100,100)), command=image_history_2_yield)
        self.image_history_2.grid(row=2, column=1, padx=5, pady=1, sticky="n")
        self.image_history_3 = customtkinter.CTkButton(self.image_history_sub_frame, width=100, height=100, corner_radius=8,text="", fg_color="transparent", image=customtkinter.CTkImage(black_image, size=(100,100)), command=image_history_3_yield)
        self.image_history_3.grid(row=3,column=1, padx=5, pady=1, sticky="n")
        self.image_history_4 = customtkinter.CTkButton(self.image_history_sub_frame, width=100, height=100, corner_radius=8,text="", fg_color="transparent",  image=customtkinter.CTkImage(black_image, size=(100,100)), command=image_history_4_yield)
        self.image_history_4.grid(row=4, column=1, padx=5, pady=1, sticky="n")
        self.image_history_button_up = customtkinter.CTkButton(self.image_history_frame, text="▲", width=100, font=my_font, state="disabled", command=up_button_pressed)
        self.image_history_button_up.grid(row=0, column=1, pady=10, padx=5, sticky="n")
        self.image_history_button_down = customtkinter.CTkButton(self.image_history_frame, text="▼", width=100, font=my_font, state="disabled", command=down_button_pressed)
        self.image_history_button_down.grid(row=13, column=1, pady=5, padx=5, sticky="n")

        def save_to_excel():
            #contributor : highnoon1
            #function : 히스토리 엑셀로 저장 (무제한 보기는 성능 이슈로 제외)
            workbook = Workbook()
            sheet = workbook.active

            alignment = Alignment(wrapText=True)
            sheet['A1'].alignment = alignment
            sheet['A1'] = 'Prompt'
            sheet['B1'] = 'Seed'
            sheet['C1'] = 'Image'

            image_objects = []  # BytesIO 객체를 추적하기 위한 리스트

            # history 데이터를 반복하며 Excel에 저장
            for index, (pil_image, prompt, seed, *_rest) in enumerate(self.image_queue):
                
                row_num = index + 1  # 행 번호 (Excel 행은 1부터 시작)

                # 프롬프트와 시드 삽입
                prompt_cell = sheet.cell(row=row_num, column=1, value=prompt)
                sheet.cell(row=row_num, column=2, value=seed)
                prompt_cell.alignment = Alignment(wrap_text=True)

                # PIL 이미지를 BytesIO 객체에 PNG 형식으로 저장
                pil_image = self.resize_image_to_fit(pil_image,192)
                output = io.BytesIO()
                pil_image.save(output, format='PNG')
                output.seek(0)
                image_objects.append(output)  # 리스트에 추가

                # Openpyxl 이미지 생성 및 시트에 추가
                img = OpenpyxlImage(output)
                img.anchor = f'C{row_num}'  # 이미지를 C열에 고정
                sheet.add_image(img)

                # 이미지 크기에 따라 행 높이 및 열 너비 조정
                scale_factor = 0.75
                sheet.row_dimensions[row_num].height = pil_image.height * scale_factor
                sheet.column_dimensions['C'].width = pil_image.width * scale_factor / 7

            # A열과 B열 크기 조정
            sheet.column_dimensions['A'].width = 50
            sheet.column_dimensions['B'].width = 15

            # 워크북 저장
            workbook.save(f"history_with_images_{self.start_time}.xlsx")

            # 모든 BytesIO 객체 닫기
            for img_obj in image_objects:
                img_obj.close()
            if os.path.exists(f"history_with_images_{self.start_time}.xlsx"):
                os.startfile(f"history_with_images_{self.start_time}.xlsx")

            print("엑셀 파일에 저장됨")

        def history_export():
            if self.control_pressed:
                save_to_excel()
                self.history_export.configure(text="+ FAV (☆)", fg_color="#F5F3C2", hover_color="#A69F40", text_color="black")
                if self.image_queue and len(self.image_queue[self.current_window]) >= 5:
                    self.history_export.configure(state="normal")
                else:
                    self.history_export.configure(state="disabled")
            else:
                """
                Description : @history_export 평상시에는 FAV 기능으로 동작
                """
                new_data = self.image_queue[self.current_window][4]
                validation_prompt = self.image_queue[self.current_window][1]
                prompt = new_data['general']
                validation_prompt = [key.strip() for key in validation_prompt.split(',')]
                prompt = [key.strip() for key in prompt.split(',')]
                autohide = self.auto_hide_keyword_input.get("0.0", "end")
                autohide = [key.strip() for key in autohide.split(',')] + app.data.bag_of_tags
                prompt = [key for key in prompt if key not in autohide]
                not_validated = [key for key in prompt if key not in validation_prompt]
                if len(not_validated) >= 3:
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", f"<ValidationError> 랜덤하게 생성된 프롬프트가 아니거나, {len(not_validated)}개의 제거된 태그가 검출되어 Favorite 등록에 실패하였습니다. 해당 기능은 랜덤 생성 프롬프트를 DataFrame 규격에 맞춰 복사하는 기능이기 때문에 수정된 프롬프트의 저장은 지원하지 않습니다.")
                    self.image_label_report.configure(text_color="#FFFF97")
                    self.image_label_report.configure(state="disabled")
                    return
                try:
                    favorite_prompts = pd.read_parquet('favorite_prompt.parquet')
                except FileNotFoundError:
                    dtype_dict = {
                        'id': 'int64',
                        'copyright': 'object',
                        'character': 'object',
                        'artist': 'object',
                        'general': 'object',
                        'meta': 'object',
                        'rating': 'object',
                        'score': 'object',
                        'created_at': 'object',
                    }
                    favorite_prompts = pd.DataFrame(columns=dtype_dict.keys())
                    self.fav_button.configure(state="normal")
                try:
                    _temp = new_data['id']
                except:
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<TagsError> 0215 버전부터 tags의 구성이 변경되었습니다. favorite 기능을 사용하기 위해 검색을 다시 수행 해 주세요.")
                    self.image_label_report.configure(text_color="#FFFF97")
                    self.image_label_report.configure(state="disabled")
                    return
                new_data_id = new_data['id']
                new_data = pd.DataFrame([new_data])
                success = False
                if 'id' not in favorite_prompts.columns:
                    favorite_prompts = pd.concat([favorite_prompts, new_data], ignore_index=True)
                    success = True
                elif not favorite_prompts['id'].isin([new_data_id]).any():
                    favorite_prompts = pd.concat([favorite_prompts, new_data], ignore_index=True)
                    success = True
                else:
                    self.image_label_report.configure(state="normal")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<AlreadyExist> 이미 favorite에 등록되어있는 프롬프트입니다.")
                    self.image_label_report.configure(text_color="#FFFF97")
                    self.image_label_report.configure(state="disabled")
                if success:
                    pil_image = self.image_queue[self.current_window][0]
                    folder_path = 'favorite_prompts'
                    if not os.path.exists(folder_path):
                        os.makedirs(folder_path)
                    favorite_prompts.to_parquet('favorite_prompt.parquet')
                    image_path = os.path.join(folder_path, f"{_temp}.jpg")
                    pil_image.save(image_path, 'JPEG')
                    self.fav_id_list.append(_temp)
                self.history_export.configure(text="FAV (★)", fg_color="#F5F3C2", hover_color="#A69F40", text_color="black", state="disabled")

        self.history_export = customtkinter.CTkButton(self.image_history_frame, text="+ FAV (☆)", width=100, fg_color="#F5F3C2", hover_color="#A69F40", text_color="black", font=my_font, command=history_export, state="disabled")
        self.history_export.grid(row=14, column=1, pady=10, padx=5, sticky="n")

        #랜덤작가 및 와일드카드 설정
        self.extended_right_frame = customtkinter.CTkFrame(self.right_frame)
        self.extended_right_frame.grid(row=17, column=0, columnspan=2, padx=5, sticky="w")
        self.random_artist_var = customtkinter.IntVar()
        self.random_artist_button = customtkinter.CTkCheckBox(self.extended_right_frame, text="랜덤작가 추가", variable=self.random_artist_var, font=my_font, state="disabled")
        self.random_artist_button.grid(row=0, column=0,pady=5, padx=10, sticky="nsew")
        self.random_artist_manage_button = customtkinter.CTkButton(self.extended_right_frame, text="랜덤작가 관리", font=my_font, command=self.random_artist_window)
        self.random_artist_manage_button.grid(row=0, column=1,pady=5, padx=5, sticky="nsew")
        self.recommended_prompt_button = customtkinter.CTkButton(self.extended_right_frame, text="추천 프롬프트", font=my_font, command= self.open_prompt_window)
        self.recommended_prompt_button.grid(row=0, column=3,pady=5, padx=5, sticky="nsew")
        self.wildcard_manager_button = customtkinter.CTkButton(self.extended_right_frame, text="와일드카드 관리", font=my_font, command=self.open_wildcard_window)
        self.wildcard_manager_button.grid(row=0, column=2,pady=5, padx=5, sticky="nsew")
        self.character_search_button = customtkinter.CTkButton(self.extended_right_frame, text="캐릭터 검색", fg_color="#7030A0", hover_color="#481F67", font=my_font, command= lambda: open_Character_search(self))
        self.character_search_button.grid(row=0, column=4,pady=5, padx=5, sticky="nsew")
        self.seed_fix_var = customtkinter.IntVar()
        self.seed_fix_button = customtkinter.CTkCheckBox(self.extended_right_frame, text="시드고정 ", variable=self.seed_fix_var, font=my_font)
        self.seed_fix_button.grid(row=1, column=0,pady=5, padx=10, sticky="nsew")
        self.entry_seed_value = customtkinter.IntVar()
        self.seed_entry = customtkinter.CTkEntry(self.extended_right_frame, textvariable=self.entry_seed_value)
        self.seed_entry.grid(row=1, column=1,pady=5, padx=5, sticky="nsew")
        self.seed_entry.insert(0, random.randint(0,9999999999))
        self.cfg_scale_label = customtkinter.CTkLabel(self.extended_right_frame, text="CFG Scale : ", font=my_font)
        self.cfg_scale_label.grid(row=1, column=2,pady=5, padx=5, sticky="w")
        self.cfg_scale_var = customtkinter.StringVar(value="5.0")
        self.cfg_scale_entry = customtkinter.CTkEntry(self.extended_right_frame, width=65, textvariable=self.cfg_scale_var)
        self.cfg_scale_entry.grid(row=1, column=2,pady=5, padx=5, sticky="e")
        self.prompt_guidance_rescale_var = customtkinter.StringVar(value="0")
        self.prompt_guidance_rescale_label = customtkinter.CTkLabel(self.extended_right_frame, text="Prompt Guidance Rescale :", font=my_font)
        self.prompt_guidance_rescale_label.grid(row=1, column=3, pady=5, padx=5, sticky="w")
        self.prompt_guidance_rescale_entry = customtkinter.CTkEntry(self.extended_right_frame, width=65)
        self.prompt_guidance_rescale_entry.grid(row=1, column=4,pady=5, padx=10, sticky="w")
        self.extra_setting_button = customtkinter.CTkButton(self.extended_right_frame, width=55, text="기타설정", font=my_font, fg_color="grey", hover_color="grey5", command=lambda: show_advanced_settings(self))
        self.extra_setting_button.grid(row=1, column=4,pady=5, padx=5, sticky="e")
        self.random_resolution_var = customtkinter.IntVar()
        self.random_resolution_button = customtkinter.CTkCheckBox(self.extended_right_frame, text="랜덤 해상도 ", variable=self.random_resolution_var, font=my_font)
        self.random_resolution_button.grid(row=2, column=0,pady=5, padx=10, sticky="nsew")
        self.resolution_var = customtkinter.StringVar(value="1024 x 1024")
        self.resolution_button = customtkinter.CTkComboBox(self.extended_right_frame, width=160,values=["1024 x 1024", "960 x 1088", "896 x 1152", "832 x 1216", "1088 x 960", "1152 x 896", "1216 x 832"], variable=self.resolution_var, font=my_font)
        self.resolution_button.grid(row=2, column=1, padx=5, sticky="w")
        self.sampler_label = customtkinter.CTkLabel(self.extended_right_frame, text="Sampler :", font=my_font)
        self.sampler_label.grid(row=2, column=2,pady=5, padx=15, sticky="w")
        self.sampler_var = customtkinter.StringVar(value="k_euler_ancestral")
        self.sampler_button = customtkinter.CTkComboBox(self.extended_right_frame, width=210,values=["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde", "k_dpmpp_2m"], variable=self.sampler_var, font=my_font)
        self.sampler_button.grid(row=2, column=2, columnspan=2, pady=5, padx=15, sticky="e")
        self.show_fullscreen_btn = customtkinter.CTkButton(self.extended_right_frame, text="전체화면(ESC닫기)", font=my_font, command=self.show_fullscreen_image)
        self.show_fullscreen_btn.grid(row=2, column=4,pady=5, padx=5, sticky="nsew")
        self.sema_button_var = customtkinter.IntVar()

        def sema_pressed():
            if self.sema_button_var.get() == 0:
                self.dyn_button.deselect()

        self.sema_button = customtkinter.CTkCheckBox(self.extended_right_frame, text="SMEA", variable=self.sema_button_var,font=my_font, command=sema_pressed)
        self.sema_button.grid(row=3, column=0, pady=5, padx=10, sticky="w")
        self.dyn_button_var = customtkinter.IntVar()
        
        def sema_dyn_pressed():
            if self.dyn_button_var.get() == 1:
                self.sema_button.select()

        self.dyn_button = customtkinter.CTkCheckBox(self.extended_right_frame, text="SMEA+DYN", variable=self.dyn_button_var, font=my_font, command=sema_dyn_pressed)
        self.dyn_button.grid(row=3, column=1, pady=5, padx=10, sticky="w")
        self.state_label = customtkinter.CTkLabel(self.extended_right_frame, text="state : idle", font=my_font)
        self.state_label.grid(row=3, column=2, columnspan=2, pady=5, padx=10, sticky="n")
        self.instant_row_button = customtkinter.CTkButton(self.extended_right_frame, text="인스턴트 이벤트", font=my_font, fg_color="grey10", command=self.open_instant_event)
        self.instant_row_button.grid(row=3, column=4,pady=5, padx=5, sticky="nsew")
        GENERATE_EVENT = "<<GenerateEvent>>"
        sync_text()
        self.bind(GENERATE_EVENT, lambda x=None: NAIA_generate(self))
        self.output_file_path_personal = False
        self.png_name_rule = "time"
        self.name_var = customtkinter.StringVar(value=self.png_name_rule)
        self.window_resize_last_access = None
        self.last_window_size_conf = None
        self.generation_count = 0
        self.random_artist_list = None
        self.random_artist = []
        self.random_artist_prefix = customtkinter.StringVar(value="none")

        def on_window_resize(event):
            if datetime.now() == app.last_window_size_conf:
                return
            time_difference = datetime.now() - app.start_time_prime
            if (time_difference.total_seconds() < 3):
                return
            if app.last_window_size is None:
                app.last_window_size = (app.winfo_width(), app.winfo_height())
        # 윈도우가 최대화되었는지 확인
            current_size = (app.winfo_width(), app.winfo_height())
            if current_size != app.last_window_size:
                app.last_window_size = current_size
                if app.state() == 'zoomed':
                    print(app.winfo_width())
                    self.right_frame.configure(width=1200)
                    self.image_label.grid_forget()
                    self.image_label_under_frame.grid_forget()
                    self.image_history_sub_frame.grid_forget()
                    self.image_history_button_down.grid_forget()
                    self.image_history_sub_frame.grid(row=0, pady=45, rowspan=12, column=1, sticky="n")
                    self.image_history_button_down.grid(row=9, column=1, pady=5, padx=5, sticky="n")
                    self.image_label.grid(row=0, column=0,rowspan=14, padx=10, pady=5, sticky="w")
                    self.hidden_frame.grid(row=0, column=2,rowspan=14, sticky="nsew")
                    self.history_export.grid(row=10, column=1, pady=1, padx=5, sticky="n")
                    self.random_artist_button = customtkinter.CTkCheckBox(self.hidden_frame, text="랜덤작가 추가", variable=self.random_artist_var, font=my_font, state="disabled")
                    self.random_artist_button.grid(row=0, column=0,pady=5, padx=5, sticky="nsew")
                    self.seed_fix_button = customtkinter.CTkCheckBox(self.hidden_frame, text="시드고정 ", variable=self.seed_fix_var, font=my_font)
                    self.seed_fix_button.grid(row=1, column=0,pady=5, padx=5, sticky="nsew")
                    self.seed_entry = customtkinter.CTkEntry(self.hidden_frame, textvariable=self.entry_seed_value)
                    self.seed_entry.grid(row=1, column=1,pady=5, padx=5, sticky="nsew")
                    self.random_artist_manage_button = customtkinter.CTkButton(self.hidden_frame, text="랜덤작가 관리", font=my_font, command=self.random_artist_window)
                    self.random_artist_manage_button.grid(row=0, column=1,pady=5, padx=5, sticky="nsew")
                    self.random_resolution_button2 = customtkinter.CTkCheckBox(self.hidden_frame, text="랜덤 해상도", variable=self.random_resolution_var, font=my_font)
                    self.random_resolution_button2.grid(row=3, column=0,pady=5, padx=5, sticky="nsew")
                    self.resolution_button2 = customtkinter.CTkComboBox(self.hidden_frame, width=160,values=["1024 x 1024", "960 x 1088", "896 x 1152", "832 x 1216", "1088 x 960", "1152 x 896", "1216 x 832"], variable=self.resolution_var, font=my_font)
                    self.resolution_button2.grid(row=3, column=1, padx=5, sticky="w")
                    self.sampler_label2 = customtkinter.CTkLabel(self.hidden_frame, text="Sampler :", font=my_font)
                    self.sampler_label2.grid(row=4, column=0,pady=5, padx=5, sticky="w")
                    self.sampler_button2 = customtkinter.CTkComboBox(self.hidden_frame, width=160,values=["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde", "k_dpmpp_2m"], variable=self.sampler_var, font=my_font)
                    self.sampler_button2.grid(row=4, column=1, columnspan=2, pady=5, padx=5, sticky="e")
                    self.cfg_scale_label2 = customtkinter.CTkLabel(self.hidden_frame, text="CFG Scale : ", font=my_font)
                    self.cfg_scale_label2.grid(row=5, column=0,pady=5, padx=5, sticky="w")
                    self.cfg_scale_entry2 = customtkinter.CTkEntry(self.hidden_frame, width=65, textvariable=self.cfg_scale_var)
                    self.cfg_scale_entry2.grid(row=5, column=1,pady=5, padx=5, sticky="w")
                    self.prompt_guidance_rescale_label2 = customtkinter.CTkLabel(self.hidden_frame, text="P.Guide Rescale :", font=my_font)
                    self.prompt_guidance_rescale_label2.grid(row=6, column=0, pady=5, padx=5, sticky="w")
                    self.prompt_guidance_rescale_entry2 = customtkinter.CTkEntry(self.hidden_frame, width=65, textvariable=self.prompt_guidance_rescale_var)
                    self.prompt_guidance_rescale_entry2.grid(row=6, column=1,pady=5, padx=5, sticky="w")
                    self.sema_button2 = customtkinter.CTkCheckBox(self.hidden_frame, text="SEMA", variable=self.sema_button_var,font=my_font)
                    self.sema_button2.grid(row=7, column=0, pady=5, padx=5, sticky="w")
                    self.dyn_button2 = customtkinter.CTkCheckBox(self.hidden_frame, text="SEMA+DYN", variable=self.dyn_button_var, font=my_font)
                    self.dyn_button2.grid(row=7, column=1, pady=5, padx=5, sticky="w")
                    self.open_save_folder2 = customtkinter.CTkButton(self.hidden_frame, text="폴더 열기", font=my_font, fg_color="transparent", command=lambda: open_file_explorer(self), width=80)
                    self.open_save_folder2.grid(row=5, column=1,padx=5, pady=5, sticky="e")
                    self.extra_setting_button2 = customtkinter.CTkButton(self.hidden_frame, width=80, text="기타설정", font=my_font, fg_color="grey", hover_color="grey5", command=lambda: show_advanced_settings(self))
                    self.extra_setting_button2.grid(row=6, column=1,pady=5, padx=5, sticky="e")
                    self.recommended_prompt_button2 = customtkinter.CTkButton(self.hidden_frame, text="추천 프롬프트", font=my_font,  command= self.open_prompt_window)
                    self.recommended_prompt_button2.grid(row=9, column=0, columnspan=2, pady=5, padx=5, sticky="nsew")
                    self.wildcard_manager_button2 = customtkinter.CTkButton(self.hidden_frame, text="와일드카드 관리", font=my_font, command=self.open_wildcard_window)
                    self.wildcard_manager_button2.grid(row=10, column=0,columnspan=2, pady=5, padx=5, sticky="nsew")
                    self.character_search_button2 = customtkinter.CTkButton(self.hidden_frame, text="캐릭터 검색", fg_color="#7030A0", hover_color="#481F67", font=my_font, command= lambda: open_Character_search(self))
                    self.character_search_button2.grid(row=11, column=0,columnspan=2, pady=5, padx=5, sticky="nsew")
                    self.window_label.grid_forget()
                    self.window_label = customtkinter.CTkLabel(self.hidden_frame, text=str(self.window)+" / "+ str(len(self.image_queue)), font=my_font)
                    self.window_label.grid(row=12, column=0,padx=5, pady=5, sticky="w")
                    self.request_upper_size_button2 = customtkinter.CTkButton(self.hidden_frame, text="img2img (trial)",fg_color="transparent", hover_color="grey10", text_color="#FFFF97", font=my_font,  command=lambda: img2img(self), width=110)
                    self.request_upper_size_button2.grid(row=12, column=1,padx=5, pady=5, sticky="nsew")
                                
                    if self.image_queue:
                        current_image = Image.open(self.image_queue[self.window-1][3])
                        original_width, original_height = current_image.size
                        max_size = app.winfo_screenheight()-100
                        if original_width > max_size or original_height > max_size:
                            new_image = Image.new("RGB", (max_size, max_size), "black")
                            new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                            instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                        else:
                            instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                        self.image_label.configure(image=instant_result_image)
                    else:
                        self.image_label.configure(image=customtkinter.CTkImage(white_image, size=(app.winfo_screenheight()-100, app.winfo_screenheight()-100)))
                else:
                    self.right_frame.configure(width=768)
                    self.image_label_report.grid_forget()
                    self.image_label.grid_forget()
                    self.image_label_under_frame.grid_forget()
                    self.image_history_sub_frame.grid_forget()
                    self.image_history_button_up.grid_forget()
                    self.image_history_button_down.grid_forget()
                    self.image_label.grid(row=1, column=0, rowspan=14, padx=10, pady=5, sticky="w")
                    self.image_label_under_frame.grid(row=0, column=0, padx=10, pady=5, sticky="ew")
                    self.image_history_sub_frame.grid(row=1, rowspan=12, column=1, sticky="n")
                    self.image_label_report.grid(row=16, column=0, padx=10, pady=5, sticky="ew")
                    self.image_history_button_up.grid(row=0, column=1, pady=10, padx=5, sticky="n")
                    self.image_history_button_down.grid(row=13, column=1, pady=5, padx=5, sticky="n")
                    self.history_export.grid(row=14, column=1, pady=10, padx=5, sticky="n")
                    self.hidden_frame.grid_forget()
                    self.window_label.grid_forget()
                    self.window_label = customtkinter.CTkLabel(self.image_label_under_frame, text=str(self.window)+" / "+ str(len(self.image_queue)), font=my_font)
                    self.window_label.grid(row=0, column=4,padx=5, pady=5, sticky="w")


                    if self.image_queue:
                        self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(620, 620)))
                    else:
                        self.image_label.configure(image=customtkinter.CTkImage(white_image, size=(620, 620)))
                app.last_window_size_conf =  datetime.now()
        self.bind("<Configure>", on_window_resize)

        def on_ctrl_press(event):
            self.control_pressed = True
            self.search_button.configure(text="심층 검색")
            self.image_history_button_up.configure(text="▲ (Top)")
            self.image_history_button_down.configure(text="▼ (100)")
            self.request_upper_size_button.configure(text="img2img (INST)", text_color="#FD8853")
            self.history_export.configure(text=f"export ({len(self.image_queue)})", fg_color="#1F6AA5", hover_color="#144870", text_color="#DCE4EE")
            if app.state() == 'zoomed':
                self.request_upper_size_button2.configure(text="img2img (INST)", text_color="#FD8853")

        def on_ctrl_release(event):
            self.control_pressed = False
            self.search_button.configure(text="검색")
            self.image_history_button_up.configure(text="▲")
            self.image_history_button_down.configure(text="▼")
            self.request_upper_size_button.configure(text="img2img (trial)", text_color="#FFFF97")
            self.history_export.configure(text="+ FAV (☆)", fg_color="#F5F3C2", hover_color="#A69F40", text_color="black")
            if self.image_queue and len(self.image_queue[self.current_window]) >= 5:
                self.history_export.configure(state="normal")
            else:
                self.history_export.configure(state="disabled")
            if app.state() == 'zoomed':
                self.request_upper_size_button2.configure(text="img2img (trial)", text_color="#FFFF97")

        def on_escape(event=None):
            self.focus_set()
        self.bind('<Escape>', on_escape)

        self.control_pressed = False
        self.bind_all("<Control_L>", on_ctrl_press)
        self.bind_all("<KeyRelease-Control_L>", on_ctrl_release)
        self.bind('<Control-c>', copy_file)
        self.last_window_size = None
        self.random_artist_select = "global"
        self.random_artist_list_length = 0
        self.protocol("WM_DELETE_WINDOW", lambda: (self.Automation_setting.destroy()))
        self.wildcard_dict = None
        self.wildacrds_dir = ""

        def on_arrow_key(event):
            key_pressed = event.keysym
            #self.focus_set()
            if key_pressed == "Up" and self.image_history_button_up.cget("state") == "normal":
                up_button_pressed()
            elif key_pressed == "Down" and self.image_history_button_down.cget("state") == "normal":
                down_button_pressed()

        def img2img(self):
            if self.control_pressed: 
                instant_img2img(self)
                self.control_pressed = False
            else: 
                global img2img_window
                if img2img_window is not None:
                    img2img_window.destroy()
                    img2img_window = None
                _img2img(self)

        def _img2img(self):
            global iimg, img2img_window, inpaint_mode

            def instant_image_generation(self, current_lookup):
                try:
                    img2img_window.attributes('-topmost', False)
                except:
                    pass
                def image_to_base64(image):
                    image_bytesIO = io.BytesIO()
                    img.save(image_bytesIO, format="png")
                    return base64.b64encode(image_bytesIO.getvalue()).decode()
                def mask_to_base64(image):
                    # PIL.Image 객체를 넘파이 배열로 변환
                    i = np.array(image)
                    # RGBA 채널 처리를 위해 알파 채널 추가 전 이미지 처리
                    if i.shape[-1] == 3:  # RGB 이미지인 경우
                        alpha = np.sum(i, axis=-1) > 0  # 알파 마스크 생성
                        alpha = np.uint8(alpha * 255)  # 알파 채널 값으로 변환
                        rgba = np.dstack((i, alpha))  # RGBA 이미지 생성
                    elif i.shape[-1] == 4:  # 이미 RGBA 이미지인 경우
                        rgba = i
                    else:
                        raise ValueError("Unsupported image format")

                    # 넘파이 배열에서 PIL.Image 객체로 변환
                    img = Image.fromarray(rgba)
                    
                    # PIL.Image 객체를 Base64 문자열로 변환
                    image_bytesIO = io.BytesIO()
                    img.save(image_bytesIO, format="png")
                    return base64.b64encode(image_bytesIO.getvalue()).decode()
                try:
                    i2i_generate_button.configure(state="disabled")
                except:
                    pass
                try:
                    request_prompt = i2i_text_input.get("0.0", "end")
                except:
                    request_prompt = self.text_input.get("0.0", "end")
                try:
                    request_seed = current_lookup[2]
                    filename = current_lookup[3]
                except:
                    current_lookup = self.image_queue[self.current_window].copy()
                    request_seed = current_lookup[2]
                    filename = current_lookup[3]
                img = Image.open(filename)
                send_image = image_to_base64(img)
                scale_pre = self.cfg_scale_entry.get()
                try:
                    steps = request_upper_size_steps.get()
                except:
                    steps = 28
                try:
                    scale_pre = float(scale_pre)
                except:
                    scale_pre = 5.0
                    self.cfg_scale_var.set("5.0")
                rescale_pre = self.prompt_guidance_rescale_entry.get()
                try:
                    rescale_pre = float(rescale_pre)
                except:
                    rescale_pre = 0
                    self.prompt_guidance_rescale_var.set("0")
                try:
                    steps = int(steps)
                except:
                    steps = 28
                    self.cfg_scale_var.set("28")
                uncond_pre = self.uncond_strength_entry.get()
                try:
                    uncond_pre = float(uncond_pre)
                    uncond_pre = round(uncond_pre / 0.05) * 0.05
                    if (uncond_pre > 1.5):
                        uncond_pre = 1.5
                        self.uncond_strength_entry.delete(0, "end")
                        self.uncond_strength_entry.insert(0, "1.5")
                except:
                    uncond_pre = 1.0
                    self.uncond_strength_entry.delete(0, "end")
                    self.uncond_strength_entry.insert(0, "1.0")
                try:
                    i2i_negative_text = i2i_negative_input.get("0.0", "end-1c")
                except:
                    i2i_negative_text = self.negative_prompt_input.get("0.0", "end-1c")
                inpaint_check = sum(sum(row) for row in mirror_image) >= 50
                gen_request = {
                        "width":self.i2i_width if not inpaint_check else cwidth ,
                        "height":self.i2i_height if not inpaint_check else cheight,
                        "quality_toggle":self.auto_quality_toggle.get(),
                        "seed":request_seed if self.i2i_seed_hold_check == True else random.randint(0,9999999999),
                        "sampler":self.sampler_button.get(),
                        "scale":scale_pre,
                        "uncond_scale":uncond_pre,
                        "sema":self.sema_button.get(),
                        "sema_dyn": self.dyn_button.get(),
                        "cfg_rescale": rescale_pre,
                        "prompt": request_prompt,
                        "negative":i2i_negative_text,
                        "user_screen_size": self.get_max_size(),
                        "start_time": self.start_time,
                        "access_token": self.access_token,
                        "save_folder": self.output_file_path,
                        "png_rule": self.name_var.get(),
                        "type": "upper" if not inpaint_check else "inpaint",
                        "steps": steps if steps <= 50 else 50,
                        "image": send_image
                    }
                if not inpaint_check:
                    gen_request["strength"] = round(self.i2i_value, 2)
                    gen_request["noise"] = 0
                if gen_request["type"] == "inpaint":
                    gen_request["mask"] = mask_to_base64(create_and_save_mask_image())
                    gen_request["add_original_image"] = True if overlay_original_image_var.get()==1 else False
                def run_generation():
                        if gen_request["png_rule"] == "count":
                            self.generation_count += 1
                            gen_request["count"] =self.generation_count
                        self.state_label.configure(text ="state : img2img 요청됨 ", text_color = "#FFFF97")
                        result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request)
                        self.state_label.configure(text ="state : img2img 요청 반환됨", text_color = "#DCE4EE")
                        self.get_anlas()
                        i2i_generate_button.configure(state="normal")
                        if info:
                            temp = info.get('Comment', '')
                            temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','')
                        else:
                            temp = result_prompt
                        self.image_label_report.configure(state="normal")
                        self.image_label_report.delete("0.0", "end")
                        self.image_label_report.configure(text_color="#DCE4EE")
                        self.image_label_report.insert("0.0", temp)
                        self.image_label_report.configure(state="disabled")
                        if result_image:
                            if app.state() != 'zoomed':
                                instant_result_image = customtkinter.CTkImage(result_image, size=(620,620))
                            else:
                                current_image = Image.open(filename)
                                original_width, original_height = current_image.size
                                max_size = app.winfo_screenheight()-100
                                if original_width > max_size or original_height > max_size:
                                    new_image = Image.new("RGB", (max_size, max_size), "black")
                                    new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                                    instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                                else:
                                    instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                            self.image_label.configure(image=instant_result_image)
                            img_label_result.grid(row=0, column=1)
                            img_label_result.configure(image=customtkinter.CTkImage(result_image, size=(576, 576)))
                            set_image_to_queue(result_image, result_prompt, str(result_seed), filename)
                generation_thread = threading.Thread(target=run_generation, daemon=True)
                generation_thread.start()
            
            def find_max_resolution(width, height, max_pixels=2166784, multiple_of=64):
                ratio = width / height

                max_width = int((max_pixels * ratio)**0.5)
                max_height = int((max_pixels / ratio)**0.5)

                max_width = (max_width // multiple_of) * multiple_of
                max_height = (max_height // multiple_of) * multiple_of

                while max_width * max_height > max_pixels:
                    max_width -= multiple_of
                    max_height = int(max_width / ratio)
                    max_height = (max_height // multiple_of) * multiple_of

                return (max_width, max_height)

            img2img_window = customtkinter.CTkToplevel()
            img2img_window.title("img2img")
            img2img_window.attributes('-topmost', True)
            img2img_window.resizable(width=False, height=False)

            current_lookup = copy.deepcopy(self.image_queue[self.current_window])
            filename = current_lookup[3]
            img = Image.open(filename)
            width, height = img.size

            img2img_window_left = customtkinter.CTkFrame(img2img_window)
            img2img_window_left.grid(row=0, column=0, pady=5, padx=5, sticky="nsew")
            img2img_window_right = customtkinter.CTkFrame(img2img_window, width=586)
            img2img_window_right.grid(row=0, column=1, pady=5, padx=5, sticky="nsew")
            #img2img_window_menu = customtkinter.CTkFrame(img2img_window, width=140)
            #img2img_window_menu.grid(row=0, column=2, pady=5, padx=5, sticky="nsew")

            iimg = None
            inpaint_mode = False
            iimg = Image.open(filename).convert("RGB")
            original_image = iimg.copy()
            cwidth, cheight = iimg.size

            # mirror_width와 mirror_height 계산
            mirror_width = width // 8
            mirror_height = height // 8
            mirror_image = [[0 for _ in range(mirror_height)] for _ in range(mirror_width)]

            img_label = customtkinter.CTkCanvas(img2img_window_left, width=cwidth, height=cheight)
            img_label.grid(row=0, column=0)
            img_label_result = customtkinter.CTkLabel(img2img_window_left, text="")

            # 마스크 이미지 생성 및 저장 함수
            def create_and_save_mask_image():
                # 마스크 이미지 생성: 원본 이미지 크기의 1/8, 투명 배경
                mask_image = Image.new('RGBA', (mirror_width, mirror_height), (0, 0, 0, 0))
                draw = ImageDraw.Draw(mask_image)
                
                # 이중리스트를 순회하며 value > 0인 위치에 하얀색으로 칠함
                for x in range(mirror_width):
                    for y in range(mirror_height):
                        if mirror_image[x][y] > 0:
                            draw.point((x, y), fill=(255, 255, 255, 255))
                
                # 마스크 이미지를 파일로 저장
                return mask_image

            tk_image = ImageTk.PhotoImage(iimg)
            canvas = img_label
            canvas.create_image(0, 0, anchor="nw", image=tk_image)
            canvas.image = tk_image  # 참조를 유지

            def create_custom_cursor():
                # 40x40px 투명 이미지 생성
                cursor_image = Image.new("RGBA", (40, 40), (0, 0, 0, 0))
                draw = ImageDraw.Draw(cursor_image)
                # 1px 하얀색 테두리 그리기
                draw.rectangle([0, 0, 39, 39], outline=(255, 255, 255, 255))
                return cursor_image

            # 마우스 이동 이벤트에 대한 핸들러
            def on_mouse_move(event):
                # 이전에 그려진 커스텀 커서가 있다면 삭제
                canvas.delete("custom_cursor")
                # 마우스 위치에 커스텀 커서 이미지를 표시
                cursor_image = create_custom_cursor()
                tk_cursor_image = ImageTk.PhotoImage(cursor_image)
                # canvas에 커스텀 커서 이미지 렌더링. 이 때, 'tags' 옵션을 사용하여 태그를 지정
                canvas.create_image(event.x, event.y, image=tk_cursor_image, anchor="center", tags="custom_cursor")
                # 커스텀 커서 이미지의 참조를 별도로 유지
                canvas.cursor_image = tk_cursor_image

            # 마우스 이동 이벤트 바인딩
            canvas.bind("<Motion>", on_mouse_move)

            def inpaint_check():
                global inpaint_mode
                check =  sum(sum(row) for row in mirror_image) >= 50
                if(check and not inpaint_mode):
                    inpaint_mode = True
                    i2i_slider_label.grid_forget()
                    i2i_slider.grid_forget()
                    i2i_resolution_label.grid_forget()
                    i2i_radio_frame.grid_forget()
                    overlay_original_image.grid(row=0, column=0, padx=30, sticky="n")
                    cancel_inpainting_button.grid(row=0, column=1, padx=30, sticky="n")
                elif(inpaint_mode and not check):
                    inpaint_mode = False
                    overlay_original_image.grid_forget()
                    cancel_inpainting_button.grid_forget()
                    i2i_slider_label.grid(row=0, column=0, sticky="nsew")
                    i2i_slider.grid(row=0, column=1, sticky="nsew")
                    i2i_resolution_label.grid(row=1, column=0, sticky="nsew")
                    i2i_radio_frame.grid(row=1, column=1, pady=5, sticky="nsew")


            def update_canvas_image():
                global tk_image  # 전역 변수 사용
                tk_image = ImageTk.PhotoImage(iimg)
                canvas.create_image(0, 0, anchor="nw", image=tk_image, tags="original_image")  # 'tags' 옵션을 사용하여 태그 지정
                canvas.image = tk_image  # 원본 이미지 참조 업데이트

            def on_canvas_click_or_move(event):
                x, y = event.x // 8, event.y // 8
                paint_on_image(x, y)
                update_canvas_image()

            def paint_on_image(x, y):
                draw = ImageDraw.Draw(iimg, 'RGBA')
                for i in range(max(0, x-2), min(mirror_width, x+3)):
                    for j in range(max(0, y-2), min(mirror_height, y+3)):
                        mirror_image[i][j] += 1  # 마스크 업데이트
                        if mirror_image[i][j] == 1:  # 마스크 값이 0보다 큰 경우에만 페인트 칠함
                            draw.rectangle([(i*8, j*8), ((i+1)*8-1, (j+1)*8-1)], fill=(0, 0, 255, 128))
                inpaint_check()

            def remove_paint_from_image(x, y):
                global iimg
                for i in range(max(0, x-2), min(mirror_width, x+3)):
                    for j in range(max(0, y-2), min(mirror_height, y+3)):
                        mirror_image[i][j] = 0  # 마스크 값을 0으로 설정
                        
                        # 원본 이미지에서 해당 영역의 픽셀 값을 가져옴
                        original_pixels = original_image.load()
                        current_pixels = iimg.load()
                        
                        for xi in range(i*8, min((i+1)*8, width)):
                            for yi in range(j*8, min((j+1)*8, height)):
                                # 원본 이미지의 픽셀 값을 현재 이미지에 복원
                                current_pixels[xi, yi] = original_pixels[xi, yi]
                inpaint_check()

            def on_canvas_right_click_or_move(event):
                # 마우스 우클릭 위치를 축소된 좌표로 변환
                x, y = event.x // 8, event.y // 8
                # 페인트 제거 함수 호출
                remove_paint_from_image(x, y)
                # 변경된 이미지를 캔버스에 다시 표시
                update_canvas_image()

            # 우클릭 이벤트와 우클릭 드래그 이벤트에 대한 바인딩
            canvas.bind("<Button-3>", on_canvas_right_click_or_move)
            canvas.bind("<B3-Motion>", on_canvas_right_click_or_move)
            canvas.bind("<Button-1>", on_canvas_click_or_move)
            canvas.bind("<B1-Motion>", on_canvas_click_or_move)

            highlight_tags = ["aqua","black","blonde","blue","brown","cyan","green","grey","orange","pink","purple","red","violet","white","yellow","mouth", "eyes", " cap", " ears", " girl", " ornament", " hat", "beret", " ear "]

            def insert_with_color():
                words = [word.strip() for word in current_lookup[1].split(',')]
                for index, word in enumerate(words):
                    highlight = False
                    start_index = i2i_text_input.index("end-1c")
                    if index == len(words) - 1:  # 마지막 원소인 경우
                        i2i_text_input.insert("end", word)
                    else:
                        i2i_text_input.insert("end", word + ", ")
                    end_index = i2i_text_input.index("end-1c")

                    for tag in highlight_tags:
                        if tag in word:
                            highlight = True
                    if word == "hat": highlight = True
                    # 조건 확인
                    if word in cd.character_dictionary or word in tagbag.bag_of_tags[5:] or 'tail' in word or 'pupil' in word:
                        i2i_text_input.tag_add(word, start_index, end_index)
                        i2i_text_input.tag_config(word, foreground="#FFFF97")
                    elif highlight:
                        i2i_text_input.tag_add(word, start_index, end_index)
                        i2i_text_input.tag_config(word, foreground="#AED395")

            i2i_text_input_label = customtkinter.CTkLabel(img2img_window_right, text="            ------------------- i2i 프롬프트 -------------------  ", font=large_font)
            i2i_text_input_label.grid(row = 0, sticky="w" )
            text_hyperlink = customtkinter.CTkLabel(img2img_window_right, text="가이드 열기 (arca.live)", font=customtkinter.CTkFont('Pretendard', 13), width=180, text_color="lightblue", cursor="hand2", state="disabled")
            text_hyperlink.grid(row=0, column=0, padx=5, pady=5, sticky="e")
            #text_hyperlink.bind("<Button-1>", lambda e: webbrowser.open_new("https://arca.live/b/aiart/95877361"))
            i2i_text_input = customtkinter.CTkTextbox(img2img_window_right, width=490, height=240,font=v_large_font)
            i2i_text_input.grid(row=1, column=0, pady=5, sticky="nsew")
            insert_with_color()

            def slider_event(value):
                i2i_slider_label.configure(text=f"Strength : {value:.2f}")
                self.i2i_value = value

            def get_i2i_neagtive(filename):
                with Image.open(filename) as img:
                    info = img.info.get('Comment', '')
                start_pattern = '"uc": "'
                end_pattern = '", "'
                start_index = info.find(start_pattern)
                if start_index != -1:
                    # 실제 추출할 문자열의 시작 인덱스 조정
                    start_index += len(start_pattern)
                    
                    # 종료 패턴의 인덱스를 찾기
                    end_index = info.find(end_pattern, start_index)
                    if end_index != -1:
                        # 문자열 추출
                        extracted_string = info[start_index:end_index]
                else:
                    if app.current_window in app.import_image_negative:
                        extracted_string = app.import_image_negative[app.current_window]
                    else:
                        extracted_string = ""
                return extracted_string

            i2i_offset_input_label = customtkinter.CTkLabel(img2img_window_right, text="            ------------------- i2i 네거티브 -------------------  ", font=large_font)
            i2i_offset_input_label.grid(row = 2, column=0,sticky="w" )
            i2i_character_search_button = customtkinter.CTkButton(img2img_window_right, text="캐릭터 검색", fg_color="#7030A0", hover_color="#481F67", font=my_font, command= lambda: open_Character_search(self))
            i2i_character_search_button.grid(row=2, column=0, pady=5, padx=5, sticky="e")
            i2i_negative_input = customtkinter.CTkTextbox(img2img_window_right, width=490, height=115,font=v_large_font)
            i2i_negative_input.grid(row=3, column=0, pady=5, sticky="nsew")
            i2i_negative = get_i2i_neagtive(filename)
            i2i_negative_input.insert("0.0", i2i_negative)

            i2i_slider_frame = customtkinter.CTkFrame(img2img_window_right, fg_color="#333333")
            i2i_slider_frame.grid(row=4, column=0, pady=5, padx=5, sticky="nsew")

            i2i_value = round(self.i2i_value, 2)
            i2i_seed_hold_check = 1 if self.i2i_seed_hold_check else 0
            i2i_slider_label = customtkinter.CTkLabel(i2i_slider_frame, text="Strength : "+str(i2i_value), font=large_font, width=140)
            i2i_slider_label.grid(row=0, column=0, sticky="nsew")
            i2i_slider = customtkinter.CTkSlider(i2i_slider_frame, from_=0, to=0.99, number_of_steps=100, command=slider_event, width=340)
            i2i_slider.grid(row=0, column=1, sticky="nsew")
            i2i_slider.set(i2i_value)
            i2i_resolution_label = customtkinter.CTkLabel(i2i_slider_frame, text="해상도 배율", font=large_font, width=140)
            i2i_resolution_label.grid(row=1, column=0, sticky="nsew")

            def restore_original_image():
                global tk_image, iimg
                iimg = Image.open(filename).convert("RGB")
                tk_image = ImageTk.PhotoImage(iimg.copy())  # 원본 이미지를 사용하여 Tkinter 호환 이미지 생성
                canvas.create_image(0, 0, anchor="nw", image=tk_image)
                canvas.image = tk_image
                for i in range(len(mirror_image)):
                    for j in range(len(mirror_image[i])):
                        mirror_image[i][j] = 0
                inpaint_check()

            overlay_original_image_var = customtkinter.IntVar()
            overlay_original_image = customtkinter.CTkCheckBox(i2i_slider_frame, text="Overlay Original Image", font=large_font, width=140, variable=overlay_original_image_var)
            cancel_inpainting_button = customtkinter.CTkButton(i2i_slider_frame, text="인페인트 취소", font=large_font, command=restore_original_image)

            i2i_radio_frame = customtkinter.CTkFrame(i2i_slider_frame,  fg_color="#333333")
            i2i_radio_frame.grid(row=1, column=1, pady=5, sticky="nsew")

            radio_var = customtkinter.IntVar(value=self.i2i_resolution)
            i2i_request_width = customtkinter.IntVar(value=width)
            i2i_request_height = customtkinter.IntVar(value=height)
            img2img_window.after(2500, lambda: img2img_window.attributes('-topmost', False))



            def radiobutton_event():
                v = radio_var.get()
                if v == 0: 
                    request_width = width
                    request_height = height
                    self.i2i_resolution = 0
                elif v == 1:
                    request_width, request_height = find_max_resolution(width, height, 2166784)
                    self.i2i_resolution = 1
                elif v == 2:
                    request_width, request_height = find_max_resolution(width, height, 2662400)
                    self.i2i_resolution = 2
                i2i_resolution_label.configure(text=f"{request_width} x {request_height}")
                i2i_request_width.set(request_width)
                self.i2i_width = request_width
                i2i_request_height.set(request_height)
                self.i2i_height = request_height

            radio_button_1 = customtkinter.CTkRadioButton(i2i_radio_frame, text="해상도 유지", command=radiobutton_event, variable= radio_var, value=0, font=large_font)
            radio_button_1.grid(row=0, column=0, sticky="nsew")
            radio_button_2 = customtkinter.CTkRadioButton(i2i_radio_frame, text="2.16 MP", command=radiobutton_event, variable= radio_var, value=1, font=large_font)
            radio_button_2.grid(row=0, column=1, sticky="nsew")
            radio_button_3 = customtkinter.CTkRadioButton(i2i_radio_frame, text="2.66 MP", command=radiobutton_event, variable= radio_var, value=2, font=large_font)
            radio_button_3.grid(row=0, column=2, sticky="nsew")
            radiobutton_event()

            i2i_generate_frame = customtkinter.CTkFrame(img2img_window_right,  fg_color="#2B2B2B")
            i2i_generate_frame.grid(row=5, column=0, pady=5, sticky="n")

            i2i_offset_input_label2 = customtkinter.CTkLabel(i2i_generate_frame, text=" 해상도와 Strength에 따라 Anlas가 소모됩니다 ", font=large_font, text_color="#FFFF97")
            i2i_offset_input_label2.grid(row = 0, column=0, columnspan=3, sticky="n" )

            def seed_button_event():
                self.i2i_seed_hold_check = True if request_upper_size_seed_hold.get() == 1 else False

            request_upper_size_seed_hold_var = customtkinter.IntVar(value=i2i_seed_hold_check)
            request_upper_size_seed_hold = customtkinter.CTkCheckBox(i2i_generate_frame, text="시드고정  Step : ", font=my_font, variable=request_upper_size_seed_hold_var, command=seed_button_event)
            request_upper_size_seed_hold.grid(row=1, column=0, padx=5, pady=5, sticky="nsew")
            request_upper_size_seed_hold.select() if i2i_seed_hold_check == 1 else request_upper_size_seed_hold.deselect()
            request_upper_size_steps = customtkinter.StringVar(value="28")
            request_upper_size_steps_entry = customtkinter.CTkEntry(i2i_generate_frame, font=my_font, textvariable=request_upper_size_steps, width=60)
            request_upper_size_steps_entry.grid(row=1, column=1,padx=5, pady=5, sticky="nsew")
            i2i_generate_button = customtkinter.CTkButton(i2i_generate_frame, text="Request I2I", font=large_font,  command=lambda: instant_image_generation(self, current_lookup))
            i2i_generate_button.grid(row = 1, column= 2, pady=5, sticky="n" )
            
        def instant_img2img(self):
            current_lookup = self.image_queue[self.current_window].copy()
            def instant_image_generation(self):
                def image_to_base64(image):
                    image_bytesIO = io.BytesIO()
                    img.save(image_bytesIO, format="png")
                    return base64.b64encode(image_bytesIO.getvalue()).decode()
                request_prompt = current_lookup[1]
                request_seed = current_lookup[2]
                filename = current_lookup[3]
                img = Image.open(filename)
                send_image = image_to_base64(img)
                scale_pre = self.cfg_scale_entry.get()
                steps = 28
                try:
                    scale_pre = float(scale_pre)
                except:
                    scale_pre = 5.0
                    self.cfg_scale_var.set("5.0")
                rescale_pre = self.prompt_guidance_rescale_entry.get()
                try:
                    rescale_pre = float(rescale_pre)
                except:
                    rescale_pre = 0
                    self.prompt_guidance_rescale_var.set("0")
                try:
                    steps = int(steps)
                except:
                    steps = 28
                    #self.cfg_scale_var.set("28")
                uncond_pre = self.uncond_strength_entry.get()
                try:
                    uncond_pre = float(uncond_pre)
                    uncond_pre = round(uncond_pre / 0.05) * 0.05
                    if (uncond_pre > 1.5):
                        uncond_pre = 1.5
                        self.uncond_strength_entry.delete(0, "end")
                        self.uncond_strength_entry.insert(0, "1.5")
                except:
                    uncond_pre = 1.0
                    self.uncond_strength_entry.delete(0, "end")
                    self.uncond_strength_entry.insert(0, "1.0")
                i2i_negative_text = self.negative_prompt_input.get("0.0", "end-1c")
                gen_request = {
                        "width":self.i2i_width,
                        "height":self.i2i_height,
                        "quality_toggle":self.auto_quality_toggle.get(),
                        "seed":request_seed if self.i2i_seed_hold_check == True else random.randint(0,9999999999),
                        "sampler":self.sampler_button.get(),
                        "scale":scale_pre,
                        "uncond_scale":uncond_pre,
                        "sema":self.sema_button.get(),
                        "sema_dyn": self.dyn_button.get(),
                        "cfg_rescale": rescale_pre,
                        "prompt": request_prompt,
                        "negative":i2i_negative_text,
                        "user_screen_size": self.get_max_size(),
                        "start_time": self.start_time,
                        "access_token": self.access_token,
                        "save_folder": self.output_file_path,
                        "png_rule": self.name_var.get(),
                        "type": "upper",
                        "steps": steps if steps <= 50 else 50,
                        "image": send_image,
                        "strength": round(self.i2i_value, 2),
                        "noise": 0
                    }
                def run_generation():
                        if gen_request["png_rule"] == "count":
                            self.generation_count += 1
                            gen_request["count"] =self.generation_count
                        self.state_label.configure(text ="state : img2img 요청됨 ", text_color = "#FFFF97")
                        result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request)
                        self.state_label.configure(text ="state : img2img 요청 반환됨", text_color = "#DCE4EE")
                        self.get_anlas()
                        if info:
                            temp = info.get('Comment', '')
                            temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','')
                        else:
                            temp = result_prompt
                        self.image_label_report.configure(state="normal")
                        self.image_label_report.delete("0.0", "end")
                        self.image_label_report.configure(text_color="#DCE4EE")
                        self.image_label_report.insert("0.0", temp)
                        self.image_label_report.configure(state="disabled")
                        if result_image:
                            if app.state() != 'zoomed':
                                instant_result_image = customtkinter.CTkImage(result_image, size=(620,620))
                            else:
                                current_image = Image.open(filename)
                                original_width, original_height = current_image.size
                                max_size = app.winfo_screenheight()-100
                                if original_width > max_size or original_height > max_size:
                                    new_image = Image.new("RGB", (max_size, max_size), "black")
                                    new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                                    instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                                else:
                                    instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                            self.image_label.configure(image=instant_result_image)
                            set_image_to_queue(result_image, result_prompt, str(result_seed), filename)
                generation_thread = threading.Thread(target=run_generation, daemon=True)
                generation_thread.start()
            
            def find_max_resolution(width, height, max_pixels=2166784, multiple_of=64):
                ratio = width / height

                max_width = int((max_pixels * ratio)**0.5)
                max_height = int((max_pixels / ratio)**0.5)

                max_width = (max_width // multiple_of) * multiple_of
                max_height = (max_height // multiple_of) * multiple_of

                while max_width * max_height > max_pixels:
                    max_width -= multiple_of
                    max_height = int(max_width / ratio)
                    max_height = (max_height // multiple_of) * multiple_of

                return (max_width, max_height)


            img = Image.open(current_lookup[3])
            width, height = img.size
            v = self.i2i_resolution
            if v == 0: 
                self.i2i_width = width
                self.i2i_height = height
            elif v == 1:
                self.i2i_width, self.i2i_height = find_max_resolution(width, height, 2166784)
            elif v == 2:
                self.i2i_width, self.i2i_height = find_max_resolution(width, height, 2662400)
            instant_image_generation(self)

        self.bind("<Up>", on_arrow_key)
        self.bind("<Down>", on_arrow_key)
        self.image_generation_repeat = 1
        self.image_generation_repeat_flag = False
        self.image_generation_repeat_current = 0
        self.wildcard_preopen_repeat = 1
        self.wildcard_preopen_repeat_flag = False
        self.wildcard_preopen_repeat_current = 1
        self.previous_fix_prompt = None
        self.i2i_value = 0.7
        self.i2i_seed_hold_check = True
        self.i2i_resolution = 0
        self.i2i_width = 0
        self.i2i_height = 0
        self.i2i_steps = 28
        self.image_label.drop_target_register(DND_ALL)
        self.image_label.dnd_bind("<<Drop>>", self.on_drop)
    #세상에 시발 이 위까지 전부 __init__에 들어가있음 
        
    
    def on_drop(self, event):
        def read_info_from_image_stealth(image):
            # trying to read stealth pnginfo
            width, height = image.size
            pixels = image.load()

            if image.mode != 'RGBA':
                return {}

            binary_data = ''
            buffer_a = ''
            index_a = 0
            confirming_signature = True
            reading_param_len = False
            reading_param = False
            read_end = False

            for x in range(width):
                for y in range(height):

                    r, g, b, a = pixels[x, y]
                    buffer_a += str(a & 1)
                    index_a += 1
                    
                    if confirming_signature and x == 0:
                        if y == 119: # index_a == len('stealth_pngcomp') * 8:
                            decoded_sig = bytearray(int(buffer_a[i:i + 8], 2) for i in
                                                    range(0, len(buffer_a), 8)).decode('utf-8', errors='ignore')
                            if decoded_sig == 'stealth_pngcomp':
                                confirming_signature = False
                                reading_param_len = True
                                buffer_a = ''
                                index_a = 0

                    elif reading_param_len:
                        if y == 151: # index_a == 32:
                            param_len = int(buffer_a, 2)
                            reading_param_len = False
                            reading_param = True
                            buffer_a = ''
                            index_a = 0

                    elif reading_param:
                        if index_a == param_len:
                            binary_data = buffer_a
                            read_end = True
                            break
                    else:
                        read_end = True
                        break

                if read_end:
                    break

            if binary_data != '':
                # Convert binary string to UTF-8 encoded text
                byte_data = bytearray(int(binary_data[i:i + 8], 2)
                                    for i in range(0, len(binary_data), 8))
                try:
                    decoded_data = gzip.decompress(
                        bytes(byte_data)).decode('utf-8')
                    return decoded_data
                except Exception as e:
                    print(e)
                    pass

            return {}

        def download_image_from_url(url):
            response = requests.get(url)
            response.raise_for_status()  # 에러가 발생했을 경우 예외를 던짐
            return Image.open(io.BytesIO(response.content))
        
        def extract_keywords_from_image(image):
            if image.info and image.info.get('dpi') is None:
                result = image.info.get('Comment', '')
                if result == '':
                    result = image.info.get('parameters', '')
                    if result != '':
                        try: 
                            result = json.loads(result)
                        except:
                            result = image.info.get('parameters', '')
                        return result
                    else:
                        self.image_label_report.configure(state="normal", text_color = "#FFFF97")
                        self.image_label_report.delete("0.0", "end")
                        self.image_label_report.insert("0.0", "<No Image Data Error> : 이미지에서 NAI 정보를 얻는데 실패하였습니다. 이미지에 메타데이터가 없습니다.")
                        self.image_label_report.configure(state="disabled")
                else:
                    return json.loads(result)
            else:
                stealth_info = read_info_from_image_stealth(image)
                if isinstance(stealth_info, str):
                    # 문자열 내의 모든 '\\'를 제거하거나 다른 문자로 대체
                    try:
                        result = stealth_info.replace("\\", "")
                        comment_data = json.loads(result)
                        return comment_data
                    except:
                        return stealth_info.replace("\\", "")
                elif stealth_info and 'Comment' in stealth_info:
                    try:
                        # Comment 값이 JSON 문자열인지 확인하고, 파싱
                        comment_data = json.loads(stealth_info['Comment'])
                        # 'prompt' 키의 값을 추출하여 반환
                        if 'prompt' in comment_data:
                            return comment_data["prompt"].strip()
                        else:
                            self.image_label_report.configure(state="normal", text_color = "#FFFF97")
                            self.image_label_report.delete("0.0", "end")
                            self.image_label_report.insert("0.0", "<Unsupported Image Type Error> : 이미지에서 NAI 정보를 얻는데 실패하였습니다. comment_data가 존재하지만 NAI와 호환되는 Stable Diffusion 이미지가 아닙니다.")
                            self.image_label_report.configure(state="disabled")
                    except json.JSONDecodeError:
                        self.image_label_report.configure(state="normal", text_color = "#FFFF97")
                        self.image_label_report.delete("0.0", "end")
                        self.image_label_report.insert("0.0", "<JSONDecodeError> : 이미지에서 NAI 정보를 얻는데 실패하였습니다.")
                        self.image_label_report.configure(state="disabled")
                else:
                    self.image_label_report.configure(state="normal", text_color = "#FFFF97")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<No Image Data Error> : 이미지에서 NAI 정보를 얻는데 실패하였습니다. 이미지에 메타데이터가 없습니다.")
                    self.image_label_report.configure(state="disabled")

        file_path_or_url = event.data
        file_path_or_url = file_path_or_url.strip("{}")
        from_url = False
        try:
            # URL의 유효성 검사
            if file_path_or_url.startswith(('http://', 'https://')):
                from_url = True
                img = download_image_from_url(file_path_or_url)
            else:
                if file_path_or_url.startswith(('blob:')):
                    self.image_label_report.configure(state="normal", text_color = "#FFFF97")
                    self.image_label_report.delete("0.0", "end")
                    self.image_label_report.insert("0.0", "<NAI Blob Image Error> : NAI 홈페이지에서 생성한 이미지는 NAIA로 즉시 복사할 수 없습니다. 이미지를 다운로드 한 뒤, 드래그 & 드랍을 통해 NAIA에 전달 해 주세요.")
                    self.image_label_report.configure(state="disabled")
                    return
                try:
                    img = Image.open(file_path_or_url)
                except:
                    try:
                        file_path_or_url = file_path_or_url.replace("\\", '')
                        img = Image.open(file_path_or_url)
                    except:
                        try:
                            file_path_or_url = file_path_or_url.replace("\\", '/')
                            img = Image.open(file_path_or_url)
                        except:
                            self.image_label_report.configure(state="normal", text_color = "#FFFF97")
                            self.image_label_report.delete("0.0", "end")
                            self.image_label_report.insert("0.0", f"<Unhandled exception> : Tkdnd2로부터 유효하지 않은 file path 또는 url : '{file_path_or_url}' 를 전달 받았습니다.")
                            self.image_label_report.configure(state="disabled")
                            return

            # 이미지 객체로부터 키워드 추출
            description = extract_keywords_from_image(img)
            if description == '' or description == None:
                return
            elif type(description) == type(' '):
                text_type, contents = 'str', description
                if '"Software": "NovelAI"' in contents:
                    software = 'NAI'
                else:
                    software = 'Local'
            else:
                text_type, contents = 'dict', description
                if 'sm' in contents:
                    software = 'NAI'
                else:
                    software = 'Local'

            #image window
            import_window = customtkinter.CTkToplevel()
            import_window.title("Image with Metadata found!")
            import_window.attributes('-topmost', True)
            import_window.resizable(width=False, height=False)

            import_window_left = customtkinter.CTkFrame(import_window)
            import_window_left.grid(row=0, column=0, pady=5, padx=5, sticky="nsew")
            import_window_right = customtkinter.CTkFrame(import_window, width=596)
            import_window_right.grid(row=0, column=1, pady=5, padx=5, sticky="nsew")

            width, height = img.size
            new_size = max(width, height)
            new_image = Image.new("RGB", (new_size, new_size), 'black')
            left = (new_size - width) // 2
            top = (new_size - height) // 2
            new_image.paste(img, (left, top))
    
            import_window_img = customtkinter.CTkImage(new_image, size=(576, 576))
            import_window_img_label = customtkinter.CTkLabel(import_window_left, text="", image=import_window_img)
            import_window_img_label.grid(row=0, column=0)

            if software == 'Local':
                local_prompt = customtkinter.CTkTextbox(import_window_right, height=576, width=586, font=customtkinter.CTkFont('Pretendard', 14))
                local_prompt.grid(row=0, column=0, pady=5, padx=5, sticky="nsew")
                contents = 'Image Type : Local Generated \n\n' + str(contents).replace('\n', '\n\n')
                local_prompt.insert("0.0", contents)
            else:
                if text_type == 'str':
                    try:
                        start_marker = '"Comment": "'
                        end_marker = '", "request_type"'
                        start_index = contents.find(start_marker) + len(start_marker)
                        end_index = contents.find(end_marker, start_index)
                        text = contents[start_index:end_index]
                        contents = {}
                    except:
                        local_prompt = customtkinter.CTkTextbox(import_window_right, height=766, width=766, font=customtkinter.CTkFont('Pretendard', 15))
                        local_prompt.grid(row=0, column=0, pady=5, padx=5, sticky="nsew")
                        contents = 'Image Type : Local Generated \n\n' + str(contents).replace('\n', '\n\n')
                        local_prompt.insert("0.0", contents)
                    try:
                        start_marker = 'prompt": "'
                        end_marker = '", "steps'
                        start_index = text.find(start_marker) + len(start_marker)
                        end_index = text.find(end_marker, start_index)
                        contents['prompt'] = text[start_index:end_index]
                        text = text[end_index:]
                    except:
                        pass
                    try:
                        start_marker = '"uc": "'
                        end_marker = '", "request_type'
                        start_index = text.find(start_marker) + len(start_marker)
                        end_index = text.find(end_marker, start_index)
                        contents['uc'] = text[start_index:]
                        text = text[:start_index]
                    except:
                        pass
                    keys = ["steps", "scale", "uncond_scale", "cfg_rescale", "seed", "sampler", "sm", "sm_dyn"]
                    for key in keys:
                        # 정규 표현식 패턴: key 다음에 나오는 : 공백을 포함한 후 어떤 값이든(숫자, 문자열 등) 매치
                        pattern = r'"{}":\s*([^,}}]+)'.format(key)
                        match = re.search(pattern, text)
                        
                        if match:
                            # 값을 추출 (그룹 1)
                            value = match.group(1)
                            
                            # 숫자이면 숫자로 변환, 그 외의 경우는 그대로 사용 (True, False, 문자열 등)
                            try:
                                # 정수, 실수 변환 시도
                                if '.' in value:
                                    contents[key] = float(value)
                                else:
                                    contents[key] = int(value)
                            except ValueError:
                                # boolean 변환 시도
                                if value.lower() == "true":
                                    contents[key] = True
                                elif value.lower() == "false":
                                    contents[key] = False
                                else:
                                    # 문자열 그대로 저장 (쌍따옴표 제거)
                                    contents[key] = value.strip('"')

                my_font = customtkinter.CTkFont('Pretendard', 13)
                large_font = customtkinter.CTkFont('Pretendard', 14)
                NAI_prompt_label = customtkinter.CTkLabel(import_window_right, width=586, font=my_font, text=" -------------------- 프롬프트 -------------------- ")
                NAI_prompt_label.grid(row=0, column=0, padx=5, sticky="nsew")
                NAI_prompt = customtkinter.CTkTextbox(import_window_right, width=586, height=205, font=large_font)
                NAI_prompt.grid(row=1, column=0, pady=5, padx=5, sticky="nsew")
                NAI_negative_label = customtkinter.CTkLabel(import_window_right, width=586, font=my_font, text=" --------------- 네거티브 프롬프트 --------------- ")
                NAI_negative_label.grid(row=2, column=0, padx=5, sticky="nsew")
                NAI_negative = customtkinter.CTkTextbox(import_window_right, width=586,height=130, font=large_font)
                NAI_negative.grid(row=3, column=0, pady=5, padx=5, sticky="nsew")
                NAI_prompt.insert("0.0", contents['prompt'])
                NAI_prompt.configure(state="disabled")
                NAI_negative.insert("0.0", contents['uc'])
                NAI_negative.configure(state="disabled")

                import_frame1 = customtkinter.CTkFrame(import_window_right, width=586, fg_color="#2B2B2B")
                import_frame1.grid(row=4, column=0, pady=5, padx=5, sticky="nsew")

                i_steps_label = customtkinter.CTkLabel(import_frame1, font=my_font, text="Steps : ")
                i_steps_label.grid(row=0, column=0, padx=5, sticky="nsew")
                i_steps = customtkinter.CTkEntry(import_frame1, font=my_font, width=35)
                i_steps.grid(row=0, column=1, padx=5, sticky="nsew")
                i_steps.insert(0, str(contents['steps']))
                i_steps.configure(state="disabled")

                i_scale_label = customtkinter.CTkLabel(import_frame1, font=my_font, text="CFG Scale : ")
                i_scale_label.grid(row=0, column=2, padx=5, sticky="nsew")
                i_scale = customtkinter.CTkEntry(import_frame1, font=my_font, width=40)
                i_scale.grid(row=0, column=3, padx=5, sticky="nsew")
                i_scale.insert(0, str(contents['scale']))
                i_scale.configure(state="disabled")

                i_uncond_label = customtkinter.CTkLabel(import_frame1, font=my_font, text="UC Strength : ")
                i_uncond_label.grid(row=0, column=4, padx=5, sticky="nsew")
                i_uncond = customtkinter.CTkEntry(import_frame1, font=my_font, width=40)
                i_uncond.grid(row=0, column=5, padx=5, sticky="nsew")
                i_uncond.insert(0, str(contents['uncond_scale']))
                i_uncond.configure(state="disabled")

                i_rescale_label = customtkinter.CTkLabel(import_frame1, font=my_font, text="CFG Rescale : ")
                i_rescale_label.grid(row=0, column=6, padx=5, sticky="nsew")
                i_rescale = customtkinter.CTkEntry(import_frame1, font=my_font, width=40)
                i_rescale.grid(row=0, column=7, padx=5, sticky="nsew")
                i_rescale.insert(0, str(contents['cfg_rescale']))
                i_rescale.configure(state="disabled")

                import_frame2 = customtkinter.CTkFrame(import_window_right, width=586, fg_color="#2B2B2B")
                import_frame2.grid(row=5, column=0, pady=5, padx=5, sticky="nsew")

                i_seed_label = customtkinter.CTkLabel(import_frame2, font=my_font, text="Steps : ")
                i_seed_label.grid(row=0, column=0, padx=5, sticky="nsew")
                i_seed = customtkinter.CTkEntry(import_frame2, font=my_font, width=100)
                i_seed.grid(row=0, column=1, padx=5, sticky="nsew")
                i_seed.insert(0, str(contents['seed']))

                i_sampler_label = customtkinter.CTkLabel(import_frame2, font=my_font, text="Steps : ")
                i_sampler_label.grid(row=0, column=2, padx=5, sticky="nsew")
                i_sampler = customtkinter.CTkEntry(import_frame2, font=my_font, width=100)
                i_sampler.grid(row=0, column=3, padx=5, sticky="nsew")
                i_sampler.insert(0, str(contents['sampler']))

                i_smea = customtkinter.CTkCheckBox(import_frame2, font=my_font, text="SMEA")
                i_smea.grid(row=0, column=4, padx=5, sticky="nsew")
                if contents['sm'] == True: 
                    i_smea.select() 
                else: 
                    i_smea.deselect()
                i_dyn = customtkinter.CTkCheckBox(import_frame2, font=my_font, text="SMEA+DYN")
                i_dyn.grid(row=0, column=5, padx=5, sticky="nsew")
                if contents['sm_dyn'] == True: 
                    i_dyn.select() 
                else: 
                    i_dyn.deselect()
                i_smea.configure(state="disabled")
                i_dyn.configure(state="disabled")

                import_frame3 = customtkinter.CTkFrame(import_window_right, width=586, fg_color="#2B2B2B")
                import_frame3.grid(row=6, column=0, pady=5, padx=5, sticky="nsew")

                i_resolution_label = customtkinter.CTkLabel(import_frame3, font=my_font, text="Resolution : ")
                i_resolution_label.grid(row=0, column=0, padx=5, sticky="nsew")
                i_resolution = customtkinter.CTkEntry(import_frame3, font=my_font, width=100)
                i_resolution.grid(row=0, column=1, padx=5, sticky="nsew")
                i_resolution.insert(0, f"{width} x {height}")

                import_frame4 = customtkinter.CTkFrame(import_window_right, width=586, fg_color="#2B2B2B")
                import_frame4.grid(row=7, column=0, pady=10, padx=5, sticky="n")

                def image_to_base64(image):
                    image_bytesIO = io.BytesIO()
                    image.save(image_bytesIO, format="PNG")
                    return base64.b64encode(image_bytesIO.getvalue()).decode()

                def save_base64_image(base64_string):
                    image_data = base64.b64decode(base64_string)
                    output_file_path = f"output_NAI\\{self.start_time}\\import"
                    d = Path(output_file_path)
                    d.mkdir(parents=True, exist_ok=True)
                    filename = (d / f"{app.import_image_count:05}.png" )
                    filename.write_bytes(image_data)
                    return filename

                def image_to_queue():
                    if from_url == True:
                        base64_string = image_to_base64(img)
                        filename = save_base64_image(base64_string)
                        app.ext_set_image_to_queue(new_image.copy(), contents['prompt'], str(contents['seed']), filename)
                        app.import_image_count += 1
                    else:
                        app.ext_set_image_to_queue(new_image.copy(), contents['prompt'], str(contents['seed']), file_path_or_url)
                    app.import_image_negative[len(app.image_queue)-1] = contents['uc']

                import_image_to_queue = customtkinter.CTkButton(import_frame4, font=my_font, text="이미지/프롬프트를 큐에 삽입", command=image_to_queue)
                import_image_to_queue.grid(row=0, column=0, padx=5, sticky="nsew")
                if text_type == 'str':
                    import_image_to_queue.configure(state="disabled")

                def prompt_insert():
                    app.text_input.delete("0.0", "end")
                    app.text_input.insert("0.0", contents['prompt'])
                    app.negative_prompt_input.delete("0.0", "end")
                    app.negative_prompt_input.insert("0.0", contents['uc'])
                    app.automation_button.deselect()

                import_prompts = customtkinter.CTkButton(import_frame4, font=my_font, text="프롬프트/네거티브 삽입", fg_color="grey", hover_color="grey10", command=prompt_insert)
                import_prompts.grid(row=0, column=1, padx=5, sticky="nsew")

                # ["steps", "scale", "uncond_scale", "cfg_rescale", "seed", "sampler", "sm", "sm_dyn"
                def settings_insert():
                    app.cfg_scale_var.set(str(contents['scale']))
                    app.cfg_scale_entry.delete(0, "end")
                    app.cfg_scale_entry.insert(0, str(contents['scale']))
                    app.uncond_strength_entry.delete(0, "end")
                    app.uncond_strength_entry.insert(0, str(contents['uncond_scale']))
                    app.prompt_guidance_rescale_var.set(str(contents['cfg_rescale']))
                    app.prompt_guidance_rescale_entry.delete(0, "end")
                    app.prompt_guidance_rescale_entry.insert(0, str(contents['cfg_rescale']))
                    app.seed_fix_button.select()
                    app.seed_entry.delete(0, "end")
                    app.seed_entry.insert(0, str(contents['seed']))
                    app.sampler_var.set(contents['sampler'])
                    app.sampler_button.set(contents['sampler'])
                    if contents['sm'] == True: 
                        app.sema_button.select()
                    else: 
                        app.sema_button.deselect()
                    if contents['sm_dyn'] == True: 
                        app.dyn_button.select()
                    else: 
                        app.dyn_button.deselect()
                    app.random_resolution_button.deselect()
                    app.resolution_button.set(f"{width} x {height}")
                    app.resolution_var.set(f"{width} x {height}")
                    app.cond_negative_button.deselect()
                    app.automation_button.deselect()

                import_settings = customtkinter.CTkButton(import_frame4, font=my_font, text="설정값 일괄 삽입", fg_color="#F5F3C2", hover_color="#A69F40", text_color="black", command=settings_insert)
                import_settings.grid(row=0, column=2, padx=5, sticky="nsew")




            import_window.after(1500, lambda: import_window.attributes('-topmost', False))

        except Exception as e:
            self.image_label_report.configure(state="normal", text_color = "#FFFF97")
            self.image_label_report.delete("0.0", "end")
            self.image_label_report.insert("0.0", f"Error: {e}")
            self.image_label_report.configure(state="disabled")



    def ext_set_image_to_queue(self, imagen, prompt, seed, filename):
        self.image_queue.append([imagen, prompt, seed, filename])
        #self.history_export.configure(text=f"export ({len(self.image_queue)})")
        self.request_upper_size_button.configure(state="normal")
        self.current_window = self.window
        if self.window == len(self.image_queue)-1:
            self.window+=1
            self.update()
        show_text = str(self.window)+" / "+ str(len(self.image_queue))
        
        self.window_label.configure(text=show_text)

    def update(self):
        if len(self.image_queue) <= 5:
            if len(self.image_queue) >= 1:
                self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
            if len(self.image_queue) >= 2:
                self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
                self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100)))
            if len(self.image_queue) >= 3:
                self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
                self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100)))
                self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100)))
            if len(self.image_queue) >= 4:
                self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
                self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100)))
                self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100)))
                self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100)))
            if len(self.image_queue) == 5:
                self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
                self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100)))
                self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100)))
                self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100)))
                self.image_history_4.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-5][0], size=(100,100)))
        else:
            self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100)))
            self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100)))
            self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100)))
            self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100)))
            self.image_history_4.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-5][0], size=(100,100)))
        if len(self.image_queue) == 6:
            self.image_history_button_down.configure(state="normal")

    

    def save_settings(self):
        settings = {
            "NAI_ID": self.NAI_ID if self.NAI_ID else " ",
            "access_token": self.access_token if self.access_token else " ",
            "searach_keyword": self.search_label_entry.get() if len(self.search_label_entry.get()) > 3 else " ",
            "exclude_keyword": self.exclude_label_entry.get() if len(self.exclude_label_entry.get()) > 3 else " ",
            "explicit": self.rating_select_explicit.get(),
            "nsfw": self.rating_select_nsfw.get(),
            "sensitive": self.rating_select_sensitive.get(),
            "general": self.rating_select_general.get(),
            "rm_artist": self.rm_artist_name_button.get(),
            "rm_copyright": self.rm_copyright_name_button.get(),
            "rm_character": self.rm_characteristic_button.get(),
            "prompt": self.text_input.get("0.0", "end-1c") if len(self.text_input.get("0.0", "end")) > 4 else " ",
            "negative": self.negative_prompt_input.get("0.0", "end-1c") if len(self.negative_prompt_input.get("0.0", "end")) > 4 else " ",
            "fix": self.fixed_prompt_input.get("0.0", "end-1c") if len(self.fixed_prompt_input.get("0.0", "end")) > 4 else " ",
            "after": self.fixed_prompt_after_input.get("0.0", "end-1c") if len(self.fixed_prompt_after_input.get("0.0", "end")) > 4 else " ",
            "auto_hide": self.auto_hide_keyword_input.get("0.0", "end-1c") if len(self.auto_hide_keyword_input.get("0.0", "end")) > 4 else " ",
            "cfg_scale": str(self.cfg_scale_entry.get()),
            "uncond_scale": str(self.uncond_strength_entry.get()),
            "guidance": str(self.prompt_guidance_rescale_entry.get()),
            "sampler": self.sampler_var.get(),
            "random": self.random_resolution_button.get(),
            "sema": self.sema_button.get(),
            "dyn": self.dyn_button.get(),
            "personal_folder":self.output_file_path_personal,
            "save_folder":self.output_file_path if self.output_file_path_personal else " ",
            "png_rule":self.name_var.get(),
            "quality_toggle":self.auto_quality_toggle.get(),
            "cond_prompt": self.conditional_prompt_input.get("0.0", "end-1c") if len(self.conditional_prompt_input.get("0.0", "end")) > 4 else " ",
            "cond_negative": self.conditional_negative_input.get("0.0", "end-1c") if len(self.conditional_negative_input.get("0.0", "end")) > 4 else " ",
            "activate_cond_prompt": self.cond_prompt_button.get(),
            "activate_cond_negative": self.cond_negative_button.get(),
            "prompt_rating": self.current_prompt_rating,
            "resolution": self.resolution_button.get(),
            "wildcard_preopen": self.toggle_wildcard_preopen.get(),
            "i2i": [self.i2i_value, self.i2i_seed_hold_check, self.i2i_resolution]
        }
        with open('app_settings.json', 'w', encoding='utf-8') as f:
            json.dump(settings, f, ensure_ascii=False, indent=4)
        if type(self.cached_rows) != type(None) and not self.cached_rows.empty:
            self.cached_rows.to_parquet('txt2img_temp_prompt.parquet')
        #print("finished")

    def load_settings(self):
        if os.path.exists('app_settings.json'):
            with open('app_settings.json', 'r', encoding='utf-8') as f:
                try:
                    settings = json.load(f)
                    try:
                        self.NAI_ID = settings["NAI_ID"] if len(settings["NAI_ID"]) > 2 else None
                    except: pass
                    try:
                        self.access_token = settings["access_token"] if len(settings["access_token"]) > 2 else None
                        if self.access_token:
                            self.NAI_Account_Login.configure(state="disabled")
                            self.NAI_Token_Remove.configure(state="normal")
                            self.NAI_Account_State.configure(text="NAI Login : OK")
                            self.image_generation_button.configure(state="normal")
                    except: pass
                    try:
                        self.search_label_entry.insert(0, settings["searach_keyword"])
                    except: pass
                    try:
                        self.exclude_label_entry.insert(0, settings["exclude_keyword"])
                    except: pass
                    try:
                        self.rating_select_var_explicit.set(settings["explicit"])
                        if settings["explicit"] == 1: self.rating_select_explicit.select() 
                        else: self.rating_select_explicit.deselect()
                    except: pass
                    try:
                        self.rating_select_var_nsfw.set(settings[ "nsfw"])
                        if settings["nsfw"] == 1: self.rating_select_nsfw.select() 
                        else: self.rating_select_nsfw.deselect()
                    except: pass
                    try:
                        self.rating_select_var_sensitive.set(settings["sensitive"])
                        if settings["sensitive"] == 1: self.rating_select_sensitive.select() 
                        else: self.rating_select_sensitive.deselect()
                    except: pass
                    try:
                        self.rating_select_var_general.set(settings["general"])
                        if settings["general"] == 1: self.rating_select_general.select() 
                        else: self.rating_select_general.deselect()
                    except: pass
                    try:
                        self.rm_artist_name_var = settings["rm_artist"]
                        if settings["rm_artist"] == 1: self.rm_artist_name_button.select()
                        else: self.rm_artist_name_button.deselect()
                    except: pass
                    try:
                        self.rm_copyright_name_var = settings["rm_copyright"]
                        if settings["rm_copyright"] == 1: self.rm_copyright_name_button.select()
                        else: self.rm_copyright_name_button.deselect()
                    except: pass
                    try:
                        self.rm_characteristic_var = settings["rm_character"]
                        if settings["rm_character"] == 1: self.rm_characteristic_button.select()
                        else: self.rm_characteristic_button.deselect()
                    except: pass
                    try:
                        self.text_input.insert("0.0", settings["prompt"])
                    except: pass
                    try:
                        self.negative_prompt_input.delete("0.0", "end")
                        self.negative_prompt_input.insert("0.0", settings["negative"])
                    except: pass
                    try:
                        self.fixed_prompt_input.insert("0.0", settings["fix"])
                    except: pass
                    try:
                        self.fixed_prompt_after_input.insert("0.0", settings["after"])
                    except: pass
                    try:
                        self.auto_hide_keyword_input.insert("0.0", settings[ "auto_hide"])
                    except: pass
                    try:
                        self.cfg_scale_entry.delete(0, "end")
                        self.cfg_scale_entry.insert(0, str(settings["cfg_scale"]))
                        self.cfg_scale_var.set(settings["cfg_scale"])
                    except: pass
                    try:
                        self.prompt_guidance_rescale_entry.delete(0, "end")
                        self.prompt_guidance_rescale_entry.insert(0, str(settings["guidance"]))
                        self.prompt_guidance_rescale_var.set(settings["guidance"])
                    except: pass
                    try:
                        self.sampler_var.set(settings["sampler"])
                        self.sampler_button.set(settings["sampler"])
                    except: pass
                    try:
                        self.random_resolution_var.set(settings["random"])
                        if settings["random"] == 1: self.random_resolution_button.select()
                        else: self.random_resolution_button.deselect()
                    except: pass
                    try:
                        self.sema_button_var.set(settings["sema"])
                        if settings["sema"] == 1: self.sema_button.select()
                        else: self.sema_button.deselect()
                    except: pass
                    try:
                        self.dyn_button_var.set(settings["dyn"])
                        if settings["dyn"] == 1: self.dyn_button.select()
                        else: self.dyn_button.deselect()
                    except: pass
                    try:
                        if settings["personal_folder"] == True: 
                            self.output_file_path_personal =True
                            self.output_file_path = settings["save_folder"]
                        else: self.output_file_path_personal =False
                    except: pass
                    try:
                        self.name_var.set(settings["png_rule"])
                    except: pass
                    try:
                        self.auto_quality_toggle_var=settings["quality_toggle"]
                        if settings["quality_toggle"] == 1: self.auto_quality_toggle.select()
                        else: self.auto_quality_toggle.deselect()
                    except: pass
                    try:
                        self.conditional_prompt_input.insert("0.0", settings[ "cond_prompt"])
                    except: pass
                    try:
                        self.conditional_negative_input.insert("0.0", settings[ "cond_negative"])
                    except: pass
                    try:
                        self.cond_prompt_button_var.set(settings["activate_cond_prompt"])
                        if settings["activate_cond_prompt"] == 1: self.cond_prompt_button.select()
                        else: self.cond_prompt_button.deselect()
                    except: pass
                    try:
                        self.cond_prompt_button_var.set(settings["activate_cond_negative"])
                        if settings["activate_cond_negative"] == 1: self.cond_negative_button.select()
                        else: self.cond_negative_button.deselect()
                    except: pass
                    try:
                        self.current_prompt_rating = settings["prompt_rating"]
                    except: pass
                    try:
                        self.resolution_var.set(settings["resolution"])
                        self.resolution_button.set(settings["resolution"])
                    except: pass
                    try:
                        self.toggle_wildcard_preopen_var.set(settings["wildcard_preopen"])
                        if settings["wildcard_preopen"] == 1: self.toggle_wildcard_preopen.select()
                        else: self.toggle_wildcard_preopen.deselect()
                    except: pass
                    try:
                        self.uncond_strength_entry.delete(0, "end")
                        self.uncond_strength_entry.insert(0, settings["uncond_scale"])
                    except: pass
                    try:
                        self.i2i_value, self.i2i_seed_hold_check, self.i2i_resolution = settings["i2i"][0], settings["i2i"][1],settings["i2i"][2]
                    except: pass
                except json.JSONDecodeError as e:
                    self.image_label_report.configure(state="normal", text_color = "#FFFF97")
                    self.image_label_report.insert("0.0", "세이브 파일을 불러오는데 실패하였습니다 : " + str(e))
                    self.image_label_report.configure(state="disabled")
        if os.path.exists('txt2img_temp_prompt.parquet'):
            try:
                self.cached_rows = pd.read_parquet('txt2img_temp_prompt.parquet')
                self.cached_prompt_label.configure(text = "남은 프롬프트 행 : "+str(len(self.cached_rows)))
                if 'id' not in self.cached_rows.columns:
                    self.image_label_report.configure(state="normal", text_color = "#FFFF97")
                    self.image_label_report.insert("0.0", "<TagsError> 0215 버전부터 tags의 구성이 변경되었습니다. favorite 기능을 사용하기 위해 검색을 다시 수행 해 주세요.")
                    self.image_label_report.configure(state="disabled")
            except: pass

    def exit_program(self):
        self.save_settings()
        app.destroy()

    def get_max_size(self):
        width = self.winfo_screenheight()
        return 768 if width < 1440 else 768

    def update_fullscreen_image(self,new_window, new_image_label):
        last_updated_image = None
        while True: 
            time.sleep(1) 
            if not new_window.winfo_exists():
                break
            if self.image_queue:
                current_image = Image.open(self.image_queue[self.window-1][3])
                if current_image and current_image != last_updated_image:
                    #resized_image = self.resize_image_to_fit(current_image, new_window.winfo_screenheight())
                    original_width, original_height = current_image.size
                    ratio = new_window.winfo_screenheight() / float(original_height)
                    new_width = int(original_width * ratio)
                    tk_image = customtkinter.CTkImage(current_image, size=(new_width,new_window.winfo_screenheight()))
                    new_window.after(0, lambda img=tk_image: new_image_label.configure(image=img))
                    new_image_label.image = tk_image
                    last_updated_image = current_image

    def show_fullscreen_image(self):
        new_window = customtkinter.CTkToplevel()
        new_window.attributes('-fullscreen', True)
        new_window.state('zoomed')
        new_window.configure(bg='black')

        new_image_label = customtkinter.CTkLabel(new_window, text=" ") 
        new_image_label.pack(expand=True, fill='both')
        new_window.bind("<Escape>", lambda e: new_window.destroy())

        update_thread = threading.Thread(target=self.update_fullscreen_image, args=(new_window, new_image_label), daemon=True)
        update_thread.daemon = True  
        update_thread.start()

    def resize_image_to_fit(self, image, target_height):
        original_width, original_height = image.size

        ratio = target_height / float(original_height)
        new_width = int(original_width * ratio)

        resized_image = image.resize((new_width, target_height), Image.Resampling.LANCZOS)
        return resized_image
    
    def open_prompt_window(self):
        prompt_window = customtkinter.CTkToplevel()
        prompt_window.title("추천 프롬프트")
        prompt_window.attributes('-topmost', True)
        prompt_window.resizable(width=False, height=False)

        text_label1 = customtkinter.CTkLabel(prompt_window, text="검색 결과 내 고빈도 키워드", font=customtkinter.CTkFont('Pretendard', 13), width=500)
        text_label1.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
        text_output1 = customtkinter.CTkTextbox(prompt_window, height=250, width=350, font=customtkinter.CTkFont('Pretendard', 15))
        text_output1.grid(row=1, column=0, padx=5, pady=5, sticky="nsew")

        text_label2 = customtkinter.CTkLabel(prompt_window, text="검색 결과 내 작가명 순위", font=customtkinter.CTkFont('Pretendard', 13), width=500)
        text_label2.grid(row=2, column=0, padx=5, pady=5, sticky="nsew")
        text_output2 = customtkinter.CTkTextbox(prompt_window, height=250, width=350, font=customtkinter.CTkFont('Pretendard', 15))
        text_output2.grid(row=3, column=0, padx=5, pady=5, sticky="nsew")

        text_label3 = customtkinter.CTkLabel(prompt_window, text="많이 사용된 캐릭터 순위", font=customtkinter.CTkFont('Pretendard', 13), width=500)
        text_label3.grid(row=4, column=0, padx=5, pady=5, sticky="nsew")
        text_output3 = customtkinter.CTkTextbox(prompt_window, height=250, width=350, font=customtkinter.CTkFont('Pretendard', 15))
        text_output3.grid(row=5, column=0, padx=5, pady=5, sticky="nsew")

        if type(self.cached_rows) != type(None) and not self.cached_rows.empty:
            counts1 = Counter()
            ndf = self.cached_rows[self.cached_rows['general'].notnull()]
            for row in ndf['general']:
                if row != None:
                    substrings = [substring.strip() for substring in row.split(',') if substring.strip()]
                    counts1.update(substrings)
            top_200_keywords = counts1.most_common(200)
            formatted_keywords = [f"{keyword}: {count}" for keyword, count in top_200_keywords]
            formatted_text = "\n".join(formatted_keywords)
            text_output1.insert("0.0", formatted_text)
            del[ndf]

            counts2 = Counter()
            ndf = self.cached_rows[self.cached_rows['artist'].notnull()]
            for row in ndf['artist']:
                if row != None:
                    substrings = [substring.strip() for substring in row.split(',') if substring.strip()]
                    counts2.update(substrings)
            top_200_keywords = [(keyword, count) for keyword, count in counts2.most_common(200) if keyword in artist_dict]
            formatted_keywords = [f"{keyword}: {count}" for keyword, count in top_200_keywords]
            formatted_text = "\n".join(formatted_keywords)
            text_output2.insert("0.0", formatted_text)
            del[ndf]

            counts3 = Counter()
            ndf = self.cached_rows[self.cached_rows['character'].notnull()]
            for row in ndf['character']:
                if row != None:
                    substrings = [substring.strip() for substring in row.split(',') if substring.strip()]
                    counts3.update(substrings)
            top_200_keywords = counts3.most_common(200)
            formatted_keywords = [f"{keyword}: {count}" for keyword, count in top_200_keywords]
            formatted_text = "\n".join(formatted_keywords)
            text_output3.insert("0.0", formatted_text)
            del[ndf]

        
    def random_artist_window(self):
        rartist_window = customtkinter.CTkToplevel()
        rartist_window.title("랜덤 작가명 설정")
        rartist_window.attributes('-topmost', True)
        rartist_window.resizable(width=False, height=False)

        rartist_window_left = customtkinter.CTkFrame(rartist_window, width=250)
        rartist_window_left.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
        #rartist_window_right = customtkinter.CTkFrame(rartist_window, width=250)
        #rartist_window_right.grid(row=0, column=1, padx=5, pady=5, sticky="nsew")
        text_label1 = customtkinter.CTkLabel(rartist_window_left, text="랜덤 작가 삽입 방법 선택", font=customtkinter.CTkFont('Pretendard', 13), width=250)
        text_label1.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
        self.random_artist_select = customtkinter.StringVar()
        ramdom_artist_global = customtkinter.CTkRadioButton(rartist_window_left, text="전체 작가명 리스트에서", variable=self.random_artist_select, value="global", font=customtkinter.CTkFont('Pretendard', 13))
        ramdom_artist_global.grid(row=1, column=0, padx=5, pady=5, sticky="w")
        ramdom_artist_local = customtkinter.CTkRadioButton(rartist_window_left, text="검색 프롬프트 안에서", variable=self.random_artist_select, value="local", font=customtkinter.CTkFont('Pretendard', 13))
        ramdom_artist_local.grid(row=2, column=0, padx=5, pady=5, sticky="w")
        text_label2 = customtkinter.CTkLabel(rartist_window_left, text="단부루 내 최소 이미지 수 설정(최소: 80)", font=customtkinter.CTkFont('Pretendard', 13), width=250)
        text_label2.grid(row=3, column=0, padx=5, pady=5, sticky="nsew")
        self.danbooru_minimum = customtkinter.IntVar(value=80)
        danbooru_entry = customtkinter.CTkEntry(rartist_window_left, textvariable=self.danbooru_minimum,  font=customtkinter.CTkFont('Pretendard', 13), width=50)
        danbooru_entry.grid(row=4, column=0, padx=5, pady=5, sticky="n")
        danbooru_set = customtkinter.CTkButton(rartist_window_left, text="새로 탑재",font=customtkinter.CTkFont('Pretendard', 13), width=50, command=self.get_artist)
        danbooru_set.grid(row=5, column=0, padx=5, pady=5, sticky="n")
        self.random_artist_list_length = customtkinter.CTkLabel(rartist_window_left, text="total length : 0", font=customtkinter.CTkFont('Pretendard', 13), width=250)
        self.random_artist_list_length.grid(row=6, column=0, padx=5, pady=5, sticky="nsew")
        text_label3 = customtkinter.CTkLabel(rartist_window_left, text="작가명 삽입 방식", font=customtkinter.CTkFont('Pretendard', 13), width=250)
        text_label3.grid(row=7, column=0, padx=5, pady=5, sticky="nsew")
        random_artist_radio1 = customtkinter.CTkRadioButton(rartist_window_left, text="앞에 artist: 붙이기", variable=self.random_artist_prefix, value="artist:", font=customtkinter.CTkFont('Pretendard', 13))
        random_artist_radio1.grid(row=8, column=0, padx=5, pady=5, sticky="w")
        random_artist_radio2 = customtkinter.CTkRadioButton(rartist_window_left, text="뒤에 (artist) 붙이기", variable=self.random_artist_prefix, value="(artist)", font=customtkinter.CTkFont('Pretendard', 13))
        random_artist_radio2.grid(row=9, column=0, padx=5, pady=5, sticky="w")
        random_artist_radio3 = customtkinter.CTkRadioButton(rartist_window_left, text="기본 스타일로", variable=self.random_artist_prefix, value="none", font=customtkinter.CTkFont('Pretendard', 13))
        random_artist_radio3.grid(row=10, column=0, padx=5, pady=5, sticky="w")
        self.random_artist_list = customtkinter.CTkTextbox(rartist_window_left, height=350, width=250, font=customtkinter.CTkFont('Pretendard', 15))
        self.random_artist_list.grid(row=11, column=0, padx=5, pady=5, sticky="nsew")
        text_label4 = customtkinter.CTkLabel(rartist_window_left, text="고정 프롬프트에서는 <random_artist>로 호출", font=customtkinter.CTkFont('Pretendard', 13), width=250)
        text_label4.grid(row=12, column=0, padx=5, pady=5, sticky="nsew")

        #TODO : 정규식 기반의 랜덤작가 인원/브래킷 관리 기능 추가
        #text_label4 = customtkinter.CTkLabel(rartist_window_right, text="랜덤작가 수 가중치", font=customtkinter.CTkFont('Pretendard', 13), width=250)
        #text_label4.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
        #text_label5 = customtkinter.CTkLabel(rartist_window_right, text="가중치:int, 작가수(int), ", font=customtkinter.CTkFont('Pretendard', 13), width=250)
        #text_label5.grid(row=1, column=0, padx=5, pady=5, sticky="nsew")

    def reactivate_wildcards(self):
        self.activate_wildcards()
        pretty_string = ""
        for key, value in self.wildcard_dict.items():
            pretty_string += f"{key}: {value}\n"
        self.wildcard_text.configure(state="normal")
        self.wildcard_text.delete('0.0', "end")
        self.wildcard_text.insert('0.0', pretty_string)
        self.wildcard_text.configure(state="disabled")

    def open_wildcard_folder(self):
        if not os.path.exists(self.wildcards_dir):
            os.makedirs(self.wildcards_dir)
        os.startfile(self.wildcards_dir)

    def open_wildcard_window(self):
        wildcard_window = customtkinter.CTkToplevel()
        wildcard_window.title("와일드카드 관리")
        wildcard_window.attributes('-topmost', True)
        wildcard_window.resizable(width=False, height=False)

        wildcard_window_left = customtkinter.CTkFrame(wildcard_window)
        wildcard_window_left.grid(row=0, column=0, sticky="nsew")
        wildcard_window_right = customtkinter.CTkFrame(wildcard_window)
        wildcard_window_right.grid(row=0, column=1, sticky="nsew")

        text_label_frame = customtkinter.CTkFrame(wildcard_window_right, fg_color="#2B2B2B")
        text_label_frame.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
        text_label3 = customtkinter.CTkLabel(text_label_frame, text="와일드카드 관리", font=customtkinter.CTkFont('Pretendard', 13), width=300)
        text_label3.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
        text_hyperlink = customtkinter.CTkLabel(text_label_frame, text="가이드 열기 (arca.live)", font=customtkinter.CTkFont('Pretendard', 13), width=180, text_color="lightblue", cursor="hand2")
        text_hyperlink.grid(row=0, column=1, padx=5, pady=5, sticky="nsew")
        text_hyperlink.bind("<Button-1>", lambda e: webbrowser.open_new("https://arca.live/b/aiart/95877361"))

        def wildcard_folder_callback(choice):
            if choice != '':
                if choice != '(+) 폴더 추가':
                    value = list(self.wildcard_dict[wildcard_folder_select_var.get()])+['(+) 새 와일드카드']
                    wildcard_folder_select_var.set(choice)
                    wildcard_file_select.configure(values=value)
                    wildcard_file_select.set('')
                else:
                    value = list(self.wildcard_dict.keys())
                    dialog = customtkinter.CTkInputDialog(text="새 와일드카드 폴더명을 입력하세요 (같은 이름 불가):", title="폴더 생성")
                    input_value = dialog.get_input()
                    if input_value and input_value not in value:
                        os.makedirs(self.wildcards_dir+'/'+input_value)
                        self.reactivate_wildcards()
                        wildcard_folder_select.configure(values=list(self.wildcard_dict.keys())+['(+) 폴더 추가'])
                        wildcard_folder_select.set(input_value)
                        wildcard_file_select.set('')
                    else:
                        wildcard_folder_select.set('')


        def wildcard_select_callback(choice):
            if choice != '':
                if choice == '(+) 새 와일드카드':
                    value = list(self.wildcard_dict[wildcard_folder_select_var.get()])
                    dialog = customtkinter.CTkInputDialog(text="새 와일드카드의 이름을 입력하세요 (같은 이름 불가):", title="와일드카드 생성")
                    input_value = dialog.get_input()
                    if input_value and input_value not in value:
                        filepath = self.wildcards_dir+'/'+input_value if wildcard_folder_select_var.get() == "none" else self.wildcards_dir+'/'+wildcard_folder_select_var.get()+'/'+input_value
                        with open(filepath+'.txt', 'w') as file:
                            pass
                    self.reactivate_wildcards()
                    value2 = list(self.wildcard_dict[wildcard_folder_select_var.get()])+['(+) 새 와일드카드']
                    wildcard_file_select.configure(values=value2)
                    wildcard_file_select.set('')
                else:
                    self.wildcard_file_select_var = choice if wildcard_folder_select_var.get() == "none" else wildcard_folder_select_var.get()+'/'+choice
                    filepath = self.wildcards_dir+'/'+choice if wildcard_folder_select_var.get() == "none" else self.wildcards_dir+'/'+wildcard_folder_select_var.get()+'/'+choice
                    if os.path.exists(filepath):
                        with open(filepath, 'r', encoding='utf-8') as file:
                            lines = file.readlines()
                        updated_lines = []
                        for line in lines:
                            line = line.strip()
                            updated_lines.append(line)
                        wildcard_select_text.configure(state="normal")
                        wildcard_select_text.delete("0.0","end")
                        wildcard_select_text.insert("0.0", '\n'.join(updated_lines))
                        wildcard_select_text.configure(state="disabled")
                    self.current_wildcard_path  = filepath

        def fix_wildcard():
            if fix_button.cget("text") == "수정":
                save_button.configure(state="normal")
                wildcard_select_text.configure(state="normal")
                fix_button.configure(text="취소")
                wildcard_folder_select.configure(state="disabled")
                wildcard_file_select.configure(state="disabled")
                coy_button.configure(state="disabled")
            elif fix_button.cget("text") == "취소":
                save_button.configure(state="disabled")
                wildcard_select_text.configure(state="disabled")
                fix_button.configure(text="수정")
                wildcard_folder_select.configure(state="normal")
                wildcard_file_select.configure(state="normal")
                coy_button.configure(state="normal")

        def save_wildcard():
            text = wildcard_select_text.get("1.0", "end-1c")
            with open(self.current_wildcard_path, "w", encoding="utf-8") as file:
                file.write(text)
            wildcard_select_text.configure(state="disabled")
            fix_button.configure(text="수정")
            wildcard_folder_select.configure(state="normal")
            wildcard_file_select.configure(state="normal")
            coy_button.configure(state="normal")
            save_button.configure(state="disabled")

        def copy_wildcard():
            text = self.wildcard_file_select_var
            text = text.replace(".txt","")
            pyperclip.copy('<'+text+'>')
        
        wildcard_window_select_frame = customtkinter.CTkFrame(wildcard_window_right)
        wildcard_window_select_frame.grid(row=1, column=0, sticky="n")
        text_label4 = customtkinter.CTkLabel(wildcard_window_select_frame, text="폴더 선택:", font=customtkinter.CTkFont('Pretendard', 13))
        text_label4.grid(row=0, column=0, padx=15, pady=5, sticky="nsew")
        text_label5 = customtkinter.CTkLabel(wildcard_window_select_frame, text="파일 선택:", font=customtkinter.CTkFont('Pretendard', 13))
        text_label5.grid(row=0, column=2, padx=15, pady=5, sticky="nsew")
        wildcard_folder_select_var = customtkinter.StringVar(value="none")
        wildcard_folder_select = customtkinter.CTkComboBox(wildcard_window_select_frame,values=list(self.wildcard_dict.keys())+['(+) 폴더 추가'],command=wildcard_folder_callback, variable=wildcard_folder_select_var, font=customtkinter.CTkFont('Pretendard', 13))
        wildcard_folder_select.grid(row=0, column=1, padx=15, pady=5, sticky="nsew")
        self.wildcard_file_select_var = ""
        self.current_wildcard_path = ""
        wildcard_file_select = customtkinter.CTkComboBox(wildcard_window_select_frame,values=list(self.wildcard_dict[wildcard_folder_select_var.get()])+['(+) 새 와일드카드'],command=wildcard_select_callback, font=customtkinter.CTkFont('Pretendard', 13))
        wildcard_file_select.grid(row=0, column=3, padx=15, pady=5, sticky="nsew")
        wildcard_file_select.set("")
        text_label6 = customtkinter.CTkLabel(wildcard_window_select_frame, text="폴더 및 파일의 삭제기능은 제공되지 않습니다. 와일드카드 폴더에서 직접 삭제하세요.", font=customtkinter.CTkFont('Pretendard', 13))
        text_label6.grid(row=1, column=0, columnspan=4, padx=5, pady=5, sticky="n")
        fix_button = customtkinter.CTkButton(wildcard_window_select_frame, text="수정", font=customtkinter.CTkFont('Pretendard', 13), width=100, hover_color="grey10", command=fix_wildcard)
        fix_button.grid(row=2, column=0, padx=15, pady=5, sticky="n")
        save_button = customtkinter.CTkButton(wildcard_window_select_frame, text="저장", font=customtkinter.CTkFont('Pretendard', 13), width=100, fg_color="grey", hover_color="grey10", command=save_wildcard, state="disabled")
        save_button.grid(row=2, column=1, padx=15, pady=5, sticky="n")
        coy_button = customtkinter.CTkButton(wildcard_window_select_frame, text="<와일드카드>를 클립보드에 복사", font=customtkinter.CTkFont('Pretendard', 13), fg_color="#7030A0", hover_color="#481F67", command=copy_wildcard)
        coy_button.grid(row=2, column=2, columnspan=2, padx=5, pady=5, sticky="n")
        text_label7 = customtkinter.CTkLabel(wildcard_window_right, text="<UserAttention> Enter 입력시 다른 행으로 취급됩니다. 수정 후 꼭 저장 버튼을 누르세요.", font=customtkinter.CTkFont('Pretendard', 13),  text_color="#FFFF97")
        text_label7.grid(row=3, column=0, columnspan=4, padx=5, pady=5, sticky="n")
        wildcard_select_text = customtkinter.CTkTextbox(wildcard_window_right, font=customtkinter.CTkFont('Pretendard', 14), width=490, height=280, state="disabled")
        wildcard_select_text.grid(row=2, column=0, columnspan=4, padx=5, pady=5, sticky="nsew")

        #wildcard_window_left = customtkinter.CTkFrame(wildcard_window, width=500)
        #wildcard_window_left.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
        text_label1 = customtkinter.CTkLabel(wildcard_window_left, text="와일드카드 정보", font=customtkinter.CTkFont('Pretendard', 13), width=500)
        text_label1.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
        self.wildcard_text = customtkinter.CTkTextbox(wildcard_window_left, font=customtkinter.CTkFont('Pretendard', 13), width=500)
        self.wildcard_text.grid(row=1, column=0, padx=5, pady=5, sticky="nsew")
        text_label2 = customtkinter.CTkLabel(wildcard_window_left, text="txt파일 내 가중치 문법(100: keyword)은 계속 유효합니다. default=100", font=customtkinter.CTkFont('Pretendard', 13), width=500)
        text_label2.grid(row=2, column=0, padx=5, pady=5, sticky="nsew")
        self.wildcard_button_frame = customtkinter.CTkFrame(wildcard_window_left)
        self.wildcard_button_frame.grid(row=3, column=0, padx=5, pady=5, sticky="n")
        self.reactive_button = customtkinter.CTkButton(self.wildcard_button_frame, font=customtkinter.CTkFont('Pretendard', 13), text="와일드카드 업데이트", command= self.reactivate_wildcards)
        self.reactive_button.grid(row=0, column=0, padx=5, pady=5, sticky="n")
        self.open_wildcard_button = customtkinter.CTkButton(self.wildcard_button_frame, font=customtkinter.CTkFont('Pretendard', 13), text="와일드카드 폴더 열기", command= self.open_wildcard_folder)
        self.open_wildcard_button.grid(row=0, column=1, padx=15, pady=5, sticky="n")
        self.wildcard_text_sample = customtkinter.CTkTextbox(wildcard_window_left, font=customtkinter.CTkFont('Pretendard', 13), width=500, height=100,  text_color="#FFFF97")
        self.wildcard_text_sample.grid(row=4, column=0, padx=5, pady=5, sticky="nsew")
        self.wildcard_text_sample.insert("0.0", "Example : 1girl, <koharu (blue archive)|noa (blue archive)|unicorn (azur lane)|<characters>>, <random_artist>, <happy|surprised|depressed>, <<__colors__clothes>|<{{clothes}}>>, looking at viewer")
        self.wildcard_text_sample.configure(state="disabled")
        text_label3 = customtkinter.CTkLabel(wildcard_window_left, text="<keyword1|keyword2> 형태 표기는 '|'로 구분되는 인스턴트 와일드카드입니다.", font=customtkinter.CTkFont('Pretendard', 13), width=500)
        text_label3.grid(row=5, column=0, padx=5, pady=5, sticky="nsew")
        self.reactivate_wildcards()

    def get_artist(self):
        self.random_artist_list.delete("0.0", "end")
        danbooru_minimum = self.danbooru_minimum.get()
        if self.random_artist_select.get() == "local":
            counts = Counter()
            ndf = self.cached_rows[self.cached_rows['artist'].notnull()]
            for row in ndf['artist']:
                if row != None:
                    substrings = [substring.strip() for substring in row.split(',') if substring.strip()]
                    counts.update(substrings)
            top_500_keywords = [(keyword, count) for keyword, count in counts.most_common(500) if keyword in artist_dict]
            filtered_keywords = [(keyword, count) for keyword, count in top_500_keywords if artist_dict.get(keyword, 0) > danbooru_minimum]
            formatted_keywords = [f"{keyword}: {count}" for keyword, count in filtered_keywords]
            keywords_only = [item.split(": ")[0] for item in formatted_keywords]
            self.random_artist_list_length.configure(text='total length : ' + str(len(filtered_keywords)))
            self.random_artist = keywords_only
            try:
                with open("wildcards/random_artist.txt", 'w') as file:
                    for keyword in keywords_only:
                        if self.random_artist_prefix.get() == "artist:":
                            file.write("artist:"+ keyword + '\n')
                        elif self.random_artist_prefix.get() == "(artist)":
                            file.write(keyword + ' (artist)\n')
                        else:
                            file.write(keyword + '\n')
            except: pass
            formatted_text = "\n".join(formatted_keywords)
            self.random_artist_list.insert("0.0", formatted_text)
        else:
            filtered_keywords = [keyword for keyword, count in artist_dict.items() if count > danbooru_minimum]
            formatted_keywords = [f"{keyword}: {count}" for keyword, count in artist_dict.items() if count > danbooru_minimum]
            self.random_artist_list_length.configure(text='total length : ' + str(len(filtered_keywords)))
            formatted_text = "\n".join(formatted_keywords)
            self.random_artist_list.insert("0.0", formatted_text)
            self.random_artist = filtered_keywords
            try:
                with open("wildcards/random_artist.txt", 'w') as file:
                    for keyword in filtered_keywords:
                        if self.random_artist_prefix.get() == "artist:":
                            file.write("artist:"+ keyword + '\n')
                        elif self.random_artist_prefix.get() == "(artist)":
                            file.write(keyword + ' (artist)\n')
                        else:
                            file.write(keyword + '\n')
            except: pass
        self.random_artist_button.configure(state="normal")

    def activate_wildcards(self):
        wildcards_dir = os.path.join(os.getcwd(), 'wildcards')

        # wildcards 폴더가 있는지 확인하고, 없으면 생성
        if not os.path.exists(wildcards_dir):
            os.makedirs(wildcards_dir)

        # wildcard_dict 딕셔너리 초기화
        wildcard_dict = {'none': []}

        # wildcards 폴더 내의 파일 및 폴더명 획득
        for item in os.listdir(wildcards_dir):
            item_path = os.path.join(wildcards_dir, item)
            # 파일인 경우
            if os.path.isfile(item_path) and item.endswith('.txt'):
                wildcard_dict['none'].append(item)
            # 폴더인 경우
            elif os.path.isdir(item_path):
                wildcard_dict[item] = []
                # 해당 폴더 내의 파일들을 탐색
                for subitem in os.listdir(item_path):
                    subitem_path = os.path.join(item_path, subitem)
                    if os.path.isfile(subitem_path) and subitem.endswith('.txt'):
                        wildcard_dict[item].append(subitem)
        self.wildcard_dict = wildcard_dict
        self.wildcards_dir = wildcards_dir

    def get_wildcard(self, input_str):
        def read_file_with_fallback(file_path, encodings=['utf-8', 'cp949']):
            for encoding in encodings:
                try:
                    with open(file_path, 'r', encoding=encoding, errors='ignore') as file:
                        return file.readlines()
                except UnicodeDecodeError:
                    continue
            return None
        
        bracket_count = input_str.count('[')
        brace_count = input_str.count('{')

        modified_input_str = input_str.replace('[', '').replace(']', '').replace('{', '').replace('}', '')

        file_path = ""
        if '/' in modified_input_str:
            folder, filename = modified_input_str.split('/', 1)
            file_path = os.path.join(self.wildcards_dir, folder, filename + '.txt')
            valid_file = folder in self.wildcard_dict and filename + ".txt" in self.wildcard_dict[folder] and os.path.exists(file_path)
        else:
            file_path = os.path.join(self.wildcards_dir, modified_input_str + ".txt")
            valid_file = modified_input_str + ".txt" in self.wildcard_dict['none'] and os.path.exists(file_path)
        
        if valid_file:
            lines = read_file_with_fallback(file_path)
            
            if lines:
                choice_dic = {}
                for line in lines:
                    match = re.match(r'(\d*\.?\d+):(.+)', line)
                    if match:
                        value, keyword = float(match.group(1)), match.group(2).strip()
                    else:
                        value, keyword = 100, line.strip()
                    choice_dic[keyword] = value

                keywords = list(choice_dic.keys())
                weights = list(choice_dic.values())
                result = random.choices(keywords, weights=weights, k=1)[0].strip()
        else:
            result = modified_input_str

        if brace_count > 0:
            return '{' * brace_count + result + '}' * brace_count
        elif bracket_count > 0:
            return '[' * bracket_count + result + ']' * bracket_count
        else:
            return result

    #Code from https://github.com/DCP-arca/NAI-Auto-Generator/blob/main/nai_generator.py
    #Author : DCP-arca
    def get_anlas(self):
            try:
                response = requests.get("https://api.novelai.net/user/subscription", headers={
                    "Authorization": f"Bearer {self.access_token}"})
                data_dict = json.loads(response.content)
                trainingStepsLeft = data_dict['trainingStepsLeft']
                anlas = int(trainingStepsLeft['fixedTrainingStepsLeft']) + \
                    int(trainingStepsLeft['purchasedTrainingSteps'])
                app.my_anlas.set(anlas)
                self.anlas_label.configure(text="Anlas : "+str(app.my_anlas.get()), text_color="#FFFF97")
            except Exception as e:
                print(e)

            return None
            
    def open_instant_event(self):
        my_font = customtkinter.CTkFont('Pretendard', 13)
        instant_event_window = customtkinter.CTkToplevel()
        instant_event_window.title("인스턴트 이벤트 (작업 도중 종료하지 마세요)")
        instant_event_window.attributes('-topmost', True)
        instant_event_window.resizable(width=False, height=False)
        tabview = customtkinter.CTkTabview(instant_event_window)
        tabview.grid(row=0, column=0, padx=5, pady=5)
        generation_frame = customtkinter.CTkFrame(instant_event_window, height=300)
        generation_frame.grid(row=0, column=1, padx=5, pady=5)

        generation_label = customtkinter.CTkLabel(generation_frame, text="0 / 0", font=my_font)
        generation_label.grid(row=0, column=0, padx=5, pady=5, sticky="n")
        self.instant_stop_bit = False

        def stop_gen():
            self.instant_stop_bit = True
            generation_stop_button.configure(state = "disabled")
            xyz_execute_button.configure(state="normal")

        def close_window():
            stop_gen()
            instant_event_window.destroy()
            
        generation_stop_button = customtkinter.CTkButton(generation_frame, text="Stop", font=my_font, state="disabled", command=stop_gen)
        generation_stop_button.grid(row=1, column=0, padx=5, pady=25, sticky="n")
        instant_event_window.protocol("WM_DELETE_WINDOW", close_window)

        #Tab 관리
        tabview.add("X/Y plot")

        def xyz_excute():
            comboboxes = [xyz_box1, xyz_box2]
            prompts = [xyz_prompt1, xyz_prompt2]
            xyz_list = []
            prompt_list = []
            prompt_len = 0
            for i, combobox in enumerate(comboboxes):
                value = combobox.get()
                #None
                if value == "None":
                    continue
                #CFG Scale
                elif value == "CFG Scale":
                    xyz_list.append("CFG Scale")
                    input_string = prompts[i].get("0.0", "end-1c")
                    split_strings = [s.strip() for s in input_string.split(',')]
                    float_values = [float(s) for s in split_strings]
                    cfg_scale_list = []
                    while float_values[0] <= float_values[1]:
                        cfg_scale_list.append(float_values[0])
                        float_values[0] += float_values[2]
                    cfg_scale_list = [round(v, 1) for v in cfg_scale_list]
                #PG.Rescale
                elif value == "PG.Rescale":
                    xyz_list.append("PG.Rescale")
                    input_string = prompts[i].get("0.0", "end-1c")
                    split_strings = [s.strip() for s in input_string.split(',')]
                    float_values = [float(s) for s in split_strings]
                    pg_rescale_list = []
                    while float_values[0] <= float_values[1]:
                        pg_rescale_list.append(float_values[0])
                        float_values[0] += float_values[2]
                    pg_rescale_list = [round(v, 1) for v in pg_rescale_list]
                #프롬프트 강조
                elif value == "프롬프트 강조":
                    xyz_list.append("프롬프트 강조")
                    input_string = prompts[i].get("0.0", "end-1c")
                    split_strings = [s.strip() for s in input_string.split(',')]
                    split_strings[0] = str(split_strings[0])
                    split_strings[1] = int(split_strings[1])
                    split_strings[2] = int(split_strings[2])
                    split_strings[3] = int(split_strings[3])
                    keyword = split_strings[0]
                    ### 와일드카드 처리 ###
                    if prompt_len == 0:
                        before_wildcard = self.text_input.get("0.0", "end-1c")
                        before_wildcard = [item.strip() for item in before_wildcard.split(',')]
                        if '<' in self.text_input.get("0.0", "end-1c"):
                            #### 단계 1 : 인스턴트 와일드카드 처리 ###
                            for i, keyword in enumerate(before_wildcard):
                                if keyword.startswith('<') and keyword.endswith('>'):
                                    vbar_check = keyword[1:-1]
                                    if '|' in vbar_check:
                                        choices = vbar_check.split('|')  # '|'를 기준으로 split
                                        choice_dic = {}
                                        for choice in choices:
                                            match = re.match(r'(\d*\.?\d+):(.+)', choice)
                                            if match:
                                                value, keyword = float(match.group(1)), match.group(2).strip()
                                            else:
                                                value, keyword = 1, choice.strip()
                                            choice_dic[keyword] = value
                                        keywords = list(choice_dic.keys())
                                        weights = list(choice_dic.values())
                                        selected_instant_wildcard = random.choices(keywords, weights=weights, k=1)[0]
                                        before_wildcard[i] = selected_instant_wildcard
                            #### 단계 2 : 글로벌 와일드카드 처리 ###
                            for i, keyword in enumerate(before_wildcard):
                                if "<" in keyword:
                                    input_str = keyword.strip('<>').strip()
                                    if("__" in input_str):
                                        adjectives = re.findall(r'__(.*?)__', input_str)
                                        last_keyword = re.split(r'__.*?__', input_str)[-1]
                                        adjective_string = ""
                                        for adjective in adjectives:
                                            adjective_string += (self.get_wildcard(adjective) + " ")
                                        before_wildcard[i] = adjective_string + self.get_wildcard(last_keyword)
                                    else:
                                        before_wildcard[i] = self.get_wildcard(input_str)
                        keyword_index = before_wildcard.index(keyword)
                        start = split_strings[1]
                        end = split_strings[2]
                        step = split_strings[3]
                        prompt_list.append([])
                        first_prompt = []
                        for i in range(start, end + 1, step):
                            if i < 0:
                                before_wildcard[keyword_index] = '[' * abs(i) + keyword + ']' * abs(i)
                                first_prompt.append('[' * abs(i) + keyword + ']' * abs(i))
                            elif i == 0:
                                before_wildcard[keyword_index] = keyword
                                first_prompt.append(keyword)
                            else:
                                before_wildcard[keyword_index] = '{' * i + keyword + '}' * i
                                first_prompt.append('{' * i + keyword + '}' * i)
                            prompt_list[prompt_len].append(before_wildcard.copy())
                        prompt_len+=1
                    else:
                        start = split_strings[1]
                        end = split_strings[2]
                        step = split_strings[3]
                        second_prompt = []
                        for i in range(start, end + 1, step):
                            if i < 0:
                                second_prompt.append('[' * abs(i) + keyword + ']' * abs(i))
                            elif i == 0:
                               second_prompt.append(keyword)
                            else:
                                second_prompt.append('{' * i + keyword + '}' * i)
                            second_prompt_keyword = keyword
                #프롬프트 스왑
                elif value == "프롬프트 스왑":
                    xyz_list.append("프롬프트 스왑")
                    input_string = prompts[i].get("0.0", "end-1c")
                    split_strings = [s.strip() for s in input_string.split(',')]
                    keyword = split_strings[0]
                    ### 와일드카드 처리 ###
                    if prompt_len == 0:
                        before_wildcard = self.text_input.get("0.0", "end-1c")
                        before_wildcard = [item.strip() for item in before_wildcard.split(',')]
                        if '<' in self.text_input.get("0.0", "end-1c"):
                            #### 단계 1 : 인스턴트 와일드카드 처리 ###
                            for i, keyword in enumerate(before_wildcard):
                                if keyword.startswith('<') and keyword.endswith('>'):
                                    vbar_check = keyword[1:-1]
                                    if '|' in vbar_check:
                                        choices = vbar_check.split('|')  # '|'를 기준으로 split
                                        choice_dic = {}
                                        for choice in choices:
                                            match = re.match(r'(\d*\.?\d+):(.+)', choice)
                                            if match:
                                                value, keyword = float(match.group(1)), match.group(2).strip()
                                            else:
                                                value, keyword = 1, choice.strip()
                                            choice_dic[keyword] = value
                                        keywords = list(choice_dic.keys())
                                        weights = list(choice_dic.values())
                                        selected_instant_wildcard = random.choices(keywords, weights=weights, k=1)[0]
                                        before_wildcard[i] = selected_instant_wildcard
                            #### 단계 2 : 글로벌 와일드카드 처리 ###
                            for i, keyword in enumerate(before_wildcard):
                                if "<" in keyword:
                                    input_str = keyword.strip('<>').strip()
                                    if("__" in input_str):
                                        adjectives = re.findall(r'__(.*?)__', input_str)
                                        last_keyword = re.split(r'__.*?__', input_str)[-1]
                                        adjective_string = ""
                                        for adjective in adjectives:
                                            adjective_string += (self.get_wildcard(adjective) + " ")
                                        before_wildcard[i] = adjective_string + self.get_wildcard(last_keyword)
                                    else:
                                        before_wildcard[i] = self.get_wildcard(input_str)
                        keyword_index = before_wildcard.index(keyword)
                        prompt_list.append([])
                        first_prompt = []
                        for i in split_strings:
                            before_wildcard[keyword_index] = i
                            first_prompt.append(i)
                            prompt_list[prompt_len].append(before_wildcard.copy())
                        prompt_len+=1                    
                    else:
                        second_prompt = []
                        for i in split_strings:
                            second_prompt.append(i)
                            second_prompt_keyword = keyword
                elif value == "SMEA 0/1/dyn":
                    xyz_list.append("SMEA")
                    smea_list = [(False, False), (True, False), (True, True)]
                elif value == "Samplers":
                    xyz_list.append("Samplers")
                    sampler_list = ["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde", "k_dpmpp_2m"]
            
            #gen_request 생성
            NAI_width, NAI_height = self.resolution_button.get().split(' x ')
            scale_pre = self.cfg_scale_entry.get()
            try:
                    scale_pre = float(scale_pre)
            except:
                scale_pre = 5.0
                app.cfg_scale_var.set("5.0")
            rescale_pre = app.prompt_guidance_rescale_entry.get()
            try:
                rescale_pre = float(rescale_pre)
            except:
                rescale_pre = 0
                app.prompt_guidance_rescale_var.set("0")
            uncond_pre = self.uncond_strength_entry.get()
            try:
                uncond_pre = float(uncond_pre)
                uncond_pre = round(uncond_pre / 0.05) * 0.05
                if (uncond_pre > 1.5):
                    uncond_pre = 1.5
                    self.uncond_strength_entry.delete(0, "end")
                    self.uncond_strength_entry.insert(0, "1.5")
            except:
                uncond_pre = 1.0
                self.uncond_strength_entry.delete(0, "end")
                self.uncond_strength_entry.insert(0, "1.0")
            _gen_request = {
                    "width":NAI_width,
                    "height":NAI_height,
                    "quality_toggle":self.auto_quality_toggle.get(),
                    "seed":self.seed_entry.get(),
                    "sampler":self.sampler_button.get(),
                    "scale":scale_pre,
                    "uncond_scale":uncond_pre,
                    "sema":self.sema_button.get(),
                    "sema_dyn": self.dyn_button.get(),
                    "cfg_rescale": rescale_pre,
                    "prompt": self.text_input.get("0.0", "end-1c"),
                    "negative":self.negative_prompt_input.get("0.0", "end-1c"),
                    "user_screen_size": self.get_max_size(),
                    "start_time": self.start_time,
                    "access_token": self.access_token,
                    "save_folder": self.output_file_path,
                    "png_rule": self.name_var.get(),
                    "type": "normal",
                    "rating":self.current_prompt_rating
                }
            x = []
            y = []
            z = []
            xyzs = [x, y, z]
            prompt_len = 0
            ybar = None
            for i, xyz in enumerate(xyz_list):
                if i == 0:
                    if xyz_list[i] == "CFG Scale":
                        for cfg in cfg_scale_list:
                            gen_request = _gen_request.copy()
                            gen_request["scale"] = cfg
                            xyzs[i].append(gen_request.copy())
                        xbar = [str("CFG: {:.1f}".format(x)) for x in cfg_scale_list]
                    elif xyz_list[i] == "PG.Rescale":
                        for pgr in pg_rescale_list:
                            gen_request = _gen_request.copy()
                            gen_request["cfg_rescale"] = pgr
                            xyzs[i].append(gen_request.copy())
                        xbar = [str("PGR: {:.1f}".format(x)) for x in pg_rescale_list]
                    elif xyz_list[i] == "프롬프트 강조":
                        for prompt in prompt_list[prompt_len]:
                            gen_request = _gen_request.copy()
                            gen_request["prompt"] = ', '.join(prompt)
                            xyzs[i].append(gen_request.copy())
                        xbar = first_prompt
                        prompt_len+=1
                    elif xyz_list[i] == "프롬프트 스왑":
                        for prompt in prompt_list[prompt_len]:
                            gen_request = _gen_request.copy()
                            gen_request["prompt"] = ', '.join(prompt)
                            xyzs[i].append(gen_request.copy())
                        xbar = first_prompt
                        prompt_len+=1
                    elif xyz_list[i] == "SMEA":
                        for tp in smea_list:
                            gen_request = _gen_request.copy()
                            gen_request["sema"], gen_request["sema_dyn"] = tp
                            xyzs[i].append(gen_request.copy())
                        xbar = ['None', "SMEA", "SMEA+DYN"]
                    elif xyz_list[i] == "Samplers":
                        for sam in sampler_list:
                            gen_request = _gen_request.copy()
                            gen_request["sampler"] = sam
                            xyzs[i].append(gen_request.copy())
                        xbar = ["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde", "k_dpmpp_2m"]
                elif i == 1:
                    if xyz_list[i] == "CFG Scale":
                        for cfg in cfg_scale_list:
                            _x = copy.deepcopy(x)
                            for value in _x:
                                value["scale"] = cfg
                            y.append(_x)
                        ybar = [str("CFG: {:.1f}".format(x)) for x in cfg_scale_list]
                    elif xyz_list[i] == "PG.Rescale":
                        for pgr in pg_rescale_list:
                            _x = copy.deepcopy(x)
                            for value in _x:
                                value["cfg_rescale"] = pgr
                            y.append(_x)
                        ybar = [str("PGR: {:.1f}".format(x)) for x in pg_rescale_list]
                    elif xyz_list[i] == "프롬프트 강조":
                        if prompt_len == 0:
                            for prompt in prompt_list[prompt_len]:
                                _x = copy.deepcopy(x)
                                for value in _x:
                                    value["prompt"] = prompt
                                y.append(_x)
                            ybar = prompt_list[prompt_len]
                        else:
                            for keyword in second_prompt:
                                _x = copy.deepcopy(x)
                                for value in _x:
                                    prompt = value["prompt"]
                                    prompt = [item.strip() for item in prompt.split(',')]
                                    idx = prompt.index(second_prompt_keyword)
                                    prompt[idx] = keyword
                                    value["prompt"] = ', '.join(prompt)
                                y.append(_x)
                            ybar = second_prompt
                    elif xyz_list[i] == "프롬프트 스왑":
                        if prompt_len == 0:
                            for prompt in prompt_list[prompt_len]:
                                _x = copy.deepcopy(x)
                                for value in _x:
                                    value["prompt"] = prompt
                                y.append(_x)
                            ybar = prompt_list[prompt_len]
                        else:
                            for keyword in second_prompt:
                                _x = copy.deepcopy(x)
                                for value in _x:
                                    prompt = value["prompt"]
                                    prompt = [item.strip() for item in prompt.split(',')]
                                    idx = prompt.index(second_prompt_keyword)
                                    prompt[idx] = keyword
                                    value["prompt"] = ', '.join(prompt)
                                y.append(_x)
                            ybar = second_prompt
                    elif xyz_list[i] == "SMEA":
                        for tp in smea_list:
                            _x = copy.deepcopy(x)
                            for value in _x:
                                value["sema"], value["sema_dyn"] = tp
                            y.append(_x)
                        ybar = ['None', "SMEA", "SMEA+DYN"]
                    elif xyz_list[i] == "Samplers":
                        for sam in sampler_list:
                            _x = copy.deepcopy(x)
                            for value in _x:
                                value["sampler"] = sam
                            y.append(_x)
                        ybar = ["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde", "k_dpmpp_2m"]
            xyz_list = []
            prompt_list = []
            prompt_len = 0

            def run_generation(xy, xbar, ybar=None):
                if isinstance(xy[0], list):
                    ydim = len(xy)
                    xdim = len(xy[0])
                else:
                    ydim = 1
                    xdim = len(xy)

                max_count = str(ydim * xdim)
                generation_label.configure(text = "0" +' / '+ max_count)                  
                if not ybar: ybar = " "

                label_font_size = 40
                label_space = 500
                image_width = int(NAI_width)
                image_height = int(NAI_height)
                canvas_width = label_space + image_width * xdim
                canvas_height = image_height * ydim + label_space
                final_image = Image.new("RGB", (canvas_width, canvas_height), "white")
                font = ImageFont.truetype("arial.ttf", label_font_size)
                draw = ImageDraw.Draw(final_image)
                draw.text(
                    (label_space +((image_width * xdim) / 2), label_space // 3),
                    f"seed : {self.seed_entry.get()}", 
                    fill="black", 
                    font=font, 
                    anchor="mm"
                )

                xyz_execute_button.configure(state = "disabled")
                generation_stop_button.configure(state = "normal")
                pass_counter = 0

                for yloop in range(ydim):
                    if self.instant_stop_bit:
                        break
                    for xloop in range(xdim):
                        if ydim > 1:
                            gen_request = xy[yloop][xloop]
                        else:
                            gen_request = xy[xloop]
                        app.image_generation_button.configure(border_width = 2)
                        generation_pass = False
                        while_counter = 0
                        while (not self.instant_stop_bit and not generation_pass):
                            self.state_label.configure(text ="state : NAI 이미지 생성 대기중 ... ", text_color = "#FFFF97")
                            if while_counter >= 15:
                                self.instant_stop_bit = True
                            if gen_request["png_rule"] == "count":
                                app.generation_count += 1
                                gen_request["count"] =app.generation_count
                            result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request)
                            self.state_label.configure(text ="state : idle", text_color = "#DCE4EE")
                            app.image_generation_button.configure(border_width = 0)
                            if info:
                                temp = info.get('Comment', '')
                                temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','')
                                generation_pass = True
                                pass_counter += 1
                            else:
                                temp = result_prompt
                                while_counter += 1
                        generation_pass = False
                        self.running_flag = False
                        generation_label.configure(text = str(pass_counter) +' / '+ max_count)              
                        self.image_label_report.configure(state="normal")
                        self.image_label_report.delete("0.0", "end")
                        self.image_label_report.configure(text_color="#DCE4EE")
                        self.image_label_report.insert("0.0", temp)
                        self.image_label_report.configure(state="disabled")
                        if result_image:
                            if app.state() != 'zoomed':
                                instant_result_image = customtkinter.CTkImage(result_image, size=(620,620))
                            else:
                                current_image = Image.open(filename)
                                original_width, original_height = current_image.size
                                max_size = app.winfo_screenheight()-100
                                if original_width > max_size or original_height > max_size:
                                    new_image = Image.new("RGB", (max_size, max_size), "black")
                                    new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2))
                                    instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size))
                                else:
                                    instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size))
                            self.image_label.configure(image=instant_result_image)
                            app.ext_set_image_to_queue(result_image, result_prompt, str(result_seed), filename)
                            x_position = label_space + (xloop * image_width)
                            y_position = label_space + (yloop * image_height)
                            final_image.paste(Image.open(filename), (x_position, y_position))
                            draw = ImageDraw.Draw(final_image)
                            if yloop == 0:  # x축 레이블은 한 번만 추가
                                draw.text(
                                    (x_position + image_width / 2, label_space / 2),
                                    xbar[xloop], 
                                    fill="black", 
                                    font=font, 
                                    anchor="mm"
                                )
                            if xloop == 0:  # y축 레이블은 매 행마다 추가
                                draw.text(
                                    (label_space // 2, y_position + image_height // 2),
                                    ybar[yloop], 
                                    fill="black", 
                                    font=font, 
                                    anchor="mm"
                                )
                            if self.instant_stop_bit:
                                break
                            time.sleep(2)
                image_path = f"xy_plot_{self.start_time}_{self.xy_plot_count}.jpg"
                final_image.save(image_path)
                os.startfile(image_path)
                self.xy_plot_count += 1
                generation_stop_button.configure(state = "disabled")
                xyz_execute_button.configure(state="normal")
                self.instant_stop_bit = False
                pass_counter = 0
                

            if y:
                generation_thread = threading.Thread(target=run_generation, args=(y, xbar, ybar), daemon=True)
                generation_thread.start()
            else:
                generation_thread = threading.Thread(target=run_generation, args=(x, xbar), daemon=True)
                generation_thread.start()












        #XYZ plot
        xyz_frame = customtkinter.CTkFrame(tabview.tab("X/Y plot"))
        xyz_frame.grid(row=1, column=0, padx=5, pady=5)
        xyz_label1 = customtkinter.CTkLabel(xyz_frame, text="X value : ", font=my_font)
        xyz_label1.grid(row=0, column=0, padx=5, pady=5)
        xyz_label2 = customtkinter.CTkLabel(xyz_frame, text="Y value : ", font=my_font)
        xyz_label2.grid(row=1, column=0, padx=5, pady=5)
        xyz_label3 = customtkinter.CTkLabel(xyz_frame, text="Z value : ", font=my_font)
        #xyz_label3.grid(row=2, column=0, padx=5, pady=5)
        xyz_values = ['None','CFG Scale', '프롬프트 강조', 'PG.Rescale', 'SMEA 0/1/dyn', 'Samplers', '프롬프트 스왑']
        xyz_box1 = customtkinter.CTkComboBox(xyz_frame, values=xyz_values, font=my_font)
        xyz_box2 = customtkinter.CTkComboBox(xyz_frame, values=xyz_values, font=my_font)
        xyz_box3 = customtkinter.CTkComboBox(xyz_frame, values=xyz_values, font=my_font, state="disabled")
        xyz_box1.grid(row=0, column=1, padx=5, pady=5)
        xyz_box2.grid(row=1, column=1, padx=5, pady=5)
        #xyz_box3.grid(row=2, column=1, padx=5, pady=5)
        xyz_prompt1 = customtkinter.CTkTextbox(xyz_frame, width= 300, height=80, font=my_font)
        xyz_prompt2 = customtkinter.CTkTextbox(xyz_frame, width= 300, height=80, font=my_font)
        xyz_prompt3 = customtkinter.CTkTextbox(xyz_frame, width= 300, height=80, font=my_font, state="disabled")
        xyz_prompt1.grid(row=0, column=2, padx=5, pady=5)
        xyz_prompt2.grid(row=1, column=2, padx=5, pady=5)
        #xyz_prompt3.grid(row=2, column=2, padx=5, pady=5)
        xyz_execute_button = customtkinter.CTkButton(xyz_frame, text="작업 시작", font=my_font, command=xyz_excute)
        xyz_execute_button.grid(row=3, columnspan=3, padx=5, pady=5, sticky="n")
                                            
        '''
        self.resolution_button2 = customtkinter.CTkComboBox(self.hidden_frame, width=160,values=["1024 x 1024", "960 x 1088", "896 x 1152", "832 x 1216", "1088 x 960", "1152 x 896", "1216 x 832"], variable=self.resolution_var, font=my_font)
        self.resolution_button2.grid(row=3, column=1, padx=5, sticky="w")'
        '''




if __name__ == "__main__":
    customtkinter.set_appearance_mode("dark")

    # ----- i2i inpaint를 위한 global 변수 -----
    iimg = None
    img2img_window = None
    inpaint_mode = False
    # ----- 여기까지 global 변수 -----

    app = App()
    app.load_settings()
    app.protocol("WM_DELETE_WINDOW", app.exit_program)
    app.activate_wildcards()
    app.get_anlas()
    app.after(1000, lambda: setattr(app, 'last_window_size', (app.winfo_width(), app.winfo_height())))
    app.mainloop()