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 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 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.label_repeat = customtkinter.CTkLabel(self.upper_frame, text="동일 이미지를 다음 횟수만큼 반복하여 생성 (Default=1)", font = my_font) self.label_repeat.grid(row=2, column=0, columnspan=3, sticky="n") self.repeat_entry = customtkinter.CTkEntry(self.upper_frame, font = my_font, width=70) self.repeat_entry.grid(row=3, column=0,columnspan=3, sticky="n") self.label = customtkinter.CTkLabel(self, text="자동화 종료 조건", font = my_font) self.label.grid(row=2, 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.delay_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) 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") 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, "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("", 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('<>', 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('<>',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): 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__() 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 self.start_time_prime = datetime.now() self.start_time = self.start_time_prime.strftime('%Y%m%d_%H%M') self.title("NAIA Alpha 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", " 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", " 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("", 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 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") 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() self.prompt_preset_button = customtkinter.CTkButton(self.searched_prompt_frame, width=120, text="프리셋", fg_color="#848484", font=my_font, command= lambda: open_Preset(self)) self.prompt_preset_button.grid(row=0, column=2, padx=30, sticky="w") 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) self.text_input.grid(row=1, column=0, pady=5, sticky="nsew") self.text_input.bind("", on_enter_pressed) self.text_input.bind("", on_tab_pressed) def random_function(): if(self.random_function_pressed) == False: self.random_function_pressed = True self.random_function_button.configure(state="disabled") 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 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 } random_index = np.random.choice(self.cached_rows.index) #print(random_index) popped_row = self.cached_rows.loc[random_index] self.cached_rows.drop(random_index, inplace=True) self.cached_prompt_label.configure(text = "남은 프롬프트 행 : "+str(len(self.cached_rows))) prompt = 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 (('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", " 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 else: 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", " 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") #### 여기서부터 와일드카드 처리 구문 #### 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"): #### 단계 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) 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, "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" } if self.turbo_button.get() == 1: request_list = [] 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) 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 app.image_generation_button.configure(border_width = 2) 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('"','') else: self.error_count += 1 if self.error_count >= 5: self.automation_button.deselect() temp = result_prompt 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(4.5, 8.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) 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('"','') else: self.error_count += 1 if self.error_count >= 5: self.automation_button.deselect() self.turbo_button.deselect() temp = result_prompt 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) 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", " 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) 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) self.fixed_prompt_after_input.grid(row=7, column=0, pady=5, sticky="nsew") self.negative_prompt_label = customtkinter.CTkLabel(self.text_input_frame, text=" ----------------------------- 네거티브 프롬프트 ----------------------------- ", font=large_font) self.negative_prompt_label.grid(row = 8, column=0, sticky="n" ) self.negative_prompt_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=100, font=v_large_font) 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) 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") 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.unlock_hold_prompt_label = customtkinter.CTkLabel(self.text_input_frame, text="*잠금을 해제하더라도 선행/후행 고정 프롬프트가 프롬프트창에 반영되지 않습니다.", font=large_font) self.unlock_hold_prompt_label.grid(row = 14, column = 0, pady=5, sticky="w") #이미지 히스토리 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") #이미지 레이블 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_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_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" 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 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): 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", " 프롬프트 고정 상태에서는 사용 할 수 없습니다.") 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 : " + self.image_queue[self.window-1][2]) self.image_label_report.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", " 프롬프트 고정 상태에서는 사용 할 수 없습니다.") 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 : " + self.image_queue[self.window-2][2]) self.image_label_report.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", " 프롬프트 고정 상태에서는 사용 할 수 없습니다.") 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 : " + self.image_queue[self.window-3][2]) self.image_label_report.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", " 프롬프트 고정 상태에서는 사용 할 수 없습니다.") 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 : " + self.image_queue[self.window-4][2]) self.image_label_report.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", " 프롬프트 고정 상태에서는 사용 할 수 없습니다.") 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 : " + self.image_queue[self.window-5][2]) self.image_label_report.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) >= 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") 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, _filename) 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("엑셀 파일에 저장됨") self.history_export = customtkinter.CTkButton(self.image_history_frame, text="export (0)", width=100, font=my_font, command=save_to_excel) 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"], 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",state="disabled") self.instant_row_button.grid(row=3, column=4,pady=5, padx=5, sticky="nsew") GENERATE_EVENT = "<>" 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': 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"], 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("", 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)") 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="▼") def on_escape(event=None): self.focus_set() self.bind('', on_escape) def copy_file(event): 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 self.control_pressed = False self.bind_all("", on_ctrl_press) self.bind_all("", on_ctrl_release) self.bind('', 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): def instant_image_generation(self): img2img_window.attributes('-topmost', False) def image_to_base64(image): image_bytesIO = io.BytesIO() img.save(image_bytesIO, format="png") return base64.b64encode(image_bytesIO.getvalue()).decode() i2i_generate_button.configure(state="disabled") request_prompt = i2i_text_input.get("0.0", "end") 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 = request_upper_size_steps.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") try: steps = int(steps) except: steps = 28 self.cfg_scale_var.set("28") gen_request = { "width":i2i_request_width.get(), "height":i2i_request_height.get(), "quality_toggle":self.auto_quality_toggle.get(), "seed":request_seed if request_upper_size_seed_hold_var.get() == 1 else random.randint(0,9999999999), "sampler":self.sampler_button.get(), "scale":scale_pre, "sema":self.sema_button.get(), "sema_dyn": self.dyn_button.get(), "cfg_rescale": rescale_pre, "prompt": request_prompt, "negative":i2i_negative_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": "upper", "steps": steps if steps <= 50 else 50, "image": send_image, "strength": round(i2i_slider.get(), 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() 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 = self.image_queue[self.current_window].copy() 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") img = customtkinter.CTkImage(current_lookup[0], size=(576, 576)) img_label = customtkinter.CTkLabel(img2img_window_left, text="", image=img) img_label.grid(row=0, column=0) img_label_result = customtkinter.CTkLabel(img2img_window_left, text="") 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("", 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}") 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_input.insert("0.0", self.negative_prompt_input.get("0.0", "end-1c")) 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_slider_label = customtkinter.CTkLabel(i2i_slider_frame, text="Strength : 0.70", 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(0.7) i2i_resolution_label = customtkinter.CTkLabel(i2i_slider_frame, text="해상도 배율", font=large_font, width=140) i2i_resolution_label.grid(row=1, column=0, sticky="nsew") 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=0) 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 elif v == 1: request_width, request_height = find_max_resolution(width, height, 2166784) elif v == 2: request_width, request_height = find_max_resolution(width, height, 2662400) i2i_resolution_label.configure(text=f"{request_width} x {request_height}") i2i_request_width.set(request_width) i2i_request_height.set(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") 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" ) request_upper_size_seed_hold_var = customtkinter.IntVar(value=1) request_upper_size_seed_hold = customtkinter.CTkCheckBox(i2i_generate_frame, text="시드고정 Step : ", font=my_font, variable=request_upper_size_seed_hold_var) request_upper_size_seed_hold.grid(row=1, column=0, padx=5, pady=5, sticky="nsew") 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)) i2i_generate_button.grid(row = 1, column= 2, pady=5, sticky="n" ) self.bind("", on_arrow_key) self.bind("", on_arrow_key) self.image_generation_repeat = 1 self.image_generation_repeat_flag = False self.image_generation_repeat_current = 0 #세상에 시발 이 위까지 전부 __init__에 들어가있음 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()), "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() } 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 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))) 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("", 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="고정 프롬프트에서는 로 호출", 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("", 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=" 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, >, , , <<__colors__clothes>|<{{clothes}}>>, looking at viewer") self.wildcard_text_sample.configure(state="disabled") text_label3 = customtkinter.CTkLabel(wildcard_window_left, text=" 형태 표기는 '|'로 구분되는 인스턴트 와일드카드입니다.", 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 if __name__ == "__main__": customtkinter.set_appearance_mode("dark") 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()