import customtkinter import tkinter as tk from tkinter import font from tkinter import Tk from PIL import Image, ImageOps, ImageDraw, ImageFont,ImageTk import os, sys import ctypes import pandas as pd import numpy as np import NAIA_search, NAIA_random_function_core, NAIA_Login, NAIA_generation import json import arti_list, tagbag, wlist, copyright_list_reformatted, remove_result_e, remove_result_qe, copyright_dict_0103 import character_dictionary as cd import time from datetime import datetime import random import threading, pyperclip from ctypes import windll from CTkListbox import * from tkinter import filedialog import io from openpyxl import Workbook from openpyxl.styles import Alignment from openpyxl.drawing.image import Image as OpenpyxlImage from collections import Counter from artist_dictionary import artist_dict import re import requests import base64 import queue import webbrowser import ctypes from plyer import notification import subprocess, copy from tkinterdnd2 import TkinterDnD, DND_ALL import gzip from pathlib import Path import configparser class Data: def __init__(self, wlist, tagbag, arti_list, copyright_list_reformatted, cd, remove_result_e, remove_result_qe): self.whitelist = wlist.whitelist self.bag_of_tags = tagbag.bag_of_tags self.afilter_30000 = arti_list.afilter_30000 self.copyright_keys = copyright_list_reformatted.copyright_list self.character_keys = list(cd.character_dictionary.keys()) nsfw_word = list(remove_result_e.keyword_counts.keys()) questionable_word = list(remove_result_qe.keyword_counts.keys()) self.qe_word = nsfw_word + questionable_word def get_qe_word(self): return self.qe_word class AccountSetting(customtkinter.CTkToplevel): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.title("NAI Account Setting") self.attributes('-topmost', True) def on_close(self): self.withdraw() def NAI_connect(self): username = self.NAI_ID_entry.get().strip() password = self.NAI_PW_entry.get().strip() access_key = NAIA_Login.get_access_key(username, password) try: app.access_token = NAIA_Login.login(access_key) app.NAI_ID = username[:4] self.state_label.configure(text="(로그인 성공, 닫기 버튼을 눌러주세요.)", font=my_font) app.NAI_Account_Login.configure(state="disabled") app.NAI_Token_Remove.configure(state="normal") app.NAI_Account_State.configure(text="NAI Login : OK") app.image_generation_button.configure(state="normal") except Exception as e: print(e) self.state_label.configure(text="아이디 혹은 비밀번호 오류입니다.", font=my_font) self.button_frame = customtkinter.CTkFrame(self) self.button_frame.grid(row=0, padx=5, pady=5, sticky="nsew") self.button_frame.columnconfigure(0, weight=1) self.button_frame.columnconfigure(1, weight=4) my_font = customtkinter.CTkFont('Pretendard', 13) self.NAI_ID_label = customtkinter.CTkLabel(self.button_frame, text="NAI ID:", font=my_font) self.NAI_ID_label.grid(row = 0, column = 0, padx=5, pady=5, sticky="nsew") self.NAI_PW_label = customtkinter.CTkLabel(self.button_frame, text="NAI PW:", font=my_font) self.NAI_PW_label.grid(row = 1, column = 0, padx=5, pady=5, sticky="nsew") self.NAI_ID_entry = customtkinter.CTkEntry(self.button_frame) self.NAI_ID_entry.grid(row = 0, column = 1, padx=5, pady=5, sticky="nsew") self.NAI_PW_entry = customtkinter.CTkEntry(self.button_frame, show="*") self.NAI_PW_entry.grid(row = 1, column = 1, padx=5, pady=5, sticky="nsew") self.connect_button = customtkinter.CTkButton(self.button_frame, text="Connect", command=lambda:NAI_connect(self)) self.connect_button.grid(row = 2, column = 0, columnspan=2, padx=5, pady=5, sticky="n") self.state_label = customtkinter.CTkLabel(self.button_frame, text="해당 접속기능은 정상적인 접속 패턴이 아닌점 참고 부탁드립니다.", font=my_font) self.state_label.grid(row = 3, column = 0, columnspan=2, padx=5, pady=5, sticky="nsew") self.protocol("WM_DELETE_WINDOW", lambda: on_close(self)) class Advanced_setting(customtkinter.CTkToplevel): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.title("기타 설정") self.resizable(width=False, height=False) self.geometry("270x250") self.attributes('-topmost', True) my_font = customtkinter.CTkFont('Pretendard', 13) def on_close(self): self.withdraw() def select_folder(self): folder_selected = filedialog.askdirectory() try: self.save_path.configure(state="normal") self.save_path.delete(0,"end") self.save_path.insert(0, folder_selected) self.save_path.configure(state="disabled") app.output_file_path_personal = True app.output_file_path = folder_selected except: pass def deselect_folder(self): self.save_path.configure(state="normal") app.output_file_path = f"output_NAI\\{app.start_time}\\txt2img" self.save_path.delete(0,"end") self.save_path.insert(0, app.output_file_path) self.save_path.configure(state="disabled") app.output_file_path_personal = True self.advanced_setting_frame = customtkinter.CTkFrame(self, width=250) self.advanced_setting_frame.grid(row=0, column=0, padx=10, pady=5, sticky="nsew") self.change_save_path_button = customtkinter.CTkButton(self.advanced_setting_frame, text="이미지 저장 경로 변경", command= lambda: select_folder(self), font=my_font, width=250) self.change_save_path_button.grid(row=0, column=0, pady=5,sticky="nsew") self.save_path = customtkinter.CTkEntry(self.advanced_setting_frame, font=my_font, width=250) self.save_path.insert(0, app.output_file_path) self.save_path.configure(state="disabled") self.save_path.grid(row=1, column=0, pady=5,sticky="nsew") self.change_save_path_button2 = customtkinter.CTkButton(self.advanced_setting_frame, text="경로 초기화", command= lambda: deselect_folder(self), font=my_font, width=250) self.change_save_path_button2.grid(row=2, column=0, pady=5,sticky="nsew") self.file_name_label = customtkinter.CTkLabel(self.advanced_setting_frame, text=" -- 파일명.png 규칙 설정 -- " , font=my_font, width=250) self.file_name_label.grid(row=3, column=0, pady=5,sticky="n") self.radio1 = customtkinter.CTkRadioButton(self.advanced_setting_frame, text="생성시간.png : 20231230_123001.png", variable=app.name_var, value="time", font=my_font) self.radio1.grid(row=4, column=0) self.radio2 = customtkinter.CTkRadioButton(self.advanced_setting_frame, text="생성순서.png : 00001.png,00002.png", variable=app.name_var, value="count", font=my_font) self.radio2.grid(row=5, column=0) self.file_name_label2 = customtkinter.CTkLabel(self.advanced_setting_frame, text="*생성순서 적용시 날짜_시간 폴더에 저장" , font=my_font, width=250) self.file_name_label2.grid(row=6, column=0, pady=5,sticky="n") self.protocol("WM_DELETE_WINDOW", lambda: on_close(self)) class Automation_setting(customtkinter.CTkToplevel): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.title("Automation 종료/지연 설정") self.var = customtkinter.StringVar() self.attributes('-topmost', True) my_font = customtkinter.CTkFont('Pretendard', 13) def show_option(self): if self.var.get() == 'timer': self.timer_label.grid(row=4, column=0, pady=5) self.timer_entry.grid(row=4, column=1, pady=5) self.windows_shutdown_check.grid(row=5, column=0, columnspan=3, sticky="n", pady=5) self.count_label.grid_forget() self.count_entry.grid_forget() elif self.var.get() == 'count': self.count_label.grid(row=4, column=0, pady=5) self.count_entry.grid(row=4, column=1, pady=5) self.windows_shutdown_check.grid(row=5, column=0, columnspan=3, sticky="n", pady=5) self.timer_label.grid_forget() self.timer_entry.grid_forget() else: self.timer_label.grid_forget() self.timer_entry.grid_forget() self.count_label.grid_forget() self.count_entry.grid_forget() self.windows_shutdown_check.grid_forget() def on_close(self): self.withdraw() self.upper_frame = customtkinter.CTkFrame(self, fg_color="#242424") self.upper_frame.grid(row=0, column=0, columnspan=3, sticky="n") self.label_time = customtkinter.CTkLabel(self.upper_frame, text="이미지 생성당 지연시간 추가 (초)", font = my_font) self.label_time.grid(row=0, column=0, columnspan=3, sticky="n") self.delay_entry = customtkinter.CTkEntry(self.upper_frame, font = my_font) self.delay_entry.grid(row=1, column=0,columnspan=3, sticky="n") self.repeat_frame = customtkinter.CTkFrame(self, fg_color="#242424") self.repeat_frame.grid(row=2, column=0, columnspan=3, sticky="n") self.label_repeat = customtkinter.CTkLabel(self.repeat_frame, text="동일 이미지를 다음 횟수만큼 반복하여 생성 (Default=1)", font = my_font) self.label_repeat.grid(row=0, column=0, columnspan=3, sticky="n") self.repeat_entry = customtkinter.CTkEntry(self.repeat_frame, font = my_font, width=70) self.repeat_entry.grid(row=1, column=0, columnspan=2, sticky="e") def set_wc_hold(): if self.repeat_wildcard_hold_var.get() == 1: app.hold_wildcard = True else: app.hold_wildcard = False self.repeat_wildcard_hold_var = customtkinter.IntVar() self.repeat_wildcard_hold = customtkinter.CTkCheckBox(self.repeat_frame, font = my_font, text="와일드카드 고정", variable=self.repeat_wildcard_hold_var, command=set_wc_hold, border_color="grey10") self.repeat_wildcard_hold.grid(row=1, column=2, sticky="n") self.label_wildcard_repeat = customtkinter.CTkLabel(self.repeat_frame, text="와일드카드 *사전개봉*시 다음 횟수만큼 연속으로 할당 (Default=1)", font = my_font) self.label_wildcard_repeat.grid(row=2, column=0, columnspan=3, sticky="n") self.wildcard_repeat_entry = customtkinter.CTkEntry(self.repeat_frame, font = my_font, width=70) self.wildcard_repeat_entry.grid(row=3, column=0,columnspan=3, sticky="n") self.label = customtkinter.CTkLabel(self.repeat_frame, text="자동화 종료 조건", font = my_font) self.label.grid(row=4, column=0, columnspan=3, sticky="n") self.radio1 = customtkinter.CTkRadioButton(self, text="무제한", variable=self.var, value="unlimited", command=lambda: show_option(self), font = my_font) self.radio1.grid(row=3, column=0) self.radio2 = customtkinter.CTkRadioButton(self, text="타이머", variable=self.var, value="timer", command=lambda: show_option(self), font = my_font) self.radio2.grid(row=3, column=1) self.radio3 = customtkinter.CTkRadioButton(self, text="생성카운트", variable=self.var, value="count", command=lambda: show_option(self), font = my_font) self.radio3.grid(row=3, column=2) self.timer_label = customtkinter.CTkLabel(self, text="자동화 동작 시간(분) : ", font = my_font) self.timer_entry = customtkinter.CTkEntry(self) self.count_label = customtkinter.CTkLabel(self, text="자동 생성 횟수 : ", font = my_font) self.count_entry = customtkinter.CTkEntry(self) self.windows_shutdown = customtkinter.IntVar() self.windows_shutdown_check = customtkinter.CTkCheckBox(self, text="자동화가 자동으로 끝나면 윈도우를 종료합니다.", variable=self.windows_shutdown, font = my_font) self.apply_button = customtkinter.CTkButton(self, text="적용", font = my_font, command=lambda: on_apply(self)) self.stop_button = customtkinter.CTkButton(self, text="중단", font = my_font, command=lambda: on_stop(self)) self.close_button = customtkinter.CTkButton(self, text="닫기", font = my_font, command=lambda: on_close(self)) self.apply_button.grid(row=6, column=0, pady=5) self.stop_button.grid(row=6, column=1, pady=5) self.close_button.grid(row=6, column=2, pady=5) def on_apply(self): selected_option = self.var.get() if self.delay_entry.get(): try: app.delay_offset = round(float(self.delay_entry.get()), 1) if app.delay_offset > 60: app.delay_offset = 60 elif app.delay_offset < -8: app.delay_offset = -8 app.automation_setting_button.configure(text=f"자동화 설정 ({str(round(app.delay_offset, 1))}초)") except ValueError as e: print(e) app.delay_offset = 0 else: app.delay_offset = 0 app.automation_setting_button.configure(text=f"자동화 설정") if self.repeat_entry.get(): try: app.image_generation_repeat = int(self.repeat_entry.get()) except: self.repeat_entry.delete(0, "end") app.image_generation_repeat = 1 if self.wildcard_repeat_entry.get(): try: app.wildcard_preopen_repeat = int(self.wildcard_repeat_entry.get()) app.wildcard_preopen_repeat_current = app.wildcard_preopen_repeat except: self.wildcard_repeat_entry.delete(0, "end") app.image_generation_repeat = 1 if selected_option == "timer": app.auto_time_left_flag = True app.auto_count_left_flag = False try: # 엔트리에서 입력된 시간을 분 단위에서 초 단위로 변환 app.auto_time_left = int(self.timer_entry.get()) * 60 except ValueError: # 잘못된 입력 처리 print("Invalid input for timer. Please enter a number.") return elif selected_option == "count": app.auto_count_left_flag = True app.auto_time_left_flag = False try: app.auto_count_left = int(self.count_entry.get()) except ValueError: # 잘못된 입력 처리 print("Invalid input for count. Please enter a number.") return else: self.auto_time_left_flag = False self.auto_count_left_flag = False on_stop(self) # 이전 스레드 종료 start_auto_thread() # 새 스레드 시작 def show_shutdown_warning(): def cancel_shutdown(): os.system("shutdown -a") warning_window.destroy() def on_warning_window_close(): if warning_window.after_id is not None: app.after_cancel(warning_window.after_id) warning_window.destroy() app.deiconify() app.lift() warning_window = customtkinter.CTkToplevel(app) warning_window.title("Shutdown Warning") warning_window.attributes("-topmost", True) warning_window.protocol("WM_DELETE_WINDOW", on_warning_window_close) warning_window.after_id = None label = customtkinter.CTkLabel(warning_window, text=" 프로그램 및 컴퓨터가 90/120초 후에 종료됩니다. ", font=my_font) label.pack(pady=15) cancel_button = customtkinter.CTkButton(warning_window, text="취소", command=cancel_shutdown, font=my_font) cancel_button.pack(pady=5) # 90초 후에 프로그램 종료 warning_window.after_id = warning_window.after(90000, app.exit_program) def shutdown_computer(): os.system("shutdown /s /t 120") show_shutdown_warning() def auto_time_thread(stop_event): def seconds_to_hms(seconds): h = seconds // 3600 m = (seconds % 3600) // 60 s = seconds % 60 if h != 0: if (s%2) == 0: return f"{h:02d}:{m:02d}" else: return f"{h:02d} {m:02d}" else: if (s%2) == 0: return f"{m:02d}:{s:02d}" else: return f"{m:02d} {s:02d}" def update_label_for_time_finished(): app.automation_button.configure(text="자동화 (종료됨)") app.auto_time_left_flag = False app.automation_button.deselect() if self.windows_shutdown.get() == 1: shutdown_computer() else: notification.notify( title = '자동생성이 완료되었어요.', message = '결과를 확인해 보세요.', app_name = "NAIA", app_icon = app.basedir+'/icoico.ico', timeout = 5, # seconds ) while not stop_event.is_set() and app.auto_time_left > 0: time.sleep(1) app.auto_time_left -= 1 remaining_time = seconds_to_hms(app.auto_time_left) app.after(0, lambda: app.automation_button.configure(text=f"자동화 ({remaining_time})")) if app.auto_time_left <= 0: app.after(0, update_label_for_time_finished) if app.stop_event.is_set(): app.after(0, lambda: app.automation_button.configure(text="자동화")) app.auto_time_left_flag = False def auto_count_thread(stop_event): def update_label_for_count_finished(): app.automation_button.configure(text="자동화 (종료됨)") app.auto_time_left_flag = False app.automation_button.deselect() if self.windows_shutdown.get() == 1: shutdown_computer() else: notification.notify( title = '자동생성이 완료되었어요.', message = '결과를 확인해 보세요.', app_name = "NAIA", app_icon = app.basedir+'/icoico.ico', timeout = 5, # seconds ) while not stop_event.is_set(): time.sleep(1) # 주기적으로 확인 app.after(0, lambda: app.automation_button.configure(text=f"자동화 ({app.auto_count_left})")) if app.auto_count_left <= 0: app.after(0, update_label_for_count_finished) break # 루프 탈출 if app.stop_event.is_set(): app.after(0, lambda: app.automation_button.configure(text="자동화")) app.auto_count_left_flag = False # 스레드 시작 및 종료 함수 def start_auto_thread(): app.stop_event = threading.Event() app.auto_thread = None if app.auto_time_left_flag: app.auto_thread = threading.Thread(target=auto_time_thread, args=(app.stop_event,), daemon=True) elif app.auto_count_left_flag: app.auto_thread = threading.Thread(target=auto_count_thread, args=(app.stop_event,), daemon=True) if app.auto_thread is not None: app.auto_thread.start() def stop_auto_thread(self): if app.stop_event is not None: app.stop_event.set() def on_stop(self): stop_auto_thread(self) self.protocol("WM_DELETE_WINDOW", lambda: on_close(self)) class Character_search(customtkinter.CTkToplevel): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.title("캐릭터 검색 및 사전") #self.resizable(width=False, height=False) self.app = app self.attributes('-topmost', True) my_font = customtkinter.CTkFont('Pretendard', 13) character_book_dict = {} favorite_characters = {} try: if os.path.exists('Character_book.json'): with open('Character_book.json', 'r', encoding='utf-8') as f: try: character_book_dict = json.load(f) self.dictionary_parity = True except: character_book_dict = {} except FileNotFoundError: character_book_dict = {} try: if os.path.exists('favorite_characters.json'): with open('favorite_characters.json', 'r', encoding='utf-8') as f: try: favorite_characters = json.load(f) except: favorite_characters = {} except FileNotFoundError: favorite_characters = {} def lost_top_most(self): self.attributes('-topmost', False) def on_close(self): self.withdraw() frame_head = customtkinter.CTkFrame(self, width=750, height=40) frame_head.grid(row =0, column =0, columnspan=5, padx=5, pady=5, sticky="nsew") frame_left = customtkinter.CTkFrame(self, width=300, height=520) frame_left.grid(row =1, column =0, padx=5, pady=5, sticky="nsew") frame_right = customtkinter.CTkFrame(self, width=450, height=520) frame_right.grid(row =1, column =2, padx=5, pady=5, sticky="nsew") search_word = customtkinter.StringVar() search_entry = customtkinter.CTkEntry(frame_head, font=my_font, textvariable=search_word) character_prompt_frame = customtkinter.CTkFrame(frame_right) character_prompt_frame.grid(row=0, column=0, padx=10, pady=5, sticky="nsew") prompt_label = customtkinter.CTkLabel(character_prompt_frame, text="캐릭터 프롬프트: ", font=my_font) prompt_label.grid(row=0, column=0, padx=10, pady=5, sticky="w") def generate_character(self): prompt = character_prompt.get("0.0", "end-1c") prompt_cos = cosplay_prompt.get("0.0", "end-1c") concat_entry = generate_entry.get() + ", {{face focus, upper body}}" keywords = [item.strip() for item in prompt.split(',')] if len(keywords) >= 2: keyword = keywords[1] keywords[1] = '{{'+keyword+'}}' keywords.insert(2, concat_entry) else: keyword = keywords[0] keywords[0] = "{{" + keywords[0] + "}}" request_prompt = ', '.join(keywords) instant_image_generation_book(self, request_prompt, keyword, prompt, prompt_cos) character_prompt_generation = customtkinter.CTkButton(character_prompt_frame, font=my_font, text="즉시생성", fg_color="grey", hover_color="grey10", command=lambda: generate_character(self)) character_prompt_generation.grid(row=0, column=1, padx=5, pady=5, sticky="w") continuous_generation = customtkinter.IntVar() continuous_generation_button = customtkinter.CTkCheckBox(character_prompt_frame, font=my_font, text="빈 도감 자동채우기", variable=continuous_generation) continuous_generation_button.grid(row=0, column=2, padx=5, pady=5, sticky="w") character_prompt = customtkinter.CTkTextbox(frame_right, font=customtkinter.CTkFont('Pretendard', 15), width=450) character_prompt.grid(row=1, column=0, padx=10, pady=5, sticky="w") cosplay_prompt_frame = customtkinter.CTkFrame(frame_right) cosplay_prompt_frame.grid(row=2, column=0, padx=10, pady=5, sticky="nsew") prompt_label = customtkinter.CTkLabel(cosplay_prompt_frame, text="캐릭터(Cosplay)):", font=my_font) prompt_label.grid(row=0, column=0, padx=10, pady=5, sticky="w") #cosplay_prompt_generation = customtkinter.CTkButton(cosplay_prompt_frame, font=my_font, text="즉시생성", fg_color="grey", hover_color="grey10", command=lambda: app.instant_image_generation_book()) #cosplay_prompt_generation.grid(row=0, column=1, padx=5, pady=5, sticky="w") cosplay_prompt = customtkinter.CTkTextbox(frame_right, font=customtkinter.CTkFont('Pretendard', 15), width=450) cosplay_prompt.grid(row=3, column=0, padx=10, pady=5, sticky="w") image_label = customtkinter.CTkLabel(frame_right, text="") image_label.grid(row=0, rowspan=4, column=1, padx=10, pady=5, sticky="w") white_image = Image.new('RGB', (384, 512), 'white') white_photo = customtkinter.CTkImage(white_image, size=(384,512)) image_label.configure(image=white_photo) generate_label = customtkinter.CTkLabel(self, text="Portrait 생성시 적용할 선행 고정 프롬프트 : ", font=my_font) generate_label.grid(row=2, column=0, padx=5, pady=5, sticky="w") generate_entry = customtkinter.CTkEntry(self, font=my_font) generate_entry.grid(row=2, column=1, columnspan=2, padx=5, pady=5, sticky="nsew") if character_book_dict != None and 'user_fix_prompt' in character_book_dict and character_book_dict['user_fix_prompt'] != None: generate_entry.delete(0, "end") generate_entry.insert(0, character_book_dict['user_fix_prompt']) def instant_image_generation_book(self, request_prompt, character_name, p1, p2): if app.running_flag == False and app.automation_button.get() == 0: character_prompt_generation.configure(state="disabled") #cosplay_prompt_generation.configure(state="disabled") app.running_flag == True try: scale_pre = float(scale_pre) except: scale_pre = 5.0 app.cfg_scale_var.set("5.0") rescale_pre = app.prompt_guidance_rescale_entry.get() try: rescale_pre = float(rescale_pre) except: rescale_pre = 0 app.prompt_guidance_rescale_var.set("0") uncond_pre = app.uncond_strength_entry.get() try: uncond_pre = float(uncond_pre) uncond_pre = round(uncond_pre / 0.05) * 0.05 if (uncond_pre > 1.5): uncond_pre = 1.5 app.uncond_strength_entry.delete(0, "end") app.uncond_strength_entry.insert(0, "1.5") except: uncond_pre = 1.0 app.uncond_strength_entry.delete(0, "end") app.uncond_strength_entry.insert(0, "1.0") gen_request = { "width":896, "height":1152, "quality_toggle":app.auto_quality_toggle.get(), "seed":random.randint(0,9999999999), "sampler":app.sampler_button.get(), "scale":scale_pre, "sema":app.sema_button.get(), "sema_dyn": app.dyn_button.get(), "cfg_rescale": rescale_pre, "uncond_scale":uncond_pre, "prompt": request_prompt, "negative":app.negative_prompt_input.get("0.0", "end-1c"), "user_screen_size": app.get_max_size(), "start_time": app.start_time, "access_token": app.access_token, "save_folder": app.output_file_path, "png_rule": app.name_var.get(), "type": "normal" } def run_generation(): if gen_request["png_rule"] == "count": app.generation_count += 1 gen_request["count"] =app.generation_count app.state_label.configure(text ="state : 도감 이미지 요청됨 ", text_color = "#FFFF97") result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request) app.running_flag == False character_prompt_generation.configure(state="normal") #cosplay_prompt_generation.configure(state="normal") app.state_label.configure(text ="state : 도감 이미지 요청 반환됨", text_color = "#DCE4EE") if info: temp = info.get('Comment', '') temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','') else: temp = result_prompt app.image_label_report.configure(state="normal") app.image_label_report.delete("0.0", "end") app.image_label_report.configure(text_color="#DCE4EE") app.image_label_report.insert("0.0", temp) app.image_label_report.configure(state="disabled") if result_image: image_bytes = io.BytesIO() book_image = Image.open(filename).resize((384,512)) book_image = book_image.convert('RGB') book_image.save(image_bytes, format='JPEG', quality=90) image_bytes = base64.b64encode(image_bytes.getvalue()).decode('utf-8') character_book_dict[character_name] = [0, p1, p2, image_bytes] character_book_dict['user_fix_prompt'] = generate_entry.get() fav_button.configure(state="normal") 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]) try: fav_rem_button.grid_forget() fav_button.grid(row = 0, column=0, padx=5, pady=5, sticky="n") except: pass fav_button.configure(state="normal") if keyword in favorite_characters: fav_button.grid_forget() fav_rem_button.grid(row = 0, column=0, padx=5, pady=5, sticky="n") 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") fav_button.configure(state="disabled") 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_frame = customtkinter.CTkFrame(self) search_frame.grid(row = 1, column=1, padx=5, pady=140, sticky="w") def add_favorite(): selected_indices = listbox.curselection() selected_index = selected_indices[0] keyword_with_count = listbox.get(selected_index).strip() keyword = keyword_with_count.split(' - ')[0].strip() words = [word.strip() for word in character_prompt.get("0.0","end").split(',')] description = [] for word in words: if word == keyword or word in tagbag.bag_of_tags[5:] or 'tail' in word or 'pupil' in word: description.append(word) favorite_characters[keyword] = ', '.join(description) with open('favorite_characters.json', 'w', encoding='utf-8') as f: json.dump(favorite_characters, f, ensure_ascii=False, indent=4) with open('wildcards/favorite_character.txt', 'w') as file: for value in favorite_characters.values(): file.write('100:' + value + '\n') fav_button.grid_forget() fav_rem_button.grid(row = 0, column=0, padx=5, pady=5, sticky="n") def rem_favorite(): selected_indices = listbox.curselection() selected_index = selected_indices[0] keyword_with_count = listbox.get(selected_index).strip() keyword = keyword_with_count.split(' - ')[0].strip() del favorite_characters[keyword] with open('favorite_characters.json', 'w', encoding='utf-8') as f: json.dump(favorite_characters, f, ensure_ascii=False, indent=4) with open('wildcards/favorite_character.txt', 'w') as file: for value in favorite_characters.values(): file.write('100:' + value + '\n') fav_rem_button.grid_forget() fav_button.grid(row = 0, column=0, padx=5, pady=5, sticky="n") fav_button = customtkinter.CTkButton(search_frame, font=my_font, text="Favorite 등록", state="disabled", command=add_favorite) fav_button.grid(row = 0, column=0, padx=5, pady=5, sticky="n") fav_rem_button = customtkinter.CTkButton(search_frame, font=my_font, text="Favorite 제거", command=rem_favorite, fg_color="#FFFFFF", hover_color="grey", text_color="#FF362B") search_button = customtkinter.CTkButton(search_frame, font=my_font, text="조회", fg_color="grey", hover_color="grey10", command=on_search) search_button.grid(row = 1, column=0, padx=5, pady=5, sticky="n") 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 ) all_collections.insert(0, ('Favorites', list(favorite_characters.keys()))) split_dict = {} for keyword, value in all_collections: if keyword == 'Favorites': key_in_book = list(favorite_characters.keys()) 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}%" else: key_in_book = copyright_dict_0103.copyright_dict[keyword] cover = sum(key in character_book_dict for key in key_in_book) coverage = f"{round((cover / len(key_in_book)) * 100, 1) if cover else 0}%" # key_in_book의 길이가 90을 초과하는 경우 처리 if len(key_in_book) > 96: for i in range(0, len(key_in_book), 96): part_key = f"{keyword} ({i//96 + 1})" split_dict[part_key] = key_in_book[i:i+96] cover_part = sum(key in character_book_dict for key in split_dict[part_key]) coverage_part = f"{round((cover_part / len(split_dict[part_key])) * 100, 1) if cover_part else 0}%" collection_listbox.insert("end", f"{coverage_part:<7s}{keyword} ({i//96 + 1})") else: split_dict[keyword] = key_in_book collection_listbox.insert("end", f"{coverage:<7s}{keyword}") class Preset_open(customtkinter.CTkToplevel): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.title("프롬프트 검색/설정 프리셋") self.attributes('-topmost', True) self.resizable(width=False, height=False) my_font = customtkinter.CTkFont('Pretendard', 13) presets ={} items = 0 preset_frame_left = customtkinter.CTkFrame(self, width=250, height=520) preset_frame_left.grid(row =1, rowspan=10, column =0, padx=5, pady=5, sticky="nsew") preset_frame_right = customtkinter.CTkFrame(self, width=700, height=520) preset_frame_right.grid(row =1, rowspan=10, column =1, columnspan = 2, padx=5, pady=5, sticky="nsew") preset_insert_right_frame = customtkinter.CTkFrame(self) preset_insert_right_frame.grid(row =0, column =0, columnspan=2, padx=5, pady=5, sticky="nsew") preset_insert_button = customtkinter.CTkButton(preset_insert_right_frame, text="프리셋 추가", font=my_font, command=lambda: add_preset(self, presets)) preset_insert_button.grid(row =0, column =0, padx=5, pady=5, sticky="nsew") preset_insert_name = customtkinter.CTkLabel(preset_insert_right_frame, text="프리셋 명칭 : ", font=my_font) preset_insert_name.grid(row =0, column =1, padx=5, pady=5, sticky="w") preset_insert_name_entry = customtkinter.CTkEntry(preset_insert_right_frame,width=200, font=my_font) preset_insert_name_entry.grid(row =0, column =2, padx=5, pady=5, sticky="w") preset_insert_description = customtkinter.CTkLabel(preset_insert_right_frame, text=" 설명 : ", font=my_font) preset_insert_description.grid(row =0, column =3, padx=5, pady=5, sticky="w") preset_insert_description_entry = customtkinter.CTkEntry(preset_insert_right_frame, width=420, font=my_font) preset_insert_description_entry.grid(row =0, column =4, padx=5, pady=5, sticky="w") preset_frame_bottom = customtkinter.CTkFrame(self) preset_frame_bottom.grid(row =11, column =0, columnspan=2, padx=5, pady=5, sticky="nsew") preset_label = customtkinter.CTkLabel(preset_frame_bottom, text="생성기 내 좌측 패널의 값들을 프리셋으로 저장할 수 있습니다.", font=my_font) preset_label.grid(row =0, column=0,sticky="n" ) def _yield(selected_option): ypreset = self.presets[selected_option] yield_preset_description.configure(text=ypreset['description']) yield_preset_search.configure(text=ypreset['search']) yield_preset_exclude.configure(text=ypreset['exclude']) yield_preset_prompt.configure(state="normal") yield_preset_prompt.delete("0.0", "end") yield_preset_prompt.insert("0.0", ypreset['prompt']) yield_preset_prompt.configure(state="disabled") _text = "" if ypreset['explicit'] == 1: _text += "Explicit " if ypreset['nsfw'] == 1: _text += "NSFW " if ypreset['sensitive'] == 1: _text += "Sensitive " if ypreset['general'] == 1: _text += "General" yield_activated_ratings.configure(text = _text) yield_prefix.configure(state="normal") yield_prefix.delete("0.0", "end") yield_prefix.insert("0.0", ypreset['fix']) yield_prefix.configure(state="disabled") yield_postfix.configure(state="normal") yield_postfix.delete("0.0", "end") yield_postfix.insert("0.0", ypreset['fix_after']) yield_postfix.configure(state="disabled") yield_negative.configure(state="normal") yield_negative.delete("0.0", "end") yield_negative.insert("0.0", ypreset['negative']) yield_negative.configure(state="disabled") yield_autohide.configure(state="normal") yield_autohide.delete("0.0", "end") yield_autohide.insert("0.0", ypreset['auto_hide']) yield_autohide.configure(state="disabled") _text = "" if ypreset['rm_artist'] == 1: _text += "작가명제거 " if ypreset['rm_copyright'] == 1: _text += "작품명제거 " if ypreset['rm_character'] == 1: _text += "캐릭터특징제거" yield_rm.configure(text = _text) preset_list = CTkListbox(preset_frame_left, height=570, font=my_font, command= _yield) preset_list.grid(row = 0, column=0, padx=5, pady=5, sticky="nsew") show_preset_description = customtkinter.CTkButton(preset_frame_right, text="Description", font=my_font, width=150, fg_color="grey10", text_color_disabled="white",state="disabled") show_preset_description.grid(row = 0, column = 0, padx=5, pady=5, sticky="w") yield_preset_description = customtkinter.CTkLabel(preset_frame_right, text="", font=my_font, width=550) yield_preset_description.grid(row = 0, column = 1, padx=5, pady=5, sticky="w") def insert_search(): if preset_list.get(): app.search_label_entry.delete(0, "end") app.search_label_entry.insert(0, yield_preset_search.cget("text")) show_preset_search = customtkinter.CTkButton(preset_frame_right, text="Search Keyword", font=my_font, width=150, fg_color="grey10", hover_color="grey", command=insert_search) show_preset_search.grid(row = 1, column = 0, padx=5, pady=5, sticky="w") yield_preset_search = customtkinter.CTkLabel(preset_frame_right, text="", font=my_font, width=550) yield_preset_search.grid(row = 1, column = 1, padx=5, pady=5, sticky="w") def insert_exclude(): if preset_list.get(): app.exclude_label_entry.delete(0, "end") app.exclude_label_entry.insert(0, yield_preset_exclude.cget("text")) show_preset_exclude = customtkinter.CTkButton(preset_frame_right, text="Exclude Keyword", font=my_font, width=150, fg_color="grey10", hover_color="grey", command=insert_exclude) show_preset_exclude.grid(row = 2, column = 0, padx=5, pady=5, sticky="w") yield_preset_exclude = customtkinter.CTkLabel(preset_frame_right, text="", font=my_font, width=550) yield_preset_exclude.grid(row = 2, column = 1, padx=5, pady=5, sticky="w") def insert_prompt(): if preset_list.get(): app.text_input.delete("0.0","end") app.text_input.insert("0.0", yield_preset_prompt.get("0.0", "end")) show_preset_prompt = customtkinter.CTkButton(preset_frame_right, text="Prompt", font=my_font, width=150, height=100, fg_color="grey10", hover_color="grey", command=insert_prompt) show_preset_prompt.grid(row = 3, column = 0, padx=5, pady=5, sticky="w") yield_preset_prompt = customtkinter.CTkTextbox(preset_frame_right, font=my_font, state="disabled",width=550, height=100, fg_color='#2B2B2B') yield_preset_prompt.grid(row = 3, column = 1, padx=5, pady=5, sticky="w") def insert_ratings(): if preset_list.get(): app.rating_select_explicit.deselect() app.rating_select_nsfw.deselect() app.rating_select_sensitive.deselect() app.rating_select_general.deselect() _text = yield_activated_ratings.cget("text") if "Explicit" in _text: app.rating_select_explicit.select() if "NSFW" in _text: app.rating_select_nsfw.select() if "Sensitive" in _text: app.rating_select_sensitive.select() if "General" in _text: app.rating_select_general.select() show_activated_ratings = customtkinter.CTkButton(preset_frame_right, text="Ratings", font=my_font, width=150, fg_color="grey10", hover_color="grey", command=insert_ratings) show_activated_ratings.grid(row = 4, column = 0, padx=5, pady=5, sticky="w") yield_activated_ratings = customtkinter.CTkLabel(preset_frame_right, text="", font=my_font, width=550) yield_activated_ratings.grid(row = 4, column = 1, padx=5, pady=5, sticky="w") #선행고정 def insert_prefix(): if preset_list.get(): app.fixed_prompt_input.delete("0.0","end") app.fixed_prompt_input.insert("0.0", yield_prefix.get("0.0", "end")) show_prefix = customtkinter.CTkButton(preset_frame_right, text="Pre-fix", font=my_font, width=150, height=50, fg_color="grey10", hover_color="grey", command=insert_prefix) show_prefix.grid(row = 5, column = 0, padx=5, pady=5, sticky="w") yield_prefix = customtkinter.CTkTextbox(preset_frame_right, font=my_font, state="disabled",width=550, height=50, fg_color='#2B2B2B') yield_prefix.grid(row = 5, column = 1, padx=5, pady=5, sticky="w") def insert_postfix(): if preset_list.get(): app.fixed_prompt_after_input.delete("0.0","end") app.fixed_prompt_after_input.insert("0.0", yield_postfix.get("0.0", "end")) show_postfix = customtkinter.CTkButton(preset_frame_right, text="Post-fix", font=my_font, width=150, height=50, fg_color="grey10", hover_color="grey", command=insert_postfix) show_postfix.grid(row = 6, column = 0, padx=5, pady=5, sticky="w") yield_postfix = customtkinter.CTkTextbox(preset_frame_right, font=my_font, state="disabled",width=550, height=50, fg_color='#2B2B2B') yield_postfix.grid(row = 6, column = 1, padx=5, pady=5, sticky="w") def insert_negative(): if preset_list.get(): app.negative_prompt_input.delete("0.0","end") app.negative_prompt_input.insert("0.0", yield_negative.get("0.0", "end")) show_negative = customtkinter.CTkButton(preset_frame_right, text="Negative prompt", font=my_font, width=150, height=70, fg_color="grey10", hover_color="grey", command=insert_negative) show_negative.grid(row = 7, column = 0, padx=5, pady=5, sticky="w") yield_negative = customtkinter.CTkTextbox(preset_frame_right, font=my_font, state="disabled",width=550, height=70, fg_color='#2B2B2B') yield_negative.grid(row = 7, column = 1, padx=5, pady=5, sticky="w") def insert_autohide(): if preset_list.get(): app.auto_hide_keyword_input.delete("0.0","end") app.auto_hide_keyword_input.insert("0.0", yield_autohide.get("0.0", "end")) show_autohide = customtkinter.CTkButton(preset_frame_right, text="Hidden keyword", font=my_font, width=150, height=70, fg_color="grey10", hover_color="grey", command=insert_autohide) show_autohide.grid(row = 8, column = 0, padx=5, pady=5, sticky="w") yield_autohide = customtkinter.CTkTextbox(preset_frame_right, font=my_font, state="disabled",width=550, height=70, fg_color='#2B2B2B') yield_autohide.grid(row = 8, column = 1, padx=5, pady=5, sticky="w") def insert_rm(): if preset_list.get(): app.rm_artist_name_button.deselect() app.rm_copyright_name_button.deselect() app.rm_characteristic_button.deselect() _text = yield_rm.cget("text") if "작가명제거" in _text: app.rm_artist_name_button.select() if "작품명제거" in _text: app.rm_copyright_name_button.select() if "캐릭터특징제거" in _text: app.rm_characteristic_button.select() show_rm = customtkinter.CTkButton(preset_frame_right, text="Options", font=my_font, width=150, fg_color="grey10", hover_color="grey", command=insert_rm) show_rm.grid(row = 9, column = 0, padx=5, pady=5, sticky="w") yield_rm = customtkinter.CTkLabel(preset_frame_right, text="", font=my_font, width=550) yield_rm.grid(row = 9, column = 1, padx=5, pady=5, sticky="w") def apply_all(): if preset_list.get(): insert_search() insert_exclude() insert_prompt() insert_ratings() insert_prefix() insert_postfix() insert_negative() insert_autohide() insert_rm() apply_all = customtkinter.CTkButton(preset_frame_right, text="일괄설정", font=my_font, width=150, command=apply_all) apply_all.grid(row = 10, column = 0, padx=5, pady=5, sticky="w") def remove_preset(self): presets = self.presets preset_name = preset_list.get() if preset_name in presets: del presets[preset_name] save_preset(presets) self.presets = load_preset() update_list(self, self.presets) remove_preset_button = customtkinter.CTkButton(preset_frame_right, text="이 프리셋을 삭제", font=my_font, fg_color="grey10", hover_color="grey", command=lambda: remove_preset(self)) remove_preset_button.grid(row = 10, column =1, padx=5, pady=5, sticky="nsew") def add_preset(self, presets): preset_name = preset_insert_name_entry.get() if len(preset_name.strip()) < 1: preset_label.configure(text="프리셋 이름을 정확히 입력해주세요.", text_color="#FFFF97") else: preset = { 'preset_name':preset_name, 'description':preset_insert_description_entry.get(), 'search':app.search_label_entry.get(), 'exclude':app.exclude_label_entry.get(), 'prompt':app.text_input.get("0.0", "end-1c"), 'fix':app.fixed_prompt_input.get("0.0", "end-1c"), 'fix_after':app.fixed_prompt_after_input.get("0.0", "end-1c"), 'negative':app.negative_prompt_input.get("0.0", "end-1c"), 'auto_hide':app.auto_hide_keyword_input.get("0.0", "end-1c"), 'rm_artist':app.rm_artist_name_button.get(), 'rm_character':app.rm_characteristic_button.get(), 'rm_copyright':app.rm_copyright_name_button.get(), 'explicit':app.rating_select_explicit.get(), 'nsfw':app.rating_select_nsfw.get(), 'sensitive':app.rating_select_sensitive.get(), 'general':app.rating_select_general.get() } updated_preset = {preset_name: preset} if self.presets: updated_preset.update(self.presets) else: self.presets = updated_preset save_preset(updated_preset) self.presets = load_preset() update_list(self, self.presets) def update_list(self, presets): if preset_list.size() != 0: preset_list.delete(0, "END") if presets: for i, names in enumerate(presets.keys()): preset_list.insert(i, names) self.presets = presets def save_preset(presets): with open('NAIA_preset.json', 'w', encoding='utf-8') as f: json.dump(presets, f, ensure_ascii=False, indent=4) def load_preset(): try: if os.path.exists('NAIA_preset.json'): with open('NAIA_preset.json', 'r', encoding='utf-8') as f: return json.load(f) except FileNotFoundError: return {} def on_close(self): self.withdraw() presets = load_preset() update_list(self, presets) self.protocol("WM_DELETE_WINDOW", lambda: on_close(self)) class App(customtkinter.CTk, TkinterDnD.DnDWrapper): access_token = None NAI_ID = None data = Data(wlist, tagbag, arti_list, copyright_list_reformatted, cd, remove_result_e, remove_result_qe) def __init__(self): super().__init__() self.TkdndVersion = TkinterDnD._require(self) if getattr(sys, 'frozen', False): basedir = sys._MEIPASS else: basedir = os.path.dirname(__file__) self.basedir = basedir ctypes.windll.gdi32.AddFontResourceW(os.path.abspath(os.path.join(basedir,"Pretendard-Bold.otf"))) ctypes.windll.gdi32.AddFontResourceW(os.path.abspath(os.path.join(basedir,"Pretendard-Regular.otf"))) my_font = customtkinter.CTkFont('Pretendard', 13) large_font = customtkinter.CTkFont('Pretendard', 13) v_large_font = customtkinter.CTkFont('Pretendard', 14, weight="normal") self.config = configparser.ConfigParser() #UI 사이즈 획득 if os.path.exists('ui_config.ini'): try: self.config.read('ui_config.ini') except: self.config['SET_PROMPT_UI_SIZE'] = { 'MAIN_PROMPT': '200', 'PREFIX_PROMPT': '100', 'POSTFIX_PROMPT': '60', 'NEGATIVE_PROMPT': '100', 'AUTOHIDE_KEYWORD': '100', 'CONDITIONAL_PROMPT': '100', 'CONDITIONAL_NEGATIVE': '100' } with open('ui_config.ini', 'w') as configfile: self.config.write(configfile) else: self.config['SET_PROMPT_UI_SIZE'] = { 'MAIN_PROMPT': '200', 'PREFIX_PROMPT': '100', 'POSTFIX_PROMPT': '60', 'NEGATIVE_PROMPT': '100', 'AUTOHIDE_KEYWORD': '100', 'CONDITIONAL_PROMPT': '100', 'CONDITIONAL_NEGATIVE': '100' } with open('ui_config.ini', 'w') as configfile: self.config.write(configfile) #UI 사이즈 할당 self.ui_size = {} try: self.ui_size['prompt'] = int(self.config['SET_PROMPT_UI_SIZE']['MAIN_PROMPT']) except: self.ui_size['prompt'] = 200 try: self.ui_size['prefix'] = int(self.config['SET_PROMPT_UI_SIZE']['PREFIX_PROMPT']) except: self.ui_size['prefix'] = 100 try: self.ui_size['postfix'] = int(self.config['SET_PROMPT_UI_SIZE']['POSTFIX_PROMPT']) except: self.ui_size['postfix'] = 60 try: self.ui_size['negative'] = int(self.config['SET_PROMPT_UI_SIZE']['NEGATIVE_PROMPT']) except: self.ui_size['negative'] = 100 try: self.ui_size['autohide'] = int(self.config['SET_PROMPT_UI_SIZE']['AUTOHIDE_KEYWORD']) except: self.ui_size['autohide'] = 100 try: self.ui_size['cond_prompt'] = int(self.config['SET_PROMPT_UI_SIZE']['CONDITIONAL_PROMPT']) except: self.ui_size['cond_prompt'] = 100 try: self.ui_size['cond_negative'] = int(self.config['SET_PROMPT_UI_SIZE']['CONDITIONAL_NEGATIVE']) except: self.ui_size['cond_negative'] = 100 #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.hold_wildcard = False #For Generation self.current_prompt_rating = None #json file self.dictionary_parity = False self.start_time_prime = datetime.now() self.start_time = self.start_time_prime.strftime('%Y%m%d_%H%M') self.xy_plot_count = 0 self.import_image_negative = {} self.title("NAIA Beta v1.02") 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) def search_ui_hide(): if self.ui_hide_var.get() == 0: self.NAI_Account_State.configure(text="검색 UI 펼치기") self.search_label.grid_forget() search_hyperlink.grid_forget() self.search_label_entry.grid_forget() self.exclude_label.grid_forget() self.exclude_label_entry.grid_forget() self.select_rating_frame.grid_forget() else: self.NAI_Account_State.configure(text="검색 UI 숨기기") self.search_label.grid(row=1, column=0, padx=8, sticky="w") search_hyperlink.grid(row=1, column=0, padx=8, sticky="e") self.search_label_entry.grid(row=2, column=0, padx=8, sticky="w") self.exclude_label.grid(row=3, column=0, padx=8, sticky="w") self.exclude_label_entry.grid(row=4, column=0, padx=8, sticky="w") self.select_rating_frame.grid(row=6, column=0, padx=8, pady=10, sticky="nsew") #NAI 계정 로그인 상태 self.ui_hide_var = customtkinter.IntVar(value=1) self.NAI_Account_State = customtkinter.CTkCheckBox(self.NAI_Account_Frame, text="NAI Login 필요 ", font=my_font, variable=self.ui_hide_var, command=search_ui_hide, border_color="#333333", fg_color="grey10", hover_color="#50164A") #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, 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 fav_check(id): return id in self.fav_id_list def null_prompt_attention(): self.text_input.delete("0.0", "end") self.text_input.insert("0.0", "현재 조건에 맞는 프롬프트가 없습니다.") def prompt_search(): if not self.control_pressed: self.searching_flag = True self.search_button.configure(text="검색 (작업중)", state="disabled") search_thread = threading.Thread(target=perform_search, daemon=True) self.search_thread = search_thread search_thread.start() else: depth_search() def depth_search(): depth_search_window = customtkinter.CTkToplevel() depth_search_window.title("심층검색") depth_search_window.attributes('-topmost', True) depth_search_window.resizable(width=False, height=False) self.freezed_cached_rows = self.cached_rows.copy() def perform_depth_search(): self.search_button.configure(text="심층검색중", state="disabled") self.searching_flag = True df = self.cached_rows df = NAIA_search.search(df, search_label_entry.get(), exclude_label_entry.get()) if df is None: null_prompt_attention() # 문자열 비었다고 경고 else: self.cached_rows = df df.reset_index(drop=True, inplace=True) update_labels(df) self.searching_flag = False depth_search_execute.configure(text="남은 프롬프트 행에서 재검색 : "+str(len(self.cached_rows))) prompt_rollback.configure(text="이전 프롬프트행 복원 : "+str(len(self.freezed_cached_rows))) self.search_button.configure(text="검색", state="normal") prompt_rollback.configure(state="normal") def rollback(): self.cached_rows = self.freezed_cached_rows.copy() update_labels(self.cached_rows) depth_search_execute.configure(text="남은 프롬프트 행에서 재검색 : "+str(len(self.cached_rows))) prompt_rollback.configure(state="disabled") def depth_search_close(): self.freezed_cached_rows = None depth_search_window.destroy() search_label = customtkinter.CTkLabel(depth_search_window, text="검색 키워드 입력 : keyword, *keyword, {keyword1|keyword2}", font=my_font) search_label.grid(row=1, column=0, columnspan=2, padx=8, pady=5, sticky="w") search_label_entry = customtkinter.CTkEntry(depth_search_window, width=490) search_label_entry.grid(row=2, column=0, columnspan=2, padx=8, pady=5, sticky="w") exclude_label = customtkinter.CTkLabel(depth_search_window, text="제외 키워드 입력 : keyword, ~keyword", font=my_font) exclude_label.grid(row=3, column=0, columnspan=2, padx=8, pady=5, sticky="w") exclude_label_entry = customtkinter.CTkEntry(depth_search_window, width=490) exclude_label_entry.grid(row=4, column=0, columnspan=2, padx=8, pady=5, sticky="w") depth_search_execute = customtkinter.CTkButton(depth_search_window, text="남은 프롬프트 행에서 재검색 : "+str(len(self.cached_rows)), font=my_font, command=perform_depth_search) depth_search_execute.grid(row=5, column=0, padx=5,pady=5, sticky="n") prompt_rollback = customtkinter.CTkButton(depth_search_window, text="이전 프롬프트행 복원 : "+str(len(self.freezed_cached_rows)), font=my_font, fg_color="#7030A0", hover_color="#481F67", command=rollback, state="disabled") prompt_rollback.grid(row=5, column=1, padx=5,pady=5, sticky="n") depth_search_window.protocol("WM_DELETE_WINDOW", depth_search_close) def perform_search(): df = pd.read_parquet(os.path.join(basedir, "tags.parquet"), engine="pyarrow") df = NAIA_search.search(df, self.search_label_entry.get(), self.exclude_label_entry.get(), self.rating_select_explicit.get(), self.rating_select_nsfw.get(), self.rating_select_sensitive.get(), self.rating_select_general.get()) if df is None: null_prompt_attention() # 문자열 비었다고 경고 else: self.cached_rows = df df.reset_index(drop=True, inplace=True) update_labels(df) self.searching_flag = False self.search_button.configure(text="검색", state="normal") def update_labels(df): self.searched_prompt_label.configure(text="검색 프롬프트 행 : " + str(len(self.cached_rows))) self.cached_prompt_label.configure(text="남은 프롬프트 행 : " + str(len(self.cached_rows))) print(df.info(memory_usage="deep")) #검색 버튼 self.search_button = customtkinter.CTkButton(self.select_rating_frame, text="검색", font=my_font, command=prompt_search, width=130) self.search_button.grid(row=0, column=4,padx=5, sticky="w") #검색 결과 관리 창 self.searched_prompt_frame = customtkinter.CTkFrame(self.search_frame) self.searched_prompt_frame.grid(row=7, column=0, padx=8, pady=5, sticky="nsew") self.searched_prompt_frame.columnconfigure(0, weight= 1) self.searched_prompt_frame.columnconfigure(1, weight= 1) self.searched_prompt_frame.columnconfigure(2, weight= 1) self.searched_prompt_label = customtkinter.CTkLabel(self.searched_prompt_frame, text="검색 프롬프트 행 : 0", font=my_font) self.searched_prompt_label.grid(row=0, column=0, sticky="ew") self.cached_prompt_label = customtkinter.CTkLabel(self.searched_prompt_frame, text="남은 프롬프트 행 : 0", font=my_font) self.cached_prompt_label.grid(row=0, column=1, sticky="ew") fdf = None self.Preset_open = None def open_Preset(self): if self.Preset_open is None: self.Preset_open = Preset_open(self) else: if self.Preset_open.state() == 'withdrawn': self.Preset_open.deiconify() else: self.Preset_open.focus() def open_favorite(): favorite_window = customtkinter.CTkToplevel() favorite_window.title("선호 프롬프트") favorite_window.attributes('-topmost', True) favorite_window.resizable(width=False, height=False) self.freezed_cached_rows = self.cached_rows.copy() global fdf fdf = pd.read_parquet("favorite_prompt.parquet", engine="pyarrow") odf = fdf.copy() max_page = [1 + len(fdf) // 5] def perform_favorite_search(): global fdf fdf = NAIA_search.search(odf, search_label_entry.get(), exclude_label_entry.get()) if type(fdf) == type(None): assign_row.configure(text="검색 결과 없음") return assign_row.configure(text="랜덤 프롬프트에 삽입 "+str(len(fdf))) prompt_rollback.configure(text="이전 프롬프트행 복원 : "+str(len(self.freezed_cached_rows))) self.search_button.configure(text="검색", state="normal") max_page[0] = 1 + len(fdf) // 5 current_page[0] = 0 page.configure(text=f" 1 / {max_page[0]} ") prev_button.configure(state="disabled") if max_page[0] == 1: next_button.configure(state="disabled") else: next_button.configure(state="normal") update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font) def import_prompt(): global fdf if fdf is None: null_prompt_attention() # 문자열 비었다고 경고 else: self.cached_rows = fdf.copy() fdf.reset_index(drop=True, inplace=True) update_labels(fdf) prompt_rollback.configure(state="normal") def rollback(): global fdf self.cached_rows = self.freezed_cached_rows.copy() update_labels(self.cached_rows) assign_row.configure(text="랜덤 프롬프트에 삽입 "+str(len(fdf))) prompt_rollback.configure(state="disabled") def favorite_search_close(): self.freezed_cached_rows = None favorite_window.destroy() search_frame = customtkinter.CTkFrame(favorite_window, width=990) search_frame.grid(row=0, column=0, padx=5,pady=5, sticky="nsew") search_label = customtkinter.CTkLabel(search_frame, text="검색 키워드 입력 : keyword, *keyword, {keyword1|keyword2}", font=my_font) search_label.grid(row=0, column=0, columnspan=2, padx=8, pady=5, sticky="nsew") search_label_entry = customtkinter.CTkEntry(search_frame, width=485) search_label_entry.grid(row=1, column=0, columnspan=2, padx=8, pady=5, sticky="nsew") exclude_label = customtkinter.CTkLabel(search_frame, text="제외 키워드 입력 : keyword, ~keyword", font=my_font) exclude_label.grid(row=0, column=2, columnspan=2, padx=8, pady=5, sticky="nsew") exclude_label_entry = customtkinter.CTkEntry(search_frame, width=485) exclude_label_entry.grid(row=1, column=2, columnspan=2, padx=8, pady=5, sticky="nsew") depth_search_execute = customtkinter.CTkButton(search_frame, text="선호 프롬프트내 검색", font=my_font, command=perform_favorite_search) depth_search_execute.grid(row=2, column=0, padx=5,pady=5, sticky="n") assign_row = customtkinter.CTkButton(search_frame, text="랜덤 프롬프트에 삽입 "+str(len(fdf)), font=my_font, fg_color="#CDCDCD", text_color="black", hover_color="#848484", command=import_prompt) assign_row.grid(row=2, column=1, padx=5,pady=5, sticky="n") prompt_rollback = customtkinter.CTkButton(search_frame, text="이전 프롬프트행 복원 : "+str(len(self.freezed_cached_rows)), font=my_font, fg_color="#7030A0", hover_color="#481F67", command=rollback, state="disabled") prompt_rollback.grid(row=2, column=2, padx=5,pady=5, sticky="n") page_frame = customtkinter.CTkFrame(search_frame) page_frame.grid(row=2, column=3, padx=5,pady=5 ,sticky="nsew") def prev_pressed(): current_page[0] -= 1 if current_page[0] <= 0: prev_button.configure(state="disabled") if current_page[0] < max_page[0]: next_button.configure(state="normal") page.configure( text=f"{1+current_page[0]} / {max_page[0]} ") update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font) def next_pressed(): current_page[0] += 1 if current_page[0] >= max_page[0]-1: next_button.configure(state="disabled") prev_button.configure(state="normal") page.configure( text=f"{1+current_page[0]} / {max_page[0]} ") update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font) page = customtkinter.CTkLabel(page_frame, text=f" 1 / {max_page[0]} ", font=my_font, width=70) page.grid(row=0, column=1, padx=5, sticky="nsew") prev_button = customtkinter.CTkButton(page_frame, text=" ◀ Prev ", font=my_font, width=70, state="disabled", command=prev_pressed) prev_button.grid(row=0, column=0, padx=5 ,sticky="nsew") next_button = customtkinter.CTkButton(page_frame, text=" Next ▶ ", font=my_font, width=70, command=next_pressed) next_button.grid(row=0, column=2, padx=5, sticky="nsew") if max_page[0] == 1: next_button.configure(state="disabled") favorite_window.protocol("WM_DELETE_WINDOW", favorite_search_close) headers = ['↙', 'character', 'copyright', 'artist', 'general prompts', 'image', 'delete'] headers_width = [60, 120, 120, 120, 360, 120, 60] header_frame = customtkinter.CTkFrame(favorite_window) header_frame.grid(row=6, column=0, padx=5,pady=5, sticky="nsew") empty_image = customtkinter.CTkImage(Image.new('RGB', size=(192,192), color="#2B2B2B"), size=(120, 120)) for i, header in enumerate(headers): label = customtkinter.CTkLabel(header_frame, text=header, width=headers_width[i], font=my_font) label.grid(row=0, column=i, sticky="nsew", padx=5) ui_elements = [] # UI 요소 저장용 이중 리스트 for i in range(5): # DataFrame 길이를 고려 row_elements = [] if i < len(fdf): row = fdf.iloc[i] row_frame = customtkinter.CTkFrame(favorite_window) row_frame.grid(row=i+7, column=0, sticky="nsew", padx=5, pady=5) for j, header in enumerate(['↙', 'character', 'copyright', 'artist', 'general', 'image', 'delete']): if header == '↙': button = customtkinter.CTkButton( row_frame, width=headers_width[j], font=my_font, text="↙", height=28, state="disabled" ) button.grid(row=0, padx=5, column=j, sticky="nsew") element = button elif header == 'delete': delete_button = customtkinter.CTkButton( row_frame, width=headers_width[j], font=my_font, text="✖", height=28, fg_color="grey", hover_color="grey10", state="disabled" ) delete_button.grid(row=0, padx=5, column=j, sticky="nsew") element = delete_button elif header == 'image': label = customtkinter.CTkLabel(row_frame, width=headers_width[j], font=my_font, text=" ", height=120) label.grid(row=0, padx=5, column=j, sticky="nsew") element = label else: text = customtkinter.CTkTextbox(row_frame, width=headers_width[j], font=my_font, height=120) text.grid(row=0, padx=5, column=j, sticky="nsew") element = text row_elements.append(element) ui_elements.append(row_elements) # 각 행의 UI 요소를 추가 # 이미지 삭제 함수 def delete_image(image_path): try: os.remove(image_path) except OSError as e: print(f"Error deleting file {image_path}: {e.strerror}") # DataFrame 행 삭제 및 업데이트 함수 def delete_row(fdf, idx, image_path, basedir): # DataFrame에서 특정 id 값을 가진 행을 'deleted'로 표시 fdf.loc[fdf['id'] == idx, 'deleted'] = 'deleted' # DataFrame에서 특정 행 삭제 fdf.drop(fdf[fdf['id'] == idx].index, inplace=True) # 변경된 DataFrame을 parquet 파일로 저장 fdf.to_parquet("favorite_prompt.parquet", engine='pyarrow') # 이미지 파일 삭제 delete_image(image_path) update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font) # 삭제 버튼 클릭 시 실행될 함수를 생성하는 함수 def make_delete_command(fdf, idx, image_path, basedir): def command(): delete_row(fdf, idx, image_path, basedir) return command def make_select_command(dataframe, row_id): """ 특정 DataFrame 행의 'id' 값을 출력하는 커맨드를 생성하는 함수. 이 함수는 람다 함수를 사용하여 버튼에 할당될 커맨드를 반환합니다. """ def command(): popped_row = dataframe.loc[dataframe['id'] == row_id] if not popped_row.empty: popped_row_series = popped_row.iloc[0] # 첫 번째 행을 Series로 변환 # 얻은 Series에 random_function을 적용합니다. random_function(popped_row_series) return command def update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font): global fdf base_image_path = "favorite_prompts" rows_per_page = 5 start_index = current_page[0] * rows_per_page # current_page[0]에서 수정됨, current_page가 이미 정수라고 가정 end_index = min(start_index + rows_per_page, len(fdf)) for i in range(5): # 최대 5개의 행을 처리 # 현재 페이지에 표시할 데이터가 있는 경우 if i < end_index - start_index: row = fdf.iloc[start_index + i] for j, header in enumerate(['↙', 'character', 'copyright', 'artist', 'general', 'image', 'delete']): element = ui_elements[i][j] # 기존 UI 요소에 접근 if header == '↙': # '↙' 버튼의 커맨드 업데이트 element.configure(state="normal", command=make_select_command(fdf, row['id'])) elif header == 'delete': # 'delete' 버튼의 커맨드 업데이트 image_path = f"{base_image_path}/{row['id']}.jpg" element.configure(state="normal", command=make_delete_command(fdf, row['id'], image_path, basedir)) elif header == 'image': try: image_path = f"{base_image_path}/{row['id']}.jpg" if os.path.exists(image_path): _image = customtkinter.CTkImage(Image.open(image_path), size=(120, 120)) element.configure(image=_image) else: raise FileNotFoundError except FileNotFoundError: element.configure(text="Image Not Found") else: # 텍스트박스의 텍스트 업데이트 text_value = row[header] if pd.notna(row[header]) else "" element.delete("0.0", "end") element.insert("0.0", text_value) else: # 현재 페이지에 표시할 데이터가 없는 경우, 비어 있는 행의 내용을 초기화 for j, element in enumerate(ui_elements[i]): if isinstance(element, customtkinter.CTkLabel): element.configure(text=" ", image=empty_image) element.image = empty_image elif isinstance(element, customtkinter.CTkTextbox): element.delete("0.0", "end") elif isinstance(element, customtkinter.CTkButton): element.configure(state="disabled") # 현재 페이지를 0으로 설정 (0부터 시작) current_page = [0] # UI 업데이트 함수 호출 update_ui_with_dataframe(current_page, favorite_window, headers_width, my_font) favorite_window.after(1500, lambda: favorite_window.attributes('-topmost', False)) self.prompt_preset_button = customtkinter.CTkButton(self.searched_prompt_frame, width=80, text="프리셋", fg_color="#848484", font=my_font, command= lambda: open_Preset(self)) self.prompt_preset_button.grid(row=0, column=2, sticky="w") self.fav_button = customtkinter.CTkButton(self.searched_prompt_frame, width=40, text=" ★ ", font=my_font, fg_color="#7030A0", hover_color="#481F67", command= open_favorite) self.fav_button.grid(row=0, column=2, padx=15, sticky="e") try: temp_df = pd.read_parquet("favorite_prompt.parquet", engine="pyarrow") self.fav_id_list = [] if 'id' in temp_df.columns: self.fav_id_list.extend(temp_df['id'].tolist()) del(temp_df) except: self.fav_id_list = [] #여기서 오류남 이따 고치셈 self.fav_button.configure(state="disabled") def highlight_text(event=None): if '#' in self.text_input.get("1.0", tk.END): # 기존의 하이라이트를 모두 제거 self.text_input.tag_remove("highlight", "1.0", tk.END) # '#'으로 시작하여 ','나 '\n', 또는 텍스트 끝까지 이어지는 모든 부분을 찾음 for match in re.finditer(r'#.*?([,\n]|$)', self.text_input.get("1.0", tk.END)): start = "1.0 + {}c".format(match.start()) end = "1.0 + {}c".format(match.end()) self.text_input.tag_add("highlight", start, end) def on_enter_pressed(event): if self.control_pressed: NAIA_generate(self) return "break" else: highlight_text() 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, height=self.ui_size['prompt'], font=v_large_font, undo=True) 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) self.text_input.bind("", highlight_text) self.text_input.tag_config("highlight", foreground="#FFFF97") self.current_popped_row = None def random_function(edf = None): if(self.random_function_pressed) == False: self.random_function_pressed = True self.random_function_button.configure(state="disabled") if type(edf) == type(None): if self.toggle_prompt_fix.get()==0 and type(self.cached_rows) == type(None): self.text_input.delete("0.0", "end") self.text_input.insert("0.0", "먼저 키워드 검색을 해 주세요.") self.random_function_button.configure(state="normal") self.random_function_pressed = False return if self.toggle_prompt_fix.get()==1 and type(self.cached_rows) == type(None): self.random_function_pressed = False return elif self.toggle_prompt_fix.get()==0 and self.cached_rows.empty: if (self.automation_button.get() == 0): self.text_input.delete("0.0", "end") self.text_input.insert("0.0", "먼저 키워드 검색을 해 주세요.") self.random_function_button.configure(state="normal") self.random_function_pressed = False return elif type(self.freezed_cached_rows) != type(None): self.text_input.delete("0.0", "end") self.text_input.insert("0.0", "기존 프롬프트를 복원합니다.") self.cached_rows = self.freezed_cached_rows.copy() time.sleep(1) self.random_function_button.configure(state="normal") self.random_function_pressed = False app.after(0, random_function) return else: self.text_input.delete("0.0", "end") self.text_input.insert("0.0", "재검색을 수행합니다.") prompt_search() while(self.cached_rows.empty): time.sleep(1) self.random_function_button.configure(state="normal") self.random_function_pressed = False app.after(0, random_function) return if self.toggle_prompt_fix.get(): self.random_function_pressed = False return else: if self.random_artist_button.get() == 1: try: if self.random_artist_prefix.get() == "artist:": random_artist_name = "artist:"+ random.choice(self.random_artist) elif self.random_artist_prefix.get() == "(artist)": random_artist_name = random.choice(self.random_artist)+" (artist)" else: random_artist_name = random.choice(self.random_artist) except: random_artist_name = "" magic_word = { "random_artist":True, "random_artist_name": random_artist_name } else: magic_word = { "random_artist":False } if self.cond_prompt_button_var.get() == 1: magic_word["cond"] = self.conditional_prompt_input.get("0.0", "end-1c") if len(self.conditional_prompt_input.get("0.0", "end-1c")) > 4 else None if type(edf) == type(None): random_index = np.random.choice(self.cached_rows.index) popped_row = self.cached_rows.loc[random_index] self.current_popped_row = popped_row.copy() self.cached_rows.drop(random_index, inplace=True) self.cached_prompt_label.configure(text = "남은 프롬프트 행 : "+str(len(self.cached_rows))) else: popped_row = edf.copy() self.current_popped_row = popped_row.copy() if(self.toggle_wildcard_preopen.get()==1): if(self.wildcard_preopen_repeat_current >= self.wildcard_preopen_repeat): self.wildcard_preopen_repeat_current = 0 #와일드카드 개봉 구현 temp_fixed = self.fixed_prompt_input.get("0.0", "end") temp_fixed = [item.strip() for item in temp_fixed.split(',')] global_temp = [] if '<' in self.fixed_prompt_input.get("0.0", "end"): wildcard_present = True itc = 0 while (wildcard_present and itc < 10): wildcard_present = False #### 단계 1 : 인스턴트 와일드카드 처리 ### for i, keyword in enumerate(temp_fixed): if keyword.startswith('<') and keyword.endswith('>'): wildcard_present = True vbar_check = keyword[1:-1] if '|' in vbar_check: choices = vbar_check.split('|') # '|'를 기준으로 split choice_dic = {} for choice in choices: match = re.match(r'(\d*\.?\d+):(.+)', choice) if match: value, keyword = float(match.group(1)), match.group(2).strip() else: value, keyword = 1, choice.strip() choice_dic[keyword] = value keywords = list(choice_dic.keys()) weights = list(choice_dic.values()) selected_instant_wildcard = random.choices(keywords, weights=weights, k=1)[0] temp_fixed[i] = selected_instant_wildcard #### 단계 2 : 글로벌 와일드카드 처리 ### for i, keyword in enumerate(temp_fixed): if "<" in keyword and ">" in keyword: wildcard_present = True input_str = keyword.strip('<>').strip() if("__" in input_str): adjectives = re.findall(r'__(.*?)__', input_str) last_keyword = re.split(r'__.*?__', input_str)[-1] adjective_string = "" for adjective in adjectives: adjective_string += (self.get_wildcard(adjective) + " ") temp_fixed[i] = adjective_string + self.get_wildcard(last_keyword) else: out_wildcard = self.get_wildcard(input_str) if ',' in out_wildcard: split_wc = [item.strip() for item in out_wildcard.split(',')] temp = [] for _key in split_wc[1:]: if "{" not in _key and "}" not in _key and "[" not in _key and "]" not in _key: temp.append(_key) if temp: for _key in temp: split_wc.remove(_key) global_temp.append(_key) if len(split_wc) == 2 and '{' not in split_wc[1] and '[' not in split_wc[1] and (split_wc[1].endswith('}') or split_wc[1].endswith(']')): wc_post = split_wc[1].replace(']','').replace('}','') global_temp.append(wc_post) split_wc[0] += split_wc[1].replace(wc_post, '') split_wc.pop() out_wildcard = ', '.join(split_wc) temp_fixed[i] = out_wildcard itc += 1 if not wildcard_present: break temp_fixed_result = ', '.join(temp_fixed) if global_temp: temp_fixed_result += ', '+', '.join(global_temp) self.previous_fix_prompt = temp_fixed_result else: temp_fixed_result = self.previous_fix_prompt self.wildcard_preopen_repeat_current += 1 if isinstance(popped_row, pd.DataFrame): popped_row = popped_row.iloc[0] prompt, self.current_prompt_rating = NAIA_random_function_core.RFP(popped_row, temp_fixed_result, self.fixed_prompt_after_input.get("0.0", "end"), self.auto_hide_keyword_input.get("0.0", "end") ,self.rm_artist_name_button.get(), self.rm_copyright_name_button.get(),self.rm_characteristic_button.get(), self.rm_not_nsfw_button.get(), self.data, magic_word) else: if isinstance(popped_row, pd.DataFrame): popped_row = popped_row.iloc[0] prompt, self.current_prompt_rating = NAIA_random_function_core.RFP(popped_row, self.fixed_prompt_input.get("0.0", "end"), self.fixed_prompt_after_input.get("0.0", "end"), self.auto_hide_keyword_input.get("0.0", "end") ,self.rm_artist_name_button.get(), self.rm_copyright_name_button.get(),self.rm_characteristic_button.get(), self.rm_not_nsfw_button.get(), self.data, magic_word) self.text_input.delete("0.0", "end") self.text_input.insert("0.0", prompt) app.after(100, lambda: self.random_function_button.configure(state="normal")) self.random_function_pressed = False app.after(100, highlight_text) self.random_function_pressed = False self.running_flag = False self.error_count = 0 self.turbo_fail_count = 0 self.anlas_request = False self.image_generation_repeat_prompt = "" def NAIA_generate(self): if self.seed_fix_button.get() == 0: self.entry_seed_value.set(random.randint(0,9999999999)) if self.random_resolution_button.get() == 1: resolutions = ["1024 x 1024", "960 x 1088", "896 x 1152", "832 x 1216", "1088 x 960", "1152 x 896", "1216 x 832"] random_resolution = random.choice(resolutions) self.resolution_button.set(random_resolution) if self.cached_rows is None and self.toggle_prompt_fix_button.get() == 0 and self.automation_button.get() == 1: self.state_label.configure(text ="state : 자동화 전 프롬프트 검색을 수행하는 중 입니다", text_color = "#FFFF97") prompt_search() if self.turbo_button.get() == 1: origin = self.text_input.get("0.0", "end-1c") pretest = [keyword.strip() for keyword in origin.split(',')] if ('*(split nsfw)' in pretest or '*(split nsfw)-rand' in pretest): pass elif (('sex' not in pretest and 'group sex' not in pretest) or ('1girl' not in pretest and 'girls' not in origin[:20]) or ('1boy' not in pretest and 'boys' not in origin[:20])): self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " Explicit Turbo 기능은 프롬프트 내에 1girl/girls, 1boy/boys, sex/group sex가 존재할 때 사용 가능합니다.") self.turbo_fail_count += 1 if self.turbo_fail_count >= 20: self.turbo_button.deselect() self.image_label_report.configure(text_color="#FFFF97") self.image_label_report.configure(state="disabled") if self.automation_button.get() == 1 and self.toggle_prompt_fix_button.get() == 0: random_function() time.sleep(0.5) if self.searching_flag == True: self.search_thread.join() return self.event_generate(GENERATE_EVENT, when="tail") elif self.automation_button.get() == 1 and self.toggle_prompt_fix_button.get() == 1: self.automation_button.deselect() return else: return self.turbo_fail_count = 0 if not self.running_flag: self.image_generation_button.configure(state="disabled") self.running_flag = True NAI_width, NAI_height = self.resolution_button.get().split(' x ') NAI_width = str((int(NAI_width) // 64) * 64) NAI_height = str((int(NAI_height) // 64) * 64) if int(NAI_height) * int(NAI_width) > 1048576: self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " Anlas가 소모되는 해상도 요청입니다.") self.image_label_report.configure(text_color="#FFFF97") self.image_label_report.configure(state="disabled") self.anlas_request = True scale_pre = self.cfg_scale_entry.get() try: scale_pre = float(scale_pre) except: scale_pre = 5.0 self.cfg_scale_var.set("5.0") rescale_pre = self.prompt_guidance_rescale_entry.get() try: rescale_pre = float(rescale_pre) except: rescale_pre = 0 self.prompt_guidance_rescale_var.set("0") uncond_pre = self.uncond_strength_entry.get() try: uncond_pre = float(uncond_pre) uncond_pre = round(uncond_pre / 0.05) * 0.05 if (uncond_pre > 1.5): uncond_pre = 1.5 self.uncond_strength_entry.delete(0, "end") self.uncond_strength_entry.insert(0, "1.5") except: uncond_pre = 1.0 self.uncond_strength_entry.delete(0, "end") self.uncond_strength_entry.insert(0, "1.0") #### 여기서부터 와일드카드 처리 구문 #### if self.image_generation_repeat_flag == False: before_wildcard = self.text_input.get("0.0", "end-1c") before_wildcard = [item.strip() for item in before_wildcard.split(',')] if '<' in self.text_input.get("0.0", "end-1c"): wildcard_present = True itc = 0 while (wildcard_present and itc < 10): wildcard_present = False #### 단계 1 : 인스턴트 와일드카드 처리 ### for i, keyword in enumerate(before_wildcard): if keyword.startswith('<') and keyword.endswith('>'): wildcard_present = True vbar_check = keyword[1:-1] if '|' in vbar_check: choices = vbar_check.split('|') # '|'를 기준으로 split choice_dic = {} for choice in choices: match = re.match(r'(\d*\.?\d+):(.+)', choice) if match: value, keyword = float(match.group(1)), match.group(2).strip() else: value, keyword = 1, choice.strip() choice_dic[keyword] = value keywords = list(choice_dic.keys()) weights = list(choice_dic.values()) selected_instant_wildcard = random.choices(keywords, weights=weights, k=1)[0] before_wildcard[i] = selected_instant_wildcard #### 단계 2 : 글로벌 와일드카드 처리 ### for i, keyword in enumerate(before_wildcard): if "<" in keyword and ">" in keyword: wildcard_present = True input_str = keyword.strip('<>').strip() if("__" in input_str): adjectives = re.findall(r'__(.*?)__', input_str) last_keyword = re.split(r'__.*?__', input_str)[-1] adjective_string = "" for adjective in adjectives: adjective_string += (self.get_wildcard(adjective) + " ") before_wildcard[i] = adjective_string + self.get_wildcard(last_keyword) else: before_wildcard[i] = self.get_wildcard(input_str) itc += 1 if not wildcard_present: break else: after_wildcard = self.text_input.get("0.0", "end-1c") after_wildcard = ', '.join(before_wildcard) if self.image_generation_repeat > 1 and self.hold_wildcard: 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 elif self.image_generation_repeat > 1 and not self.hold_wildcard: self.image_generation_repeat_current += 1 ############################## gen_request = { "width":NAI_width, "height":NAI_height, "quality_toggle":self.auto_quality_toggle.get(), "seed":self.seed_entry.get(), "sampler":self.sampler_button.get(), "scale":scale_pre, "uncond_scale":uncond_pre, "sema":self.sema_button.get(), "sema_dyn": self.dyn_button.get(), "cfg_rescale": rescale_pre, "prompt": after_wildcard, "negative":self.negative_prompt_input.get("0.0", "end-1c"), "user_screen_size": self.get_max_size(), "start_time": self.start_time, "access_token": self.access_token, "save_folder": self.output_file_path, "png_rule": self.name_var.get(), "type": "normal", "rating":self.current_prompt_rating } if self.cond_negative_button_var.get() == 1: gen_request["cond_negative"] = self.conditional_negative_input.get("0.0", "end-1c") if self.turbo_button.get() == 1 and "*(split nsfw)"in gen_request["prompt"]: request_list = [] pre_prompt = gen_request["prompt"] pre_prompt = [keyword.strip() for keyword in pre_prompt.split(',')] fix_words = self.fixed_prompt_input.get("0.0", "end-1c")+", "+self.fixed_prompt_after_input.get("0.0", "end-1c") fix_words = [keyword.strip() for keyword in fix_words.split(',')] if "*(split nsfw)-rand" in pre_prompt: pre_prompt.remove("*(split nsfw)-rand") random_seed = True else: pre_prompt.remove("*(split nsfw)") random_seed = False nsfw_word = [] colors = ['black','blond','silver','gray','yellow','blue','purple','red','pink','brown','orange','green','aqua','gradient'] qe_word = app.data.get_qe_word() + ['cross-section', 'x-ray'] for keyword in pre_prompt: #전처리 if 'mouth' in keyword or 'eyes' in keyword: if keyword not in fix_words: pre_prompt.remove(keyword) for keyword in pre_prompt: if '{' not in keyword and '[' not in keyword and keyword in qe_word and any(color not in keyword for color in colors) : nsfw_word.append(keyword) if len(nsfw_word) != 0: basket = [] for keyword in nsfw_word: if 'cross-section' in keyword or 'x-ray' in keyword: if keyword not in basket: basket.append(keyword) for keyword in nsfw_word: if 'internal cumshot' in keyword or 'ejaculation' in keyword: if keyword not in basket: basket.append(keyword) for keyword in nsfw_word: if 'cum' in keyword or 'ahegao' in keyword: if keyword not in basket: basket.append(keyword) for keyword in nsfw_word: if 'after ' in keyword: if keyword not in basket: basket.append(keyword) for keyword in basket: if keyword in nsfw_word: nsfw_word.remove(keyword) nsfw_word += basket words = [] if len(nsfw_word) > 13: max_val = len(nsfw_word) // 4 if len(nsfw_word) % 4 > 0: max_val += 1 for i in range(max_val): current_word = [] if i < max_val - 1: words.append(nsfw_word[i*4]) words.append(nsfw_word[i*4+1]) words.append(nsfw_word[i*4+2]) words.append(nsfw_word[i*4+3]) current_word.append(nsfw_word[i*4]) current_word.append(nsfw_word[i*4+1]) current_word.append(nsfw_word[i*4+2]) current_word.append(nsfw_word[i*4+3]) else: if len(nsfw_word) % 4 == 0: words.append(nsfw_word[i*4]) words.append(nsfw_word[i*4+1]) words.append(nsfw_word[i*4+2]) words.append(nsfw_word[i*4+3]) current_word.append(nsfw_word[i*4]) current_word.append(nsfw_word[i*4+1]) current_word.append(nsfw_word[i*4+2]) current_word.append(nsfw_word[i*4+3]) elif len(nsfw_word) % 4 == 3: words.append(nsfw_word[i*4]) words.append(nsfw_word[i*4+1]) words.append(nsfw_word[i*4+2]) current_word.append(nsfw_word[i*4]) current_word.append(nsfw_word[i*4+1]) current_word.append(nsfw_word[i*4+2]) elif len(nsfw_word) % 4 == 2: words.append(nsfw_word[i*4]) words.append(nsfw_word[i*4+1]) current_word.append(nsfw_word[i*4]) current_word.append(nsfw_word[i*4+1]) else: words.append(nsfw_word[i*4]) current_word.append(nsfw_word[i*4]) gen_request_sub = copy.deepcopy(gen_request) temp_prompt = []+pre_prompt for keyword in nsfw_word: if keyword not in words: if random_seed == False: temp_prompt[temp_prompt.index(keyword)] = " "*len(keyword) else: temp_prompt.remove(keyword) elif keyword in current_word: temp_prompt[temp_prompt.index(keyword)] = "{"+keyword+"}" gen_request_sub["prompt"] = ', '.join(temp_prompt) if random_seed: gen_request_sub["seed" ] = random.randint(0,9999999999) request_list.append(copy.deepcopy(gen_request_sub)) elif len(nsfw_word) > 8: max_val = len(nsfw_word) // 3 if len(nsfw_word) % 3 > 0: max_val += 1 for i in range(max_val): current_word = [] if i < max_val - 1: words.append(nsfw_word[i*3]) words.append(nsfw_word[i*3+1]) words.append(nsfw_word[i*3+2]) current_word.append(nsfw_word[i*3]) current_word.append(nsfw_word[i*3+1]) current_word.append(nsfw_word[i*3+2]) else: if len(nsfw_word) % 3 == 0: words.append(nsfw_word[i*3]) words.append(nsfw_word[i*3+1]) words.append(nsfw_word[i*3+2]) current_word.append(nsfw_word[i*3]) current_word.append(nsfw_word[i*3+1]) current_word.append(nsfw_word[i*3+2]) elif len(nsfw_word) % 3 == 2: words.append(nsfw_word[i*3]) words.append(nsfw_word[i*3+1]) current_word.append(nsfw_word[i*3]) current_word.append(nsfw_word[i*3+1]) else: words.append(nsfw_word[i*3]) current_word.append(nsfw_word[i*3]) gen_request_sub = copy.deepcopy(gen_request) temp_prompt = []+pre_prompt for keyword in nsfw_word: if keyword not in words: if random_seed == False: temp_prompt[temp_prompt.index(keyword)] = " "*len(keyword) else: temp_prompt.remove(keyword) elif keyword in current_word: temp_prompt[temp_prompt.index(keyword)] = "{"+keyword+"}" gen_request_sub["prompt"] = ', '.join(temp_prompt) if random_seed: gen_request_sub["seed" ] = random.randint(0,9999999999) request_list.append(copy.deepcopy(gen_request_sub)) elif len(nsfw_word) > 3: max_val = len(nsfw_word) // 2 + len(nsfw_word) % 2 for i in range(max_val): current_word = [] if i < max_val - 1: words.append(nsfw_word[i*2]) words.append(nsfw_word[i*2+1]) current_word.append(nsfw_word[i*2]) current_word.append(nsfw_word[i*2+1]) else: if len(nsfw_word) % 2 == 0: words.append(nsfw_word[i*2]) words.append(nsfw_word[i*2+1]) current_word.append(nsfw_word[i*2]) current_word.append(nsfw_word[i*2+1]) else: words.append(nsfw_word[i*2]) current_word.append(nsfw_word[i*2]) gen_request_sub = copy.deepcopy(gen_request) temp_prompt = []+pre_prompt for keyword in nsfw_word: if keyword not in words: if random_seed == False: temp_prompt[temp_prompt.index(keyword)] = " "*len(keyword) else: temp_prompt.remove(keyword) elif keyword in current_word: temp_prompt[temp_prompt.index(keyword)] = "{"+keyword+"}" gen_request_sub["prompt"] = ', '.join(temp_prompt) if random_seed: gen_request_sub["seed" ] = random.randint(0,9999999999) request_list.append(copy.deepcopy(gen_request_sub)) else: for word in nsfw_word: words.append(word) gen_request_sub = copy.deepcopy(gen_request) temp_prompt = []+pre_prompt for keyword in nsfw_word: if keyword not in words: if random_seed == False: temp_prompt[temp_prompt.index(keyword)] = " "*len(keyword) else: temp_prompt.remove(keyword) elif keyword == word: temp_prompt[temp_prompt.index(keyword)] = "{"+word+"}" gen_request_sub["prompt"] = ', '.join(temp_prompt) if random_seed: gen_request_sub["seed" ] = random.randint(0,9999999999) request_list.append(copy.deepcopy(gen_request_sub)) else: request_list.append(gen_request) elif self.turbo_button.get() == 1: request_list = [] try: treq_0, treq_1, treq_2, treq_3 = NAIA_generation.make_turbo_prompt(gen_request) request_list.append(gen_request) request_list.append(treq_0) request_list.append(treq_1) request_list.append(treq_2) request_list.append(treq_3) except: request_list.append(gen_request) else: pre_prompt = gen_request["prompt"] pre_prompt = [keyword.strip() for keyword in pre_prompt.split(',')] if "*(split nsfw)-rand" in pre_prompt: pre_prompt.remove("*(split nsfw)-rand") gen_request["prompt"] = ', '.join(pre_prompt) def run_generation(): if gen_request["png_rule"] == "count": self.generation_count += 1 gen_request["count"] =self.generation_count if app.auto_count_left_flag == True: app.auto_count_left -= 1 if self.image_generation_repeat_flag == True: gen_request["repeat"] = self.image_generation_repeat_current -1 gen_request["repeat_max"] = self.image_generation_repeat app.image_generation_button.configure(border_width = 2) pass_bit = False retry_count = 0 while(not pass_bit): self.state_label.configure(text ="state : NAI 이미지 생성 대기중 ... ", text_color = "#FFFF97") result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request) self.state_label.configure(text ="state : idle", text_color = "#DCE4EE") app.image_generation_button.configure(border_width = 0) if self.anlas_request: self.anlas_request = False self.get_anlas() if info: self.error_count = 0 temp = info.get('Comment', '') temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','') pass_bit = True else: self.error_count += 1 retry_count += 1 if self.error_count >= 10: self.automation_button.deselect() temp = result_prompt if self.automation_button.get() == 1: instant_wait = random.uniform(3.5, 5.5) + self.delay_offset if instant_wait < 0 : instant_wait = 0.5 time.sleep(instant_wait) else: time.sleep(1) if self.automation_button.get() == 0 or retry_count >= 5: break self.running_flag = False self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.configure(text_color="#DCE4EE") self.image_label_report.insert("0.0", temp) self.image_label_report.configure(state="disabled") if result_image: if app.state() != 'zoomed': instant_result_image = customtkinter.CTkImage(result_image, size=(620,620)) else: current_image = Image.open(filename) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) set_image_to_queue(result_image, result_prompt, result_seed, filename) #자동화 체크 if self.automation_button.get() == 1: instant_wait = random.uniform(3.5, 5.5) + self.delay_offset if instant_wait < 0 : instant_wait = 0.5 if self.image_generation_repeat > 1 and self.hold_wildcard == False and (self.image_generation_repeat > self.image_generation_repeat_current): pass elif self.image_generation_repeat_flag == False or (self.image_generation_repeat <= self.image_generation_repeat_current): self.image_generation_repeat_current = 0 self.image_generation_repeat_flag = False if self.toggle_prompt_fix_button.get() == 0: random_function() #반복생성 처리구문, 트래킹 필요 while(instant_wait > 0): self.image_generation_button.configure(text=f"NAI 이미지 생성 ({round(instant_wait)})") if instant_wait >= 1: time.sleep(1) else: time.sleep(instant_wait) instant_wait -= 1 self.image_generation_button.configure(text="NAI 이미지 생성") if self.automation_button.get() == 1: self.event_generate(GENERATE_EVENT, when="tail") else: self.image_generation_button.configure(state="normal") else: self.image_generation_repeat_current = 0 self.image_generation_repeat_flag = False self.image_generation_button.configure(state="normal") def run_generation_turbo(gen_request): if gen_request["png_rule"] == "count": self.generation_count += 1 gen_request["count"] =self.generation_count if app.auto_count_left_flag == True: app.auto_count_left -= 1 app.image_generation_button.configure(border_width = 2) pass_bit = False retry_count = 0 while(not pass_bit): self.state_label.configure(text ="state : NAI 이미지 생성 대기중 (EXP.turbo) ... ", text_color = "#FFFF97") result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request) self.state_label.configure(text ="state : idle", text_color = "#DCE4EE") app.image_generation_button.configure(border_width = 0) if info: self.error_count = 0 temp = info.get('Comment', '') temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','') pass_bit = True else: self.error_count += 1 retry_count += 1 if self.error_count >= 10: self.automation_button.deselect() self.turbo_button.deselect() temp = result_prompt if self.automation_button.get() == 1: instant_wait = random.uniform(4.5, 8.5) + self.delay_offset if instant_wait < 0 : instant_wait = 0.5 time.sleep(instant_wait) else: time.sleep(1) if self.turbo_button.get() == 0 or retry_count >= 5: break self.running_flag = False self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.configure(text_color="#DCE4EE") self.image_label_report.insert("0.0", temp) self.image_label_report.configure(state="disabled") if result_image: if app.state() != 'zoomed': instant_result_image = customtkinter.CTkImage(result_image, size=(620,620)) else: current_image = Image.open(filename) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) set_image_to_queue(result_image, result_prompt, str(result_seed), filename) instant_wait = random.uniform(4.5, 8.5) + self.delay_offset if instant_wait < 0 : instant_wait = 0.5 while(instant_wait > 0): self.image_generation_button.configure(text=f"NAI 이미지 생성 ({round(instant_wait)})") if instant_wait >= 1: time.sleep(1) else: time.sleep(instant_wait) instant_wait -= 1 self.image_generation_button.configure(text="NAI 이미지 생성") def turbo_process_request(): turbo_count = 0 while(request_list): gen_request = request_list.pop(0) #length=5 generation_thread = threading.Thread(target=run_generation_turbo, args=(gen_request,), daemon=True) generation_thread.start() generation_thread.join() turbo_count += 1 if app.turbo_button.get() == 0: app.state_label.configure(text =f"state : 사용자에 의한 터보요청 중단 ({turbo_count})", text_color = "#FFFF97") break if self.automation_button.get() == 1: if self.toggle_prompt_fix_button.get() == 0: random_function() self.event_generate(GENERATE_EVENT, when="tail") else: self.image_generation_button.configure(state="normal") if self.turbo_button.get() == 0: generation_thread = threading.Thread(target=run_generation, daemon=True) generation_thread.start() else: turbo_process_request_thread = threading.Thread(target=turbo_process_request, daemon=True) turbo_process_request_thread.start() def open_AutomationSetting(self): if self.Automation_setting is None: self.Automation_setting = Automation_setting(self) else: if self.Automation_setting.state() == 'withdrawn': self.Automation_setting.deiconify() # 숨겨진 윈도우를 다시 화면에 표시 else: self.Automation_setting.focus() def show_advanced_settings(self): if self.Advanced_setting is None: self.Advanced_setting = Advanced_setting(self) else: if self.Advanced_setting.state() == 'withdrawn': self.Advanced_setting.deiconify() else: self.Advanced_setting.focus() def open_Character_search(self): if self.Character_search is None: if not os.path.exists("csdataset.parquet"): make_parquet(self) self.Character_search = Character_search(self) else: if self.Character_search.state() == 'withdrawn': self.Character_search.deiconify() else: self.Character_search.focus() def make_parquet(self): filtered_dfs = [] df = pd.read_parquet(os.path.join(basedir, "tags.parquet"),engine="pyarrow") filtered_df = df[df['general'].str.contains(' solo,', na=False) & ~df['general'].str.contains('monochrome', na=False)] filtered_dfs.append(filtered_df) final_df = pd.concat(filtered_dfs, ignore_index=True) final_df.to_parquet("csdataset.parquet") self.Advanced_setting = None self.Automation_setting = None self.Character_search = None #이미지 생성 프레임 self.image_generation_frame = customtkinter.CTkFrame(self.text_input_frame) self.image_generation_frame.grid(row=2, column=0, sticky="nsew") self.image_generation_frame.columnconfigure(0, weight= 1) self.image_generation_frame.columnconfigure(1, weight= 1) self.image_generation_frame.columnconfigure(2, weight= 1) self.random_function_button = customtkinter.CTkButton(self.image_generation_frame, text="랜덤/다음 프롬프트", font=my_font, command=random_function) self.random_function_button.grid(row=0, column=0, pady=5, sticky="nsew") self.automation_setting_button = customtkinter.CTkButton(self.image_generation_frame, text="자동화 설정", fg_color="#CDCDCD", text_color="black", hover_color="#848484", font=my_font, command=lambda: open_AutomationSetting(self)) self.automation_setting_button.grid(row=0, column=1, padx=15, sticky="ew") self.image_generation_button = customtkinter.CTkButton(self.image_generation_frame, text="NAI 이미지 생성", fg_color="#ED7D31", hover_color="#CC5D12", font=my_font, state="disabled", command=lambda: NAIA_generate(self), text_color_disabled="black") self.image_generation_button.grid(row=0, column=2, pady=5, sticky="nsew") def hold_prompt(): if self.toggle_prompt_fix_button.get() == 1: if self.unlock_hold_prompt_var.get() == 0: self.fixed_prompt_input.configure(state="disabled", text_color="#A2B8D2") self.fixed_prompt_after_input.configure(state="disabled", text_color="#A2B8D2") self.random_function_button.configure(state="disabled") self.rm_not_nsfw_button.deselect() self.rm_not_nsfw_button.configure(state="disabled") self.random_artist_button.deselect() self.random_artist_button.configure(state="disabled") self.unlock_hold_prompt.configure(state="normal") else: self.fixed_prompt_input.configure(state="normal", text_color="#DCE4EE") self.fixed_prompt_after_input.configure(state="normal", text_color="#DCE4EE") self.random_function_button.configure(state="normal") self.rm_not_nsfw_button.configure(state="normal") self.random_artist_button.configure(state="normal") def explicit_user_attention(): if self.turbo_button.get() == 1: self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0","end") self.image_label_report.insert("0.0", " 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") def fixed_prompt_label_command(): if self.fixed_prompt_label_var.get() == 0: self.fixed_prompt_input.grid_forget() else: self.fixed_prompt_input.grid(row=4, column=0, pady=5, sticky="nsew") self.fixed_prompt_label_var = customtkinter.IntVar(value=1) self.fixed_prompt_label = customtkinter.CTkCheckBox(self.text_input_frame, text=" ----------------------------- 선행 고정 프롬프트 ----------------------------- ", fg_color="grey10", hover_color="#50164A", font=large_font, variable=self.fixed_prompt_label_var, command=fixed_prompt_label_command, border_color="#333333") self.fixed_prompt_label.grid(row = 3, column=0, sticky="w" ) self.fixed_prompt_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=self.ui_size['prefix'], font=v_large_font, undo=True) self.fixed_prompt_input.grid(row=4, column=0, pady=5, sticky="nsew") #작가명 제거 및 기타 기능 self.check_box_frame = customtkinter.CTkFrame(self.text_input_frame) self.check_box_frame.grid(row=5, column=0, pady=5, columnspan=3, sticky="nsew") self.rm_artist_name_var = customtkinter.IntVar() self.rm_artist_name_button = customtkinter.CTkCheckBox(self.check_box_frame, text="작가명 제거", variable=self.rm_artist_name_var, font=my_font) self.rm_artist_name_button.grid(row=0, column=0, pady=5, padx=10, sticky="nsew") self.rm_copyright_name_var = customtkinter.IntVar() self.rm_copyright_name_button = customtkinter.CTkCheckBox(self.check_box_frame, text="작품명 제거", variable=self.rm_copyright_name_var, font=my_font) self.rm_copyright_name_button.grid(row=0, column=1, pady=5, sticky="nsew") self.rm_characteristic_var = customtkinter.IntVar() self.rm_characteristic_button = customtkinter.CTkCheckBox(self.check_box_frame, text="캐릭터 특징 제거", variable=self.rm_characteristic_var, font=my_font) self.rm_characteristic_button.grid(row=0, column=2, padx=10, pady=5, sticky="nsew") self.rm_not_nsfw_var = customtkinter.IntVar() self.rm_not_nsfw_button = customtkinter.CTkCheckBox(self.check_box_frame, text="NSFW Only", variable=self.rm_not_nsfw_var, font=my_font) self.rm_not_nsfw_button.grid(row=0, column=3, padx=15, pady=5, sticky="nsew") def fixed_prompt_after_label_command(): if self.fixed_prompt_after_label_var.get() == 0: self.fixed_prompt_after_input.grid_forget() else: self.fixed_prompt_after_input.grid(row=7, column=0, pady=5, sticky="nsew") self.fixed_prompt_after_label_var = customtkinter.IntVar(value=1) self.fixed_prompt_after_label = customtkinter.CTkCheckBox(self.text_input_frame, text=" ----------------------------- 후행 고정 프롬프트 ----------------------------- ", fg_color="grey10", hover_color="#50164A", font=large_font, variable=self.fixed_prompt_after_label_var, command=fixed_prompt_after_label_command, border_color="#333333") self.fixed_prompt_after_label.grid(row = 6, column=0, sticky="w" ) self.fixed_prompt_after_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=self.ui_size['postfix'], font=v_large_font, undo=True) self.fixed_prompt_after_input.grid(row=7, column=0, pady=5, sticky="nsew") self.negative_prompt_label_frame = customtkinter.CTkFrame(self.text_input_frame, fg_color="#2B2B2B") self.negative_prompt_label_frame.grid(row = 8, column=0, sticky="nsew" ) def negative_prompt_label_command(): if self.negative_prompt_label_var.get() == 0: self.negative_prompt_input.grid_forget() else: self.negative_prompt_input.grid(row=9, column=0, pady=5, sticky="nsew") self.negative_prompt_label_var = customtkinter.IntVar(value=1) self.negative_prompt_label = customtkinter.CTkCheckBox(self.negative_prompt_label_frame, text=" ---------------------------- 네거티브 프롬프트 ------------- Strength : ", fg_color="grey10", hover_color="#50164A", font=large_font, variable=self.negative_prompt_label_var, command=negative_prompt_label_command,border_color="#333333" ) self.negative_prompt_label.grid(row = 0, column=0, sticky="w" ) self.uncond_strength_entry = customtkinter.CTkEntry(self.negative_prompt_label_frame, font=my_font, width=50) self.uncond_strength_entry.grid(row = 0, column=1, sticky="e" ) self.uncond_strength_entry.insert(0, "1.00") self.negative_prompt_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=self.ui_size['negative'], font=v_large_font, undo=True) self.negative_prompt_input.insert("0.0", "lowres, jpeg artifacts, worst quality, watermark, blurry, very displeasing") self.negative_prompt_input.grid(row=9, column=0, pady=5, sticky="nsew") def auto_hide_label_command(): if self.auto_hide_keyword_input_var.get() == 0: self.auto_hide_keyword_input.grid_forget() else: self.auto_hide_keyword_input.grid(row=9, column=0, pady=5, sticky="nsew") self.auto_hide_keyword_input_var = customtkinter.IntVar(value=1) self.auto_hide_keyword_input_var = customtkinter.IntVar(value=1) self.auto_hide_label = customtkinter.CTkCheckBox(self.text_input_frame, text=" ----------------------------- 자동숨김 키워드 -----------------------------", fg_color="grey10", hover_color="#50164A", font=my_font, variable=self.auto_hide_keyword_input_var, command=auto_hide_label_command,border_color="#333333" ) self.auto_hide_label.grid(row = 10, column=0, sticky="w" ) self.auto_hide_keyword_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=self.ui_size['autohide'], font=v_large_font, undo=True) self.auto_hide_keyword_input.grid(row=11, column=0, pady=5, sticky="nsew") def bottom_ui_hide_command(): if self.bottom_ui_hide_var.get() == 0: self.bottom_ui_toggle.configure(text="하단 기능 펼치기") self.unlock_hold_prompt.grid_forget() self.toggle_wildcard_preopen.grid_forget() self.conditional_frame.grid_forget() self.conditional_prompt_label.grid_forget() self.conditional_prompt_input.grid_forget() self.conditional_negative_label.grid_forget() self.conditional_negative_input.grid_forget() else: self.bottom_ui_toggle.configure(text="하단 기능 숨기기") self.unlock_hold_prompt.grid(row = 13, column = 0, pady=5, sticky="w") self.toggle_wildcard_preopen.grid(row = 14, column = 0, pady=5, sticky="w") self.conditional_frame.grid(row = 15, column=0, sticky="w", pady=5) self.conditional_prompt_label.grid(row = 16, column=0, sticky="n" ) self.conditional_prompt_input.grid(row=17, column=0, pady=5, sticky="nsew") self.conditional_negative_label.grid(row = 18, column=0, sticky="n" ) self.conditional_negative_input.grid(row=19, column=0, pady=5, sticky="nsew") self.bottom_ui_hide_var = customtkinter.IntVar(value=1) self.bottom_ui_toggle = customtkinter.CTkCheckBox(self.text_input_frame, text="하단 기능 숨기기", fg_color="grey10", hover_color="#50164A", font=my_font, variable=self.bottom_ui_hide_var, command=bottom_ui_hide_command,border_color="#333333" ) self.bottom_ui_toggle.grid(row = 12, column = 0, pady=5, sticky="w") self.auto_quality_toggle_var = customtkinter.IntVar() self.auto_quality_toggle =customtkinter.CTkCheckBox(self.text_input_frame, text="Auto Quality Tag 활성화 (UC Preset은 제외)", font=my_font, variable=self.auto_quality_toggle_var) self.auto_quality_toggle.grid(row = 12, column = 0, pady=5, sticky="e") self.auto_quality_toggle.select() self.unlock_hold_prompt_var = customtkinter.IntVar() def unlock_hold(): if self.unlock_hold_prompt_var.get() == 1: self.fixed_prompt_input.configure(state="normal", text_color="#DCE4EE") self.fixed_prompt_after_input.configure(state="normal", text_color="#DCE4EE") elif self.unlock_hold_prompt_var.get() == 0 and self.toggle_prompt_fix_button.get() == 1: self.fixed_prompt_input.configure(state="disabled", text_color="#A2B8D2") self.fixed_prompt_after_input.configure(state="disabled", text_color="#A2B8D2") def reset_wildcard_preopen(): if self.toggle_wildcard_preopen_var.get() == 1: self.wildcard_preopen_repeat_current = self.wildcard_preopen_repeat self.unlock_hold_prompt = customtkinter.CTkCheckBox(self.text_input_frame, text="프롬프트 고정: 선행/후행/랜덤 프롬프트 잠금 강제해제 ", font=my_font, variable=self.unlock_hold_prompt_var, state="disabled", command=unlock_hold) self.unlock_hold_prompt.grid(row = 13, column = 0, pady=5, sticky="w") self.unlock_hold_prompt.deselect() self.toggle_wildcard_preopen_var = customtkinter.IntVar() self.toggle_wildcard_preopen = customtkinter.CTkCheckBox(self.text_input_frame, text="선행프롬의 와일드카드를 랜덤 프롬프트에서 먼저 오픈", font=my_font, variable=self.toggle_wildcard_preopen_var, command=reset_wildcard_preopen) self.toggle_wildcard_preopen.deselect() self.toggle_wildcard_preopen.grid(row = 14, column = 0, pady=5, sticky="w") self.conditional_frame = customtkinter.CTkFrame(self.text_input_frame, fg_color="#2B2B2B") self.conditional_frame.grid(row = 15, column=0, sticky="w", pady=5) self.cond_prompt_button_var = customtkinter.IntVar() self.cond_prompt_button = customtkinter.CTkCheckBox(self.conditional_frame,text="조건부 프롬프트 활성화", variable=self.cond_prompt_button_var,font=my_font ) self.cond_prompt_button.grid(row = 0, column = 0, sticky="w") self.cond_negative_button_var = customtkinter.IntVar() self.cond_negative_button = customtkinter.CTkCheckBox(self.conditional_frame,text="조건부 네거티브 활성화", variable=self.cond_negative_button_var, font=my_font ) self.cond_negative_button.grid(row = 0, column = 1, sticky="w", padx=5) self.conditional_prompt_label = customtkinter.CTkLabel(self.text_input_frame, text=" ------------------------ 조건부 프롬프트 (랜덤시 적용) ------------------------", font=my_font) self.conditional_prompt_label.grid(row = 16, column=0, sticky="w" ) self.conditional_prompt_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=self.ui_size['cond_prompt'], font=v_large_font, undo=True) self.conditional_prompt_input.grid(row=17, column=0, pady=5, sticky="nsew") self.conditional_negative_label = customtkinter.CTkLabel(self.text_input_frame, text=" ------------------------ 조건부 네거티브 (생성시 적용) ------------------------", font=my_font) self.conditional_negative_label.grid(row = 18, column=0, sticky="w" ) self.conditional_negative_input = customtkinter.CTkTextbox(self.text_input_frame, width=490, height=self.ui_size['cond_negative'], font=v_large_font, undo=True) self.conditional_negative_input.grid(row=19, column=0, pady=5, sticky="nsew") #이미지 히스토리 self.image_history_frame = customtkinter.CTkFrame(self.right_frame) self.image_history_frame.grid(row=0, column=0, columnspan=2, rowspan=15, padx=5, pady=5, sticky="n") def show_context_menu(event): if len(app.image_queue) != 0: self.image_label_context_menu.tk_popup(event.x_root, event.y_root) def copy_file(event=None): focused_widget = self.focus_get() if focused_widget == self: file_path = self.image_queue[self.current_window][3] command = f"powershell -command \"Get-Item '{file_path}' | Set-Clipboard\"" subprocess.run(command, shell=True) self.control_pressed = False def copy_file_instant(event=None): file_path = self.image_queue[self.current_window][3] command = f"powershell -command \"Get-Item '{file_path}' | Set-Clipboard\"" subprocess.run(command, shell=True) #이미지 레이블 self.image_label = customtkinter.CTkLabel(self.image_history_frame, text="") self.image_label.grid(row=1, column=0, rowspan=14, padx=10, pady=5, sticky="w") self.image_label.bind("", show_context_menu) self.image_label_context_menu = tk.Menu(self, tearoff=0, font=v_large_font) self.image_label_context_menu.add_command(label="이미지를 클립보드에 복사", command=copy_file_instant) self.image_label_report = customtkinter.CTkTextbox(self.right_frame, width=740, height=100, font=large_font) #image_label_report.insert("0.0", "1girl, {{minato aqua, ahoge, blue hair, braid, colored inner hair}}, artist:healthyman, [[[[[[[[[[artist:mikozin]]]]]]]]]], [[[artist:lakilolom]]], [[[[artist:crumbles]]]], [[artist:tianliang_duohe_fangdongye]], breasts, dutch angle, gloves, groin, gun, handgun, looking at viewer, nipples, no panties, one eye closed, skirt, smile, solo, topless, weapon, commentary request, highres, nsfw, great quality, aesthetic, absurdres, retouched, smooth lines, excellent color, suitable texture (SEED:22222222222), This text is sample, not an output of the actual generated result.") self.image_label_under_frame = customtkinter.CTkFrame(self.image_history_frame) self.image_label_under_frame.grid(row=0, column=0, padx=10, pady=5, sticky="ew") self.open_save_folder = customtkinter.CTkButton(self.image_label_under_frame, text="폴더 열기", font=my_font, fg_color="transparent", width=60,command=lambda: open_file_explorer(self)) self.open_save_folder.grid(row=0, column=0,padx=5, pady=5, sticky="nsew") self.window_label = customtkinter.CTkLabel(self.image_label_under_frame, text="0 / 0", font=my_font, width=60) self.window_label.grid(row=0, column=4,padx=5, pady=5, sticky="nsew") self.my_anlas = customtkinter.IntVar(value=0) self.anlas_label = customtkinter.CTkLabel(self.image_label_under_frame, text="Anlas : 0", font=my_font) self.anlas_label.grid(row=0, column=5,padx=5, pady=5, sticky="nsew") self.request_upper_size_button = customtkinter.CTkButton(self.image_label_under_frame, text="img2img (trial)",fg_color="transparent", hover_color="grey10", text_color="#FFFF97", font=my_font,state="disabled", command=lambda: img2img(self), width=110) self.request_upper_size_button.grid(row=0, column=6,padx=5, pady=5, sticky="nsew") #self.canvas_mode = customtkinter.CTkButton(self.image_label_under_frame, text="Inpaint", font=my_font, text_color="#0E0F21",fg_color="#F5F3C2", hover_color="#F2F2F2",width=50) #self.canvas_mode.grid(row=0, column=9,padx=5, pady=5, sticky="nsew") self.open_in_file_explorer = customtkinter.CTkButton(self.image_label_under_frame, text="파일 위치 열기", font=my_font, fg_color="transparent", width=80,command=lambda: open_in_file_explorer(self)) self.open_in_file_explorer.grid(row=0, column=7,padx=5, pady=5, sticky="nsew") self.open_save_folder.grid(row=0, column=0,padx=5, pady=5, sticky="nsew") self.image_label_report.grid(row=16, column=0, padx=10, pady=5, sticky="ew") self.image_label_report.configure(state="disabled") white_image = Image.new('RGB', (768, 768), 'white') #white_image =Image.open("sample_image.jpg") white_photo = customtkinter.CTkImage(white_image, size=(620,620)) self.image_label.configure(image=white_photo) self.image_label.image = white_photo self.image_queue = [] self.window = 0 #image history 버튼 self.image_history_sub_frame = customtkinter.CTkFrame(self.image_history_frame, width=100, height=550) self.image_history_sub_frame.grid(row=1, rowspan=12, column=1, sticky="n") self.output_file_path = f"output_NAI\\{self.start_time}\\txt2img" self.import_image_count = 0 def open_file_explorer(self): if not os.path.exists(self.output_file_path): os.makedirs(self.output_file_path) os.startfile(self.output_file_path) def open_in_file_explorer(self): filename = self.image_queue[self.current_window][3] explorer_command = f'explorer /select,"{os.path.abspath(filename)}"' subprocess.run(explorer_command) def up_button_pressed(): if self.image_history_button_down.cget("state") == "disabled": self.image_history_button_down.configure(state="normal") if self.control_pressed: self.window = len(self.image_queue) else: self.window+=1 update() show_text = str(self.window)+" / "+ str(len(self.image_queue)) self.window_label.configure(text=show_text) if self.window >= len(self.image_queue): self.image_history_button_up.configure(state="disabled") self.control_pressed = False image_history_0_yield() def down_button_pressed(): if self.image_history_button_up.cget("state") == "disabled": self.image_history_button_up.configure(state="normal") if self.control_pressed: if self.window >= 105: self.window -= 100 else: self.window = 5 else: self.window-=1 update() show_text = str(self.window)+" / "+ str(len(self.image_queue)) self.window_label.configure(text=show_text) if self.window <= 5: self.image_history_button_down.configure(state="disabled") self.control_pressed = False image_history_4_yield() highlight_tags = ["aqua","black","blonde","blue","brown","cyan","green","grey","orange","pink","purple","red","violet","white","yellow","mouth", "eyes", " cap", " ears", " girl", " ornament", " hat", "beret", " ear "] def insert_with_color(cs_text_input, current_lookup): words = [word.strip() for word in current_lookup.split(',')] for index, word in enumerate(words): highlight = False start_index = cs_text_input.index("end-1c") if index == len(words) - 1: # 마지막 원소인 경우 cs_text_input.insert("end", word) else: cs_text_input.insert("end", word + ", ") end_index = cs_text_input.index("end-1c") for tag in highlight_tags: if tag in word: highlight = True if word == "hat": highlight = True # 조건 확인 if word in cd.character_dictionary or word in tagbag.bag_of_tags[5:] or 'tail' in word or 'pupil' in word: cs_text_input.tag_add(word, start_index, end_index) cs_text_input.tag_config(word, foreground="#FFFF97") elif highlight: cs_text_input.tag_add(word, start_index, end_index) cs_text_input.tag_config(word, foreground="#AED395") self.current_window = None def set_image_to_queue(imagen, prompt, seed, filename): if type(self.current_popped_row) != type(None) and not self.current_popped_row.empty: self.image_queue.append([imagen, prompt, seed, filename, self.current_popped_row.copy()]) else: self.image_queue.append([imagen, prompt, seed, filename]) #self.history_export.configure(text=f"export ({len(self.image_queue)})") self.request_upper_size_button.configure(state="normal") self.current_window = self.window if self.window == len(self.image_queue)-1: self.window+=1 update() show_text = str(self.window)+" / "+ str(len(self.image_queue)) self.window_label.configure(text=show_text) def image_history_0_yield(event=None): if len(self.image_queue) < 1: return if self.control_pressed: if self.toggle_prompt_fix_button.get() == 0: self.text_input.delete("0.0", "end") insert_with_color(self.text_input, self.image_queue[self.window-1][1]) else: self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " 프롬프트 고정 상태에서는 사용 할 수 없습니다.") self.image_label_report.configure(text_color="#FFFF97") self.image_label_report.configure(state="disabled") else: self.current_window = self.window-1 if app.state() != 'zoomed': self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(620,620))) else: current_image = Image.open(self.image_queue[self.window-1][3]) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.configure(text_color="#DCE4EE") self.image_label_report.insert("0.0", self.image_queue[self.window-1][1] + " seed : " + str(self.image_queue[self.window-1][2])) self.image_label_report.configure(state="disabled") if len(self.image_queue[self.window-1]) >= 5 and 'id' in self.image_queue[self.window-1][4].index: if fav_check(self.image_queue[self.window-1][4]['id']): self.history_export.configure(text="+ FAV (★)", state="disabled") else: self.history_export.configure(text="+ FAV (☆)", state="normal") else: self.history_export.configure(state="disabled") def image_history_1_yield(event=None): if len(self.image_queue) < 2: return if self.control_pressed: if self.toggle_prompt_fix_button.get() == 0: self.text_input.delete("0.0", "end") insert_with_color(self.text_input, self.image_queue[self.window-2][1]) else: self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " 프롬프트 고정 상태에서는 사용 할 수 없습니다.") self.image_label_report.configure(text_color="#FFFF97") self.image_label_report.configure(state="disabled") else: self.current_window = self.window-2 if app.state() != 'zoomed': self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(620,620))) else: current_image = Image.open(self.image_queue[self.window-2][3]) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.configure(text_color="#DCE4EE") self.image_label_report.insert("0.0", self.image_queue[self.window-2][1] + " seed : " + str(self.image_queue[self.window-2][2])) self.image_label_report.configure(state="disabled") if len(self.image_queue[self.window-2]) >= 5 and 'id' in self.image_queue[self.window-2][4].index: if fav_check(self.image_queue[self.window-2][4]['id']): self.history_export.configure(text="+ FAV (★)", state="disabled") else: self.history_export.configure(text="+ FAV (☆)", state="normal") else: self.history_export.configure(state="disabled") def image_history_2_yield(event=None): if len(self.image_queue) < 3: return if self.control_pressed: if self.toggle_prompt_fix_button.get() == 0: self.text_input.delete("0.0", "end") insert_with_color(self.text_input, self.image_queue[self.window-3][1]) else: self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " 프롬프트 고정 상태에서는 사용 할 수 없습니다.") self.image_label_report.configure(text_color="#FFFF97") self.image_label_report.configure(state="disabled") else: self.current_window = self.window-3 if app.state() != 'zoomed': self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(620,620))) else: current_image = Image.open(self.image_queue[self.window-3][3]) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.configure(text_color="#DCE4EE") self.image_label_report.insert("0.0", self.image_queue[self.window-3][1] + " seed : " + str(self.image_queue[self.window-3][2])) self.image_label_report.configure(state="disabled") if len(self.image_queue[self.window-3]) >= 5 and 'id' in self.image_queue[self.window-3][4].index: if fav_check(self.image_queue[self.window-3][4]['id']): self.history_export.configure(text="+ FAV (★)", state="disabled") else: self.history_export.configure(text="+ FAV (☆)", state="normal") else: self.history_export.configure(state="disabled") def image_history_3_yield(event=None): if len(self.image_queue) < 4: return if self.control_pressed: if self.toggle_prompt_fix_button.get() == 0: self.text_input.delete("0.0", "end") insert_with_color(self.text_input, self.image_queue[self.window-4][1]) else: self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " 프롬프트 고정 상태에서는 사용 할 수 없습니다.") self.image_label_report.configure(text_color="#FFFF97") self.image_label_report.configure(state="disabled") else: self.current_window = self.window-4 if app.state() != 'zoomed': self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(620,620))) else: current_image = Image.open(self.image_queue[self.window-4][3]) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.configure(text_color="#DCE4EE") self.image_label_report.insert("0.0", self.image_queue[self.window-4][1] + " seed : " + str(self.image_queue[self.window-4][2])) self.image_label_report.configure(state="disabled") if len(self.image_queue[self.window-4]) >= 5 and 'id' in self.image_queue[self.window-4][4].index: if fav_check(self.image_queue[self.window-4][4]['id']): self.history_export.configure(text="+ FAV (★)", state="disabled") else: self.history_export.configure(text="+ FAV (☆)", state="normal") else: self.history_export.configure(state="disabled") def image_history_4_yield(event=None): if len(self.image_queue) < 5: return if self.control_pressed: if self.toggle_prompt_fix_button.get() == 0: self.text_input.delete("0.0", "end") insert_with_color(self.text_input, self.image_queue[self.window-5][1]) else: self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " 프롬프트 고정 상태에서는 사용 할 수 없습니다.") self.image_label_report.configure(text_color="#FFFF97") self.image_label_report.configure(state="disabled") else: self.current_window = self.window-5 if app.state() != 'zoomed': self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-5][0], size=(620,620))) else: current_image = Image.open(self.image_queue[self.window-5][3]) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.configure(text_color="#DCE4EE") self.image_label_report.insert("0.0", self.image_queue[self.window-5][1] + " seed : " + str(self.image_queue[self.window-5][2])) self.image_label_report.configure(state="disabled") if len(self.image_queue[self.window-5]) >= 5 and 'id' in self.image_queue[self.window-5][4].index: if fav_check(self.image_queue[self.window-5][4]['id']): self.history_export.configure(text="+ FAV (★)", state="disabled") else: self.history_export.configure(text="+ FAV (☆)", state="normal") else: self.history_export.configure(state="disabled") def update(): if len(self.image_queue) <= 5: if len(self.image_queue) >= 1: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) if len(self.image_queue[self.window-1]) >= 5: button_item_0 = self.image_queue[self.window-1][4].copy() self.image_history_0.bind("", lambda event: on_right_click(event, button_item_0)) if len(self.image_queue) >= 2: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) if len(self.image_queue[self.window-1]) >= 5: button_item_0 = self.image_queue[self.window-1][4].copy() self.image_history_0.unbind("") self.image_history_0.bind("", lambda event: on_right_click(event, button_item_0)) self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100))) if len(self.image_queue[self.window-2]) >= 5: button_item_1 = self.image_queue[self.window-2][4].copy() self.image_history_1.bind("", lambda event: on_right_click(event, button_item_1)) if len(self.image_queue) >= 3: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) if len(self.image_queue[self.window-1]) >= 5: button_item_0 = self.image_queue[self.window-1][4].copy() self.image_history_0.unbind("") self.image_history_0.bind("", lambda event: on_right_click(event, button_item_0)) self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100))) if len(self.image_queue[self.window-2]) >= 5: button_item_1 = self.image_queue[self.window-2][4].copy() self.image_history_1.unbind("") self.image_history_1.bind("", lambda event: on_right_click(event, button_item_1)) self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100))) if len(self.image_queue[self.window-3]) >= 5: button_item_2 = self.image_queue[self.window-3][4].copy() self.image_history_2.bind("", lambda event: on_right_click(event, button_item_2)) if len(self.image_queue) >= 4: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) if len(self.image_queue[self.window-1]) >= 5: button_item_0 = self.image_queue[self.window-1][4].copy() self.image_history_0.unbind("") self.image_history_0.bind("", lambda event: on_right_click(event, button_item_0)) self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100))) if len(self.image_queue[self.window-2]) >=5: button_item_1 = self.image_queue[self.window-2][4].copy() self.image_history_1.unbind("") self.image_history_1.bind("", lambda event: on_right_click(event, button_item_1)) self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100))) if len(self.image_queue[self.window-3]) >= 5: button_item_2 = self.image_queue[self.window-3][4].copy() self.image_history_2.unbind("") self.image_history_2.bind("", lambda event: on_right_click(event, button_item_2)) self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100))) if len(self.image_queue[self.window-4]) >= 5: button_item_3 = self.image_queue[self.window-4][4].copy() self.image_history_3.bind("", lambda event: on_right_click(event, button_item_3)) if len(self.image_queue) == 5: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) if len(self.image_queue[self.window-1]) >= 5: button_item_0 = self.image_queue[self.window-1][4].copy() self.image_history_0.unbind("") self.image_history_0.bind("", lambda event: on_right_click(event, button_item_0)) self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100))) if len(self.image_queue[self.window-2]) >= 5: button_item_1 = self.image_queue[self.window-2][4].copy() self.image_history_1.unbind("") self.image_history_1.bind("", lambda event: on_right_click(event, button_item_1)) self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100))) if len(self.image_queue[self.window-3]) >= 5: button_item_2 = self.image_queue[self.window-3][4].copy() self.image_history_2.unbind("") self.image_history_2.bind("", lambda event: on_right_click(event, button_item_2)) self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100))) if len(self.image_queue[self.window-4]) >= 5: button_item_3 = self.image_queue[self.window-4][4].copy() self.image_history_3.unbind("") self.image_history_3.bind("", lambda event: on_right_click(event, button_item_3)) self.image_history_4.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-5][0], size=(100,100))) if len(self.image_queue[self.window-5]) >= 5: button_item_4 = self.image_queue[self.window-5][4].copy() self.image_history_4.bind("", lambda event: on_right_click(event, button_item_4)) else: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) if len(self.image_queue[self.window-1]) >= 5: button_item_0 = self.image_queue[self.window-1][4].copy() self.image_history_0.unbind("") self.image_history_0.bind("", lambda event: on_right_click(event, button_item_0)) self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100))) if len(self.image_queue[self.window-2]) >= 5: button_item_1 = self.image_queue[self.window-2][4].copy() self.image_history_1.unbind("") self.image_history_1.bind("", lambda event: on_right_click(event, button_item_1)) self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100))) if len(self.image_queue[self.window-3]) >= 5: button_item_2 = self.image_queue[self.window-3][4].copy() self.image_history_2.unbind("") self.image_history_2.bind("", lambda event: on_right_click(event, button_item_2)) self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100))) if len(self.image_queue[self.window-4]) >= 5: button_item_3 = self.image_queue[self.window-4][4].copy() self.image_history_3.unbind("") self.image_history_3.bind("", lambda event: on_right_click(event, button_item_3)) self.image_history_4.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-5][0], size=(100,100))) if len(self.image_queue[self.window-5]) >= 5: button_item_4 = self.image_queue[self.window-5][4].copy() self.image_history_4.unbind("") self.image_history_4.bind("", lambda event: on_right_click(event, button_item_4)) if len(self.image_queue) == 6: self.image_history_button_down.configure(state="normal") def some_command(item): print(item) random_function(item) def on_right_click(event, button_item): context_menu.delete(0, tk.END) # 기존 메뉴 항목을 모두 삭제 context_menu.add_command(label="Requeue", command=lambda: some_command(button_item)) # 새 커맨드 추가 context_menu.tk_popup(event.x_root, event.y_root) context_menu = tk.Menu(self, tearoff=0, font=v_large_font, fg="black") black_image = Image.new('RGB', (100, 100), '#2B2B2B') self.image_history_0 = customtkinter.CTkButton(self.image_history_sub_frame, width=100, height=100, corner_radius=8,text="", fg_color="transparent", image=customtkinter.CTkImage(black_image, size=(100,100)), command=image_history_0_yield) self.image_history_0.grid(row=0, column=1, padx=5, pady=1, sticky="n") self.image_history_1 = customtkinter.CTkButton(self.image_history_sub_frame, width=100, height=100, corner_radius=8,text="", fg_color="transparent", image=customtkinter.CTkImage(black_image, size=(100,100)), command=image_history_1_yield) self.image_history_1.grid(row=1, column=1, padx=5, pady=1, sticky="n") self.image_history_2 = customtkinter.CTkButton(self.image_history_sub_frame, width=100, height=100, corner_radius=8,text="", fg_color="transparent",image=customtkinter.CTkImage(black_image, size=(100,100)), command=image_history_2_yield) self.image_history_2.grid(row=2, column=1, padx=5, pady=1, sticky="n") self.image_history_3 = customtkinter.CTkButton(self.image_history_sub_frame, width=100, height=100, corner_radius=8,text="", fg_color="transparent", image=customtkinter.CTkImage(black_image, size=(100,100)), command=image_history_3_yield) self.image_history_3.grid(row=3,column=1, padx=5, pady=1, sticky="n") self.image_history_4 = customtkinter.CTkButton(self.image_history_sub_frame, width=100, height=100, corner_radius=8,text="", fg_color="transparent", image=customtkinter.CTkImage(black_image, size=(100,100)), command=image_history_4_yield) self.image_history_4.grid(row=4, column=1, padx=5, pady=1, sticky="n") self.image_history_button_up = customtkinter.CTkButton(self.image_history_frame, text="▲", width=100, font=my_font, state="disabled", command=up_button_pressed) self.image_history_button_up.grid(row=0, column=1, pady=10, padx=5, sticky="n") self.image_history_button_down = customtkinter.CTkButton(self.image_history_frame, text="▼", width=100, font=my_font, state="disabled", command=down_button_pressed) self.image_history_button_down.grid(row=13, column=1, pady=5, padx=5, sticky="n") def save_to_excel(): #contributor : highnoon1 #function : 히스토리 엑셀로 저장 (무제한 보기는 성능 이슈로 제외) workbook = Workbook() sheet = workbook.active alignment = Alignment(wrapText=True) sheet['A1'].alignment = alignment sheet['A1'] = 'Prompt' sheet['B1'] = 'Seed' sheet['C1'] = 'Image' image_objects = [] # BytesIO 객체를 추적하기 위한 리스트 # history 데이터를 반복하며 Excel에 저장 for index, (pil_image, prompt, seed, *_rest) in enumerate(self.image_queue): row_num = index + 1 # 행 번호 (Excel 행은 1부터 시작) # 프롬프트와 시드 삽입 prompt_cell = sheet.cell(row=row_num, column=1, value=prompt) sheet.cell(row=row_num, column=2, value=seed) prompt_cell.alignment = Alignment(wrap_text=True) # PIL 이미지를 BytesIO 객체에 PNG 형식으로 저장 pil_image = self.resize_image_to_fit(pil_image,192) output = io.BytesIO() pil_image.save(output, format='PNG') output.seek(0) image_objects.append(output) # 리스트에 추가 # Openpyxl 이미지 생성 및 시트에 추가 img = OpenpyxlImage(output) img.anchor = f'C{row_num}' # 이미지를 C열에 고정 sheet.add_image(img) # 이미지 크기에 따라 행 높이 및 열 너비 조정 scale_factor = 0.75 sheet.row_dimensions[row_num].height = pil_image.height * scale_factor sheet.column_dimensions['C'].width = pil_image.width * scale_factor / 7 # A열과 B열 크기 조정 sheet.column_dimensions['A'].width = 50 sheet.column_dimensions['B'].width = 15 # 워크북 저장 workbook.save(f"history_with_images_{self.start_time}.xlsx") # 모든 BytesIO 객체 닫기 for img_obj in image_objects: img_obj.close() if os.path.exists(f"history_with_images_{self.start_time}.xlsx"): os.startfile(f"history_with_images_{self.start_time}.xlsx") print("엑셀 파일에 저장됨") def history_export(): if self.control_pressed: save_to_excel() self.history_export.configure(text="+ FAV (☆)", fg_color="#F5F3C2", hover_color="#A69F40", text_color="black") if self.image_queue and len(self.image_queue[self.current_window]) >= 5: self.history_export.configure(state="normal") else: self.history_export.configure(state="disabled") else: """ Description : @history_export 평상시에는 FAV 기능으로 동작 """ new_data = self.image_queue[self.current_window][4] validation_prompt = self.image_queue[self.current_window][1] prompt = new_data['general'] validation_prompt = [key.strip() for key in validation_prompt.split(',')] prompt = [key.strip() for key in prompt.split(',')] autohide = self.auto_hide_keyword_input.get("0.0", "end") autohide = [key.strip() for key in autohide.split(',')] + app.data.bag_of_tags prompt = [key for key in prompt if key not in autohide] not_validated = [key for key in prompt if key not in validation_prompt] if len(not_validated) >= 3: self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", f" 랜덤하게 생성된 프롬프트가 아니거나, {len(not_validated)}개의 제거된 태그가 검출되어 Favorite 등록에 실패하였습니다. 해당 기능은 랜덤 생성 프롬프트를 DataFrame 규격에 맞춰 복사하는 기능이기 때문에 수정된 프롬프트의 저장은 지원하지 않습니다.") self.image_label_report.configure(text_color="#FFFF97") self.image_label_report.configure(state="disabled") return try: favorite_prompts = pd.read_parquet('favorite_prompt.parquet') except FileNotFoundError: dtype_dict = { 'id': 'int64', 'copyright': 'object', 'character': 'object', 'artist': 'object', 'general': 'object', 'meta': 'object', 'rating': 'object', 'score': 'object', 'created_at': 'object', } favorite_prompts = pd.DataFrame(columns=dtype_dict.keys()) self.fav_button.configure(state="normal") try: _temp = new_data['id'] except: self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " 0215 버전부터 tags의 구성이 변경되었습니다. favorite 기능을 사용하기 위해 검색을 다시 수행 해 주세요.") self.image_label_report.configure(text_color="#FFFF97") self.image_label_report.configure(state="disabled") return new_data_id = new_data['id'] new_data = pd.DataFrame([new_data]) success = False if 'id' not in favorite_prompts.columns: favorite_prompts = pd.concat([favorite_prompts, new_data], ignore_index=True) success = True elif not favorite_prompts['id'].isin([new_data_id]).any(): favorite_prompts = pd.concat([favorite_prompts, new_data], ignore_index=True) success = True else: self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " 이미 favorite에 등록되어있는 프롬프트입니다.") self.image_label_report.configure(text_color="#FFFF97") self.image_label_report.configure(state="disabled") if success: pil_image = self.image_queue[self.current_window][0] folder_path = 'favorite_prompts' if not os.path.exists(folder_path): os.makedirs(folder_path) favorite_prompts.to_parquet('favorite_prompt.parquet') image_path = os.path.join(folder_path, f"{_temp}.jpg") pil_image.save(image_path, 'JPEG') self.fav_id_list.append(_temp) self.history_export.configure(text="FAV (★)", fg_color="#F5F3C2", hover_color="#A69F40", text_color="black", state="disabled") self.history_export = customtkinter.CTkButton(self.image_history_frame, text="+ FAV (☆)", width=100, fg_color="#F5F3C2", hover_color="#A69F40", text_color="black", font=my_font, command=history_export, state="disabled") self.history_export.grid(row=14, column=1, pady=10, padx=5, sticky="n") #랜덤작가 및 와일드카드 설정 self.extended_right_frame = customtkinter.CTkFrame(self.right_frame) self.extended_right_frame.grid(row=17, column=0, columnspan=2, padx=5, sticky="w") self.random_artist_var = customtkinter.IntVar() self.random_artist_button = customtkinter.CTkCheckBox(self.extended_right_frame, text="랜덤작가 추가", variable=self.random_artist_var, font=my_font, state="disabled") self.random_artist_button.grid(row=0, column=0,pady=5, padx=10, sticky="nsew") self.random_artist_manage_button = customtkinter.CTkButton(self.extended_right_frame, text="랜덤작가 관리", font=my_font, command=self.random_artist_window) self.random_artist_manage_button.grid(row=0, column=1,pady=5, padx=5, sticky="nsew") self.recommended_prompt_button = customtkinter.CTkButton(self.extended_right_frame, text="추천 프롬프트", font=my_font, command= self.open_prompt_window) self.recommended_prompt_button.grid(row=0, column=3,pady=5, padx=5, sticky="nsew") self.wildcard_manager_button = customtkinter.CTkButton(self.extended_right_frame, text="와일드카드 관리", font=my_font, command=self.open_wildcard_window) self.wildcard_manager_button.grid(row=0, column=2,pady=5, padx=5, sticky="nsew") self.character_search_button = customtkinter.CTkButton(self.extended_right_frame, text="캐릭터 검색", fg_color="#7030A0", hover_color="#481F67", font=my_font, command= lambda: open_Character_search(self)) self.character_search_button.grid(row=0, column=4,pady=5, padx=5, sticky="nsew") self.seed_fix_var = customtkinter.IntVar() self.seed_fix_button = customtkinter.CTkCheckBox(self.extended_right_frame, text="시드고정 ", variable=self.seed_fix_var, font=my_font) self.seed_fix_button.grid(row=1, column=0,pady=5, padx=10, sticky="nsew") self.entry_seed_value = customtkinter.IntVar() self.seed_entry = customtkinter.CTkEntry(self.extended_right_frame, textvariable=self.entry_seed_value) self.seed_entry.grid(row=1, column=1,pady=5, padx=5, sticky="nsew") self.seed_entry.insert(0, random.randint(0,9999999999)) self.cfg_scale_label = customtkinter.CTkLabel(self.extended_right_frame, text="CFG Scale : ", font=my_font) self.cfg_scale_label.grid(row=1, column=2,pady=5, padx=5, sticky="w") self.cfg_scale_var = customtkinter.StringVar(value="5.0") self.cfg_scale_entry = customtkinter.CTkEntry(self.extended_right_frame, width=65, textvariable=self.cfg_scale_var) self.cfg_scale_entry.grid(row=1, column=2,pady=5, padx=5, sticky="e") self.prompt_guidance_rescale_var = customtkinter.StringVar(value="0") self.prompt_guidance_rescale_label = customtkinter.CTkLabel(self.extended_right_frame, text="Prompt Guidance Rescale :", font=my_font) self.prompt_guidance_rescale_label.grid(row=1, column=3, pady=5, padx=5, sticky="w") self.prompt_guidance_rescale_entry = customtkinter.CTkEntry(self.extended_right_frame, width=65) self.prompt_guidance_rescale_entry.grid(row=1, column=4,pady=5, padx=10, sticky="w") self.extra_setting_button = customtkinter.CTkButton(self.extended_right_frame, width=55, text="기타설정", font=my_font, fg_color="grey", hover_color="grey5", command=lambda: show_advanced_settings(self)) self.extra_setting_button.grid(row=1, column=4,pady=5, padx=5, sticky="e") self.random_resolution_var = customtkinter.IntVar() self.random_resolution_button = customtkinter.CTkCheckBox(self.extended_right_frame, text="랜덤 해상도 ", variable=self.random_resolution_var, font=my_font) self.random_resolution_button.grid(row=2, column=0,pady=5, padx=10, sticky="nsew") self.resolution_var = customtkinter.StringVar(value="1024 x 1024") self.resolution_button = customtkinter.CTkComboBox(self.extended_right_frame, width=160,values=["1024 x 1024", "960 x 1088", "896 x 1152", "832 x 1216", "1088 x 960", "1152 x 896", "1216 x 832"], variable=self.resolution_var, font=my_font) self.resolution_button.grid(row=2, column=1, padx=5, sticky="w") self.sampler_label = customtkinter.CTkLabel(self.extended_right_frame, text="Sampler :", font=my_font) self.sampler_label.grid(row=2, column=2,pady=5, padx=15, sticky="w") self.sampler_var = customtkinter.StringVar(value="k_euler_ancestral") self.sampler_button = customtkinter.CTkComboBox(self.extended_right_frame, width=210,values=["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde", "k_dpmpp_2m"], variable=self.sampler_var, font=my_font) self.sampler_button.grid(row=2, column=2, columnspan=2, pady=5, padx=15, sticky="e") self.show_fullscreen_btn = customtkinter.CTkButton(self.extended_right_frame, text="전체화면(ESC닫기)", font=my_font, command=self.show_fullscreen_image) self.show_fullscreen_btn.grid(row=2, column=4,pady=5, padx=5, sticky="nsew") self.sema_button_var = customtkinter.IntVar() def sema_pressed(): if self.sema_button_var.get() == 0: self.dyn_button.deselect() self.sema_button = customtkinter.CTkCheckBox(self.extended_right_frame, text="SMEA", variable=self.sema_button_var,font=my_font, command=sema_pressed) self.sema_button.grid(row=3, column=0, pady=5, padx=10, sticky="w") self.dyn_button_var = customtkinter.IntVar() def sema_dyn_pressed(): if self.dyn_button_var.get() == 1: self.sema_button.select() self.dyn_button = customtkinter.CTkCheckBox(self.extended_right_frame, text="SMEA+DYN", variable=self.dyn_button_var, font=my_font, command=sema_dyn_pressed) self.dyn_button.grid(row=3, column=1, pady=5, padx=10, sticky="w") self.state_label = customtkinter.CTkLabel(self.extended_right_frame, text="state : idle", font=my_font) self.state_label.grid(row=3, column=2, columnspan=2, pady=5, padx=10, sticky="n") self.instant_row_button = customtkinter.CTkButton(self.extended_right_frame, text="인스턴트 이벤트", font=my_font, fg_color="grey10", command=self.open_instant_event) self.instant_row_button.grid(row=3, column=4,pady=5, padx=5, sticky="nsew") GENERATE_EVENT = "<>" sync_text() self.bind(GENERATE_EVENT, lambda x=None: NAIA_generate(self)) self.output_file_path_personal = False self.png_name_rule = "time" self.name_var = customtkinter.StringVar(value=self.png_name_rule) self.window_resize_last_access = None self.last_window_size_conf = None self.generation_count = 0 self.random_artist_list = None self.random_artist = [] self.random_artist_prefix = customtkinter.StringVar(value="none") def on_window_resize(event): if datetime.now() == app.last_window_size_conf: return time_difference = datetime.now() - app.start_time_prime if (time_difference.total_seconds() < 3): return if app.last_window_size is None: app.last_window_size = (app.winfo_width(), app.winfo_height()) # 윈도우가 최대화되었는지 확인 current_size = (app.winfo_width(), app.winfo_height()) if current_size != app.last_window_size: app.last_window_size = current_size if app.state() == 'zoomed': print(app.winfo_width()) self.right_frame.configure(width=1200) self.image_label.grid_forget() self.image_label_under_frame.grid_forget() self.image_history_sub_frame.grid_forget() self.image_history_button_down.grid_forget() self.image_history_sub_frame.grid(row=0, pady=45, rowspan=12, column=1, sticky="n") self.image_history_button_down.grid(row=9, column=1, pady=5, padx=5, sticky="n") self.image_label.grid(row=0, column=0,rowspan=14, padx=10, pady=5, sticky="w") self.hidden_frame.grid(row=0, column=2,rowspan=14, sticky="nsew") self.history_export.grid(row=10, column=1, pady=1, padx=5, sticky="n") self.random_artist_button = customtkinter.CTkCheckBox(self.hidden_frame, text="랜덤작가 추가", variable=self.random_artist_var, font=my_font, state="disabled") self.random_artist_button.grid(row=0, column=0,pady=5, padx=5, sticky="nsew") self.seed_fix_button = customtkinter.CTkCheckBox(self.hidden_frame, text="시드고정 ", variable=self.seed_fix_var, font=my_font) self.seed_fix_button.grid(row=1, column=0,pady=5, padx=5, sticky="nsew") self.seed_entry = customtkinter.CTkEntry(self.hidden_frame, textvariable=self.entry_seed_value) self.seed_entry.grid(row=1, column=1,pady=5, padx=5, sticky="nsew") self.random_artist_manage_button = customtkinter.CTkButton(self.hidden_frame, text="랜덤작가 관리", font=my_font, command=self.random_artist_window) self.random_artist_manage_button.grid(row=0, column=1,pady=5, padx=5, sticky="nsew") self.random_resolution_button2 = customtkinter.CTkCheckBox(self.hidden_frame, text="랜덤 해상도", variable=self.random_resolution_var, font=my_font) self.random_resolution_button2.grid(row=3, column=0,pady=5, padx=5, sticky="nsew") self.resolution_button2 = customtkinter.CTkComboBox(self.hidden_frame, width=160,values=["1024 x 1024", "960 x 1088", "896 x 1152", "832 x 1216", "1088 x 960", "1152 x 896", "1216 x 832"], variable=self.resolution_var, font=my_font) self.resolution_button2.grid(row=3, column=1, padx=5, sticky="w") self.sampler_label2 = customtkinter.CTkLabel(self.hidden_frame, text="Sampler :", font=my_font) self.sampler_label2.grid(row=4, column=0,pady=5, padx=5, sticky="w") self.sampler_button2 = customtkinter.CTkComboBox(self.hidden_frame, width=160,values=["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde", "k_dpmpp_2m"], variable=self.sampler_var, font=my_font) self.sampler_button2.grid(row=4, column=1, columnspan=2, pady=5, padx=5, sticky="e") self.cfg_scale_label2 = customtkinter.CTkLabel(self.hidden_frame, text="CFG Scale : ", font=my_font) self.cfg_scale_label2.grid(row=5, column=0,pady=5, padx=5, sticky="w") self.cfg_scale_entry2 = customtkinter.CTkEntry(self.hidden_frame, width=65, textvariable=self.cfg_scale_var) self.cfg_scale_entry2.grid(row=5, column=1,pady=5, padx=5, sticky="w") self.prompt_guidance_rescale_label2 = customtkinter.CTkLabel(self.hidden_frame, text="P.Guide Rescale :", font=my_font) self.prompt_guidance_rescale_label2.grid(row=6, column=0, pady=5, padx=5, sticky="w") self.prompt_guidance_rescale_entry2 = customtkinter.CTkEntry(self.hidden_frame, width=65, textvariable=self.prompt_guidance_rescale_var) self.prompt_guidance_rescale_entry2.grid(row=6, column=1,pady=5, padx=5, sticky="w") self.sema_button2 = customtkinter.CTkCheckBox(self.hidden_frame, text="SEMA", variable=self.sema_button_var,font=my_font) self.sema_button2.grid(row=7, column=0, pady=5, padx=5, sticky="w") self.dyn_button2 = customtkinter.CTkCheckBox(self.hidden_frame, text="SEMA+DYN", variable=self.dyn_button_var, font=my_font) self.dyn_button2.grid(row=7, column=1, pady=5, padx=5, sticky="w") self.open_save_folder2 = customtkinter.CTkButton(self.hidden_frame, text="폴더 열기", font=my_font, fg_color="transparent", command=lambda: open_file_explorer(self), width=80) self.open_save_folder2.grid(row=5, column=1,padx=5, pady=5, sticky="e") self.extra_setting_button2 = customtkinter.CTkButton(self.hidden_frame, width=80, text="기타설정", font=my_font, fg_color="grey", hover_color="grey5", command=lambda: show_advanced_settings(self)) self.extra_setting_button2.grid(row=6, column=1,pady=5, padx=5, sticky="e") self.recommended_prompt_button2 = customtkinter.CTkButton(self.hidden_frame, text="추천 프롬프트", font=my_font, command= self.open_prompt_window) self.recommended_prompt_button2.grid(row=9, column=0, columnspan=2, pady=5, padx=5, sticky="nsew") self.wildcard_manager_button2 = customtkinter.CTkButton(self.hidden_frame, text="와일드카드 관리", font=my_font, command=self.open_wildcard_window) self.wildcard_manager_button2.grid(row=10, column=0,columnspan=2, pady=5, padx=5, sticky="nsew") self.character_search_button2 = customtkinter.CTkButton(self.hidden_frame, text="캐릭터 검색", fg_color="#7030A0", hover_color="#481F67", font=my_font, command= lambda: open_Character_search(self)) self.character_search_button2.grid(row=11, column=0,columnspan=2, pady=5, padx=5, sticky="nsew") self.window_label.grid_forget() self.window_label = customtkinter.CTkLabel(self.hidden_frame, text=str(self.window)+" / "+ str(len(self.image_queue)), font=my_font) self.window_label.grid(row=12, column=0,padx=5, pady=5, sticky="w") self.request_upper_size_button2 = customtkinter.CTkButton(self.hidden_frame, text="img2img (trial)",fg_color="transparent", hover_color="grey10", text_color="#FFFF97", font=my_font, command=lambda: img2img(self), width=110) self.request_upper_size_button2.grid(row=12, column=1,padx=5, pady=5, sticky="nsew") if self.image_queue: current_image = Image.open(self.image_queue[self.window-1][3]) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) else: self.image_label.configure(image=customtkinter.CTkImage(white_image, size=(app.winfo_screenheight()-100, app.winfo_screenheight()-100))) else: self.right_frame.configure(width=768) self.image_label_report.grid_forget() self.image_label.grid_forget() self.image_label_under_frame.grid_forget() self.image_history_sub_frame.grid_forget() self.image_history_button_up.grid_forget() self.image_history_button_down.grid_forget() self.image_label.grid(row=1, column=0, rowspan=14, padx=10, pady=5, sticky="w") self.image_label_under_frame.grid(row=0, column=0, padx=10, pady=5, sticky="ew") self.image_history_sub_frame.grid(row=1, rowspan=12, column=1, sticky="n") self.image_label_report.grid(row=16, column=0, padx=10, pady=5, sticky="ew") self.image_history_button_up.grid(row=0, column=1, pady=10, padx=5, sticky="n") self.image_history_button_down.grid(row=13, column=1, pady=5, padx=5, sticky="n") self.history_export.grid(row=14, column=1, pady=10, padx=5, sticky="n") self.hidden_frame.grid_forget() self.window_label.grid_forget() self.window_label = customtkinter.CTkLabel(self.image_label_under_frame, text=str(self.window)+" / "+ str(len(self.image_queue)), font=my_font) self.window_label.grid(row=0, column=4,padx=5, pady=5, sticky="w") if self.image_queue: self.image_label.configure(image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(620, 620))) else: self.image_label.configure(image=customtkinter.CTkImage(white_image, size=(620, 620))) app.last_window_size_conf = datetime.now() self.bind("", on_window_resize) def on_ctrl_press(event): self.control_pressed = True self.search_button.configure(text="심층 검색") self.image_history_button_up.configure(text="▲ (Top)") self.image_history_button_down.configure(text="▼ (100)") self.request_upper_size_button.configure(text="img2img (INST)", text_color="#FD8853") self.history_export.configure(text=f"export ({len(self.image_queue)})", fg_color="#1F6AA5", hover_color="#144870", text_color="#DCE4EE") if app.state() == 'zoomed': self.request_upper_size_button2.configure(text="img2img (INST)", text_color="#FD8853") def on_ctrl_release(event): self.control_pressed = False self.search_button.configure(text="검색") self.image_history_button_up.configure(text="▲") self.image_history_button_down.configure(text="▼") self.request_upper_size_button.configure(text="img2img (trial)", text_color="#FFFF97") self.history_export.configure(text="+ FAV (☆)", fg_color="#F5F3C2", hover_color="#A69F40", text_color="black") if self.image_queue and len(self.image_queue[self.current_window]) >= 5: self.history_export.configure(state="normal") else: self.history_export.configure(state="disabled") if app.state() == 'zoomed': self.request_upper_size_button2.configure(text="img2img (trial)", text_color="#FFFF97") def on_escape(event=None): self.focus_set() self.bind('', on_escape) 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): if self.control_pressed: instant_img2img(self) self.control_pressed = False else: global img2img_window if img2img_window is not None: img2img_window.destroy() img2img_window = None _img2img(self) def _img2img(self): global iimg, img2img_window, inpaint_mode def instant_image_generation(self, current_lookup): try: img2img_window.attributes('-topmost', False) except: pass def image_to_base64(image): image_bytesIO = io.BytesIO() img.save(image_bytesIO, format="png") return base64.b64encode(image_bytesIO.getvalue()).decode() def mask_to_base64(image): # PIL.Image 객체를 넘파이 배열로 변환 i = np.array(image) # RGBA 채널 처리를 위해 알파 채널 추가 전 이미지 처리 if i.shape[-1] == 3: # RGB 이미지인 경우 alpha = np.sum(i, axis=-1) > 0 # 알파 마스크 생성 alpha = np.uint8(alpha * 255) # 알파 채널 값으로 변환 rgba = np.dstack((i, alpha)) # RGBA 이미지 생성 elif i.shape[-1] == 4: # 이미 RGBA 이미지인 경우 rgba = i else: raise ValueError("Unsupported image format") # 넘파이 배열에서 PIL.Image 객체로 변환 img = Image.fromarray(rgba) # PIL.Image 객체를 Base64 문자열로 변환 image_bytesIO = io.BytesIO() img.save(image_bytesIO, format="png") return base64.b64encode(image_bytesIO.getvalue()).decode() try: i2i_generate_button.configure(state="disabled") except: pass try: request_prompt = i2i_text_input.get("0.0", "end") except: request_prompt = self.text_input.get("0.0", "end") try: request_seed = current_lookup[2] filename = current_lookup[3] except: current_lookup = self.image_queue[self.current_window].copy() request_seed = current_lookup[2] filename = current_lookup[3] img = Image.open(filename) send_image = image_to_base64(img) scale_pre = self.cfg_scale_entry.get() try: steps = request_upper_size_steps.get() except: steps = 28 try: scale_pre = float(scale_pre) except: scale_pre = 5.0 self.cfg_scale_var.set("5.0") rescale_pre = self.prompt_guidance_rescale_entry.get() try: rescale_pre = float(rescale_pre) except: rescale_pre = 0 self.prompt_guidance_rescale_var.set("0") try: steps = int(steps) except: steps = 28 self.cfg_scale_var.set("28") uncond_pre = self.uncond_strength_entry.get() try: uncond_pre = float(uncond_pre) uncond_pre = round(uncond_pre / 0.05) * 0.05 if (uncond_pre > 1.5): uncond_pre = 1.5 self.uncond_strength_entry.delete(0, "end") self.uncond_strength_entry.insert(0, "1.5") except: uncond_pre = 1.0 self.uncond_strength_entry.delete(0, "end") self.uncond_strength_entry.insert(0, "1.0") try: i2i_negative_text = i2i_negative_input.get("0.0", "end-1c") except: i2i_negative_text = self.negative_prompt_input.get("0.0", "end-1c") inpaint_check = sum(sum(row) for row in mirror_image) >= 50 gen_request = { "width":self.i2i_width if not inpaint_check else cwidth , "height":self.i2i_height if not inpaint_check else cheight, "quality_toggle":self.auto_quality_toggle.get(), "seed":request_seed if self.i2i_seed_hold_check == True else random.randint(0,9999999999), "sampler":self.sampler_button.get(), "scale":scale_pre, "uncond_scale":uncond_pre, "sema":self.sema_button.get(), "sema_dyn": self.dyn_button.get(), "cfg_rescale": rescale_pre, "prompt": request_prompt, "negative":i2i_negative_text, "user_screen_size": self.get_max_size(), "start_time": self.start_time, "access_token": self.access_token, "save_folder": self.output_file_path, "png_rule": self.name_var.get(), "type": "upper" if not inpaint_check else "inpaint", "steps": steps if steps <= 50 else 50, "image": send_image } if not inpaint_check: gen_request["strength"] = round(self.i2i_value, 2) gen_request["noise"] = 0 if gen_request["type"] == "inpaint": gen_request["mask"] = mask_to_base64(create_and_save_mask_image()) gen_request["add_original_image"] = True if overlay_original_image_var.get()==1 else False def run_generation(): if gen_request["png_rule"] == "count": self.generation_count += 1 gen_request["count"] =self.generation_count self.state_label.configure(text ="state : img2img 요청됨 ", text_color = "#FFFF97") result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request) self.state_label.configure(text ="state : img2img 요청 반환됨", text_color = "#DCE4EE") self.get_anlas() i2i_generate_button.configure(state="normal") if info: temp = info.get('Comment', '') temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','') else: temp = result_prompt self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.configure(text_color="#DCE4EE") self.image_label_report.insert("0.0", temp) self.image_label_report.configure(state="disabled") if result_image: if app.state() != 'zoomed': instant_result_image = customtkinter.CTkImage(result_image, size=(620,620)) else: current_image = Image.open(filename) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) img_label_result.grid(row=0, column=1) img_label_result.configure(image=customtkinter.CTkImage(result_image, size=(576, 576))) set_image_to_queue(result_image, result_prompt, str(result_seed), filename) generation_thread = threading.Thread(target=run_generation, daemon=True) generation_thread.start() def find_max_resolution(width, height, max_pixels=2166784, multiple_of=64): ratio = width / height max_width = int((max_pixels * ratio)**0.5) max_height = int((max_pixels / ratio)**0.5) max_width = (max_width // multiple_of) * multiple_of max_height = (max_height // multiple_of) * multiple_of while max_width * max_height > max_pixels: max_width -= multiple_of max_height = int(max_width / ratio) max_height = (max_height // multiple_of) * multiple_of return (max_width, max_height) img2img_window = customtkinter.CTkToplevel() img2img_window.title("img2img") img2img_window.attributes('-topmost', True) img2img_window.resizable(width=False, height=False) current_lookup = copy.deepcopy(self.image_queue[self.current_window]) filename = current_lookup[3] img = Image.open(filename) width, height = img.size img2img_window_left = customtkinter.CTkFrame(img2img_window) img2img_window_left.grid(row=0, column=0, pady=5, padx=5, sticky="nsew") img2img_window_right = customtkinter.CTkFrame(img2img_window, width=586) img2img_window_right.grid(row=0, column=1, pady=5, padx=5, sticky="nsew") #img2img_window_menu = customtkinter.CTkFrame(img2img_window, width=140) #img2img_window_menu.grid(row=0, column=2, pady=5, padx=5, sticky="nsew") iimg = None inpaint_mode = False iimg = Image.open(filename).convert("RGB") original_image = iimg.copy() cwidth, cheight = iimg.size # mirror_width와 mirror_height 계산 mirror_width = width // 8 mirror_height = height // 8 mirror_image = [[0 for _ in range(mirror_height)] for _ in range(mirror_width)] img_label = customtkinter.CTkCanvas(img2img_window_left, width=cwidth, height=cheight) img_label.grid(row=0, column=0) img_label_result = customtkinter.CTkLabel(img2img_window_left, text="") # 마스크 이미지 생성 및 저장 함수 def create_and_save_mask_image(): # 마스크 이미지 생성: 원본 이미지 크기의 1/8, 투명 배경 mask_image = Image.new('RGBA', (mirror_width, mirror_height), (0, 0, 0, 0)) draw = ImageDraw.Draw(mask_image) # 이중리스트를 순회하며 value > 0인 위치에 하얀색으로 칠함 for x in range(mirror_width): for y in range(mirror_height): if mirror_image[x][y] > 0: draw.point((x, y), fill=(255, 255, 255, 255)) # 마스크 이미지를 파일로 저장 return mask_image tk_image = ImageTk.PhotoImage(iimg) canvas = img_label canvas.create_image(0, 0, anchor="nw", image=tk_image) canvas.image = tk_image # 참조를 유지 def create_custom_cursor(): # 40x40px 투명 이미지 생성 cursor_image = Image.new("RGBA", (40, 40), (0, 0, 0, 0)) draw = ImageDraw.Draw(cursor_image) # 1px 하얀색 테두리 그리기 draw.rectangle([0, 0, 39, 39], outline=(255, 255, 255, 255)) return cursor_image # 마우스 이동 이벤트에 대한 핸들러 def on_mouse_move(event): # 이전에 그려진 커스텀 커서가 있다면 삭제 canvas.delete("custom_cursor") # 마우스 위치에 커스텀 커서 이미지를 표시 cursor_image = create_custom_cursor() tk_cursor_image = ImageTk.PhotoImage(cursor_image) # canvas에 커스텀 커서 이미지 렌더링. 이 때, 'tags' 옵션을 사용하여 태그를 지정 canvas.create_image(event.x, event.y, image=tk_cursor_image, anchor="center", tags="custom_cursor") # 커스텀 커서 이미지의 참조를 별도로 유지 canvas.cursor_image = tk_cursor_image # 마우스 이동 이벤트 바인딩 canvas.bind("", on_mouse_move) def inpaint_check(): global inpaint_mode check = sum(sum(row) for row in mirror_image) >= 50 if(check and not inpaint_mode): inpaint_mode = True i2i_slider_label.grid_forget() i2i_slider.grid_forget() i2i_resolution_label.grid_forget() i2i_radio_frame.grid_forget() overlay_original_image.grid(row=0, column=0, padx=30, sticky="n") cancel_inpainting_button.grid(row=0, column=1, padx=30, sticky="n") elif(inpaint_mode and not check): inpaint_mode = False overlay_original_image.grid_forget() cancel_inpainting_button.grid_forget() i2i_slider_label.grid(row=0, column=0, sticky="nsew") i2i_slider.grid(row=0, column=1, sticky="nsew") i2i_resolution_label.grid(row=1, column=0, sticky="nsew") i2i_radio_frame.grid(row=1, column=1, pady=5, sticky="nsew") def update_canvas_image(): global tk_image # 전역 변수 사용 tk_image = ImageTk.PhotoImage(iimg) canvas.create_image(0, 0, anchor="nw", image=tk_image, tags="original_image") # 'tags' 옵션을 사용하여 태그 지정 canvas.image = tk_image # 원본 이미지 참조 업데이트 def on_canvas_click_or_move(event): x, y = event.x // 8, event.y // 8 paint_on_image(x, y) update_canvas_image() def paint_on_image(x, y): draw = ImageDraw.Draw(iimg, 'RGBA') for i in range(max(0, x-2), min(mirror_width, x+3)): for j in range(max(0, y-2), min(mirror_height, y+3)): mirror_image[i][j] += 1 # 마스크 업데이트 if mirror_image[i][j] == 1: # 마스크 값이 0보다 큰 경우에만 페인트 칠함 draw.rectangle([(i*8, j*8), ((i+1)*8-1, (j+1)*8-1)], fill=(0, 0, 255, 128)) inpaint_check() def remove_paint_from_image(x, y): global iimg for i in range(max(0, x-2), min(mirror_width, x+3)): for j in range(max(0, y-2), min(mirror_height, y+3)): mirror_image[i][j] = 0 # 마스크 값을 0으로 설정 # 원본 이미지에서 해당 영역의 픽셀 값을 가져옴 original_pixels = original_image.load() current_pixels = iimg.load() for xi in range(i*8, min((i+1)*8, width)): for yi in range(j*8, min((j+1)*8, height)): # 원본 이미지의 픽셀 값을 현재 이미지에 복원 current_pixels[xi, yi] = original_pixels[xi, yi] inpaint_check() def on_canvas_right_click_or_move(event): # 마우스 우클릭 위치를 축소된 좌표로 변환 x, y = event.x // 8, event.y // 8 # 페인트 제거 함수 호출 remove_paint_from_image(x, y) # 변경된 이미지를 캔버스에 다시 표시 update_canvas_image() # 우클릭 이벤트와 우클릭 드래그 이벤트에 대한 바인딩 canvas.bind("", on_canvas_right_click_or_move) canvas.bind("", on_canvas_right_click_or_move) canvas.bind("", on_canvas_click_or_move) canvas.bind("", on_canvas_click_or_move) highlight_tags = ["aqua","black","blonde","blue","brown","cyan","green","grey","orange","pink","purple","red","violet","white","yellow","mouth", "eyes", " cap", " ears", " girl", " ornament", " hat", "beret", " ear "] def insert_with_color(): words = [word.strip() for word in current_lookup[1].split(',')] for index, word in enumerate(words): highlight = False start_index = i2i_text_input.index("end-1c") if index == len(words) - 1: # 마지막 원소인 경우 i2i_text_input.insert("end", word) else: i2i_text_input.insert("end", word + ", ") end_index = i2i_text_input.index("end-1c") for tag in highlight_tags: if tag in word: highlight = True if word == "hat": highlight = True # 조건 확인 if word in cd.character_dictionary or word in tagbag.bag_of_tags[5:] or 'tail' in word or 'pupil' in word: i2i_text_input.tag_add(word, start_index, end_index) i2i_text_input.tag_config(word, foreground="#FFFF97") elif highlight: i2i_text_input.tag_add(word, start_index, end_index) i2i_text_input.tag_config(word, foreground="#AED395") i2i_text_input_label = customtkinter.CTkLabel(img2img_window_right, text=" ------------------- i2i 프롬프트 ------------------- ", font=large_font) i2i_text_input_label.grid(row = 0, sticky="w" ) text_hyperlink = customtkinter.CTkLabel(img2img_window_right, text="가이드 열기 (arca.live)", font=customtkinter.CTkFont('Pretendard', 13), width=180, text_color="lightblue", cursor="hand2", state="disabled") text_hyperlink.grid(row=0, column=0, padx=5, pady=5, sticky="e") #text_hyperlink.bind("", lambda e: webbrowser.open_new("https://arca.live/b/aiart/95877361")) i2i_text_input = customtkinter.CTkTextbox(img2img_window_right, width=490, height=240,font=v_large_font) i2i_text_input.grid(row=1, column=0, pady=5, sticky="nsew") insert_with_color() def slider_event(value): i2i_slider_label.configure(text=f"Strength : {value:.2f}") self.i2i_value = value def get_i2i_neagtive(filename): with Image.open(filename) as img: info = img.info.get('Comment', '') start_pattern = '"uc": "' end_pattern = '", "' start_index = info.find(start_pattern) if start_index != -1: # 실제 추출할 문자열의 시작 인덱스 조정 start_index += len(start_pattern) # 종료 패턴의 인덱스를 찾기 end_index = info.find(end_pattern, start_index) if end_index != -1: # 문자열 추출 extracted_string = info[start_index:end_index] else: if app.current_window in app.import_image_negative: extracted_string = app.import_image_negative[app.current_window] else: extracted_string = "" return extracted_string i2i_offset_input_label = customtkinter.CTkLabel(img2img_window_right, text=" ------------------- i2i 네거티브 ------------------- ", font=large_font) i2i_offset_input_label.grid(row = 2, column=0,sticky="w" ) i2i_character_search_button = customtkinter.CTkButton(img2img_window_right, text="캐릭터 검색", fg_color="#7030A0", hover_color="#481F67", font=my_font, command= lambda: open_Character_search(self)) i2i_character_search_button.grid(row=2, column=0, pady=5, padx=5, sticky="e") i2i_negative_input = customtkinter.CTkTextbox(img2img_window_right, width=490, height=115,font=v_large_font) i2i_negative_input.grid(row=3, column=0, pady=5, sticky="nsew") i2i_negative = get_i2i_neagtive(filename) i2i_negative_input.insert("0.0", i2i_negative) i2i_slider_frame = customtkinter.CTkFrame(img2img_window_right, fg_color="#333333") i2i_slider_frame.grid(row=4, column=0, pady=5, padx=5, sticky="nsew") i2i_value = round(self.i2i_value, 2) i2i_seed_hold_check = 1 if self.i2i_seed_hold_check else 0 i2i_slider_label = customtkinter.CTkLabel(i2i_slider_frame, text="Strength : "+str(i2i_value), font=large_font, width=140) i2i_slider_label.grid(row=0, column=0, sticky="nsew") i2i_slider = customtkinter.CTkSlider(i2i_slider_frame, from_=0, to=0.99, number_of_steps=100, command=slider_event, width=340) i2i_slider.grid(row=0, column=1, sticky="nsew") i2i_slider.set(i2i_value) i2i_resolution_label = customtkinter.CTkLabel(i2i_slider_frame, text="해상도 배율", font=large_font, width=140) i2i_resolution_label.grid(row=1, column=0, sticky="nsew") def restore_original_image(): global tk_image, iimg iimg = Image.open(filename).convert("RGB") tk_image = ImageTk.PhotoImage(iimg.copy()) # 원본 이미지를 사용하여 Tkinter 호환 이미지 생성 canvas.create_image(0, 0, anchor="nw", image=tk_image) canvas.image = tk_image for i in range(len(mirror_image)): for j in range(len(mirror_image[i])): mirror_image[i][j] = 0 inpaint_check() overlay_original_image_var = customtkinter.IntVar() overlay_original_image = customtkinter.CTkCheckBox(i2i_slider_frame, text="Overlay Original Image", font=large_font, width=140, variable=overlay_original_image_var) cancel_inpainting_button = customtkinter.CTkButton(i2i_slider_frame, text="인페인트 취소", font=large_font, command=restore_original_image) i2i_radio_frame = customtkinter.CTkFrame(i2i_slider_frame, fg_color="#333333") i2i_radio_frame.grid(row=1, column=1, pady=5, sticky="nsew") radio_var = customtkinter.IntVar(value=self.i2i_resolution) i2i_request_width = customtkinter.IntVar(value=width) i2i_request_height = customtkinter.IntVar(value=height) img2img_window.after(2500, lambda: img2img_window.attributes('-topmost', False)) def radiobutton_event(): v = radio_var.get() if v == 0: request_width = width request_height = height self.i2i_resolution = 0 elif v == 1: request_width, request_height = find_max_resolution(width, height, 2166784) self.i2i_resolution = 1 elif v == 2: request_width, request_height = find_max_resolution(width, height, 2662400) self.i2i_resolution = 2 i2i_resolution_label.configure(text=f"{request_width} x {request_height}") i2i_request_width.set(request_width) self.i2i_width = request_width i2i_request_height.set(request_height) self.i2i_height = request_height radio_button_1 = customtkinter.CTkRadioButton(i2i_radio_frame, text="해상도 유지", command=radiobutton_event, variable= radio_var, value=0, font=large_font) radio_button_1.grid(row=0, column=0, sticky="nsew") radio_button_2 = customtkinter.CTkRadioButton(i2i_radio_frame, text="2.16 MP", command=radiobutton_event, variable= radio_var, value=1, font=large_font) radio_button_2.grid(row=0, column=1, sticky="nsew") radio_button_3 = customtkinter.CTkRadioButton(i2i_radio_frame, text="2.66 MP", command=radiobutton_event, variable= radio_var, value=2, font=large_font) radio_button_3.grid(row=0, column=2, sticky="nsew") radiobutton_event() i2i_generate_frame = customtkinter.CTkFrame(img2img_window_right, fg_color="#2B2B2B") i2i_generate_frame.grid(row=5, column=0, pady=5, sticky="n") i2i_offset_input_label2 = customtkinter.CTkLabel(i2i_generate_frame, text=" 해상도와 Strength에 따라 Anlas가 소모됩니다 ", font=large_font, text_color="#FFFF97") i2i_offset_input_label2.grid(row = 0, column=0, columnspan=3, sticky="n" ) def seed_button_event(): self.i2i_seed_hold_check = True if request_upper_size_seed_hold.get() == 1 else False request_upper_size_seed_hold_var = customtkinter.IntVar(value=i2i_seed_hold_check) request_upper_size_seed_hold = customtkinter.CTkCheckBox(i2i_generate_frame, text="시드고정 Step : ", font=my_font, variable=request_upper_size_seed_hold_var, command=seed_button_event) request_upper_size_seed_hold.grid(row=1, column=0, padx=5, pady=5, sticky="nsew") request_upper_size_seed_hold.select() if i2i_seed_hold_check == 1 else request_upper_size_seed_hold.deselect() request_upper_size_steps = customtkinter.StringVar(value="28") request_upper_size_steps_entry = customtkinter.CTkEntry(i2i_generate_frame, font=my_font, textvariable=request_upper_size_steps, width=60) request_upper_size_steps_entry.grid(row=1, column=1,padx=5, pady=5, sticky="nsew") i2i_generate_button = customtkinter.CTkButton(i2i_generate_frame, text="Request I2I", font=large_font, command=lambda: instant_image_generation(self, current_lookup)) i2i_generate_button.grid(row = 1, column= 2, pady=5, sticky="n" ) def instant_img2img(self): current_lookup = self.image_queue[self.current_window].copy() def instant_image_generation(self): def image_to_base64(image): image_bytesIO = io.BytesIO() img.save(image_bytesIO, format="png") return base64.b64encode(image_bytesIO.getvalue()).decode() request_prompt = current_lookup[1] request_seed = current_lookup[2] filename = current_lookup[3] img = Image.open(filename) send_image = image_to_base64(img) scale_pre = self.cfg_scale_entry.get() steps = 28 try: scale_pre = float(scale_pre) except: scale_pre = 5.0 self.cfg_scale_var.set("5.0") rescale_pre = self.prompt_guidance_rescale_entry.get() try: rescale_pre = float(rescale_pre) except: rescale_pre = 0 self.prompt_guidance_rescale_var.set("0") try: steps = int(steps) except: steps = 28 #self.cfg_scale_var.set("28") uncond_pre = self.uncond_strength_entry.get() try: uncond_pre = float(uncond_pre) uncond_pre = round(uncond_pre / 0.05) * 0.05 if (uncond_pre > 1.5): uncond_pre = 1.5 self.uncond_strength_entry.delete(0, "end") self.uncond_strength_entry.insert(0, "1.5") except: uncond_pre = 1.0 self.uncond_strength_entry.delete(0, "end") self.uncond_strength_entry.insert(0, "1.0") i2i_negative_text = self.negative_prompt_input.get("0.0", "end-1c") gen_request = { "width":self.i2i_width, "height":self.i2i_height, "quality_toggle":self.auto_quality_toggle.get(), "seed":request_seed if self.i2i_seed_hold_check == True else random.randint(0,9999999999), "sampler":self.sampler_button.get(), "scale":scale_pre, "uncond_scale":uncond_pre, "sema":self.sema_button.get(), "sema_dyn": self.dyn_button.get(), "cfg_rescale": rescale_pre, "prompt": request_prompt, "negative":i2i_negative_text, "user_screen_size": self.get_max_size(), "start_time": self.start_time, "access_token": self.access_token, "save_folder": self.output_file_path, "png_rule": self.name_var.get(), "type": "upper", "steps": steps if steps <= 50 else 50, "image": send_image, "strength": round(self.i2i_value, 2), "noise": 0 } def run_generation(): if gen_request["png_rule"] == "count": self.generation_count += 1 gen_request["count"] =self.generation_count self.state_label.configure(text ="state : img2img 요청됨 ", text_color = "#FFFF97") result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request) self.state_label.configure(text ="state : img2img 요청 반환됨", text_color = "#DCE4EE") self.get_anlas() if info: temp = info.get('Comment', '') temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','') else: temp = result_prompt self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.configure(text_color="#DCE4EE") self.image_label_report.insert("0.0", temp) self.image_label_report.configure(state="disabled") if result_image: if app.state() != 'zoomed': instant_result_image = customtkinter.CTkImage(result_image, size=(620,620)) else: current_image = Image.open(filename) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) set_image_to_queue(result_image, result_prompt, str(result_seed), filename) generation_thread = threading.Thread(target=run_generation, daemon=True) generation_thread.start() def find_max_resolution(width, height, max_pixels=2166784, multiple_of=64): ratio = width / height max_width = int((max_pixels * ratio)**0.5) max_height = int((max_pixels / ratio)**0.5) max_width = (max_width // multiple_of) * multiple_of max_height = (max_height // multiple_of) * multiple_of while max_width * max_height > max_pixels: max_width -= multiple_of max_height = int(max_width / ratio) max_height = (max_height // multiple_of) * multiple_of return (max_width, max_height) img = Image.open(current_lookup[3]) width, height = img.size v = self.i2i_resolution if v == 0: self.i2i_width = width self.i2i_height = height elif v == 1: self.i2i_width, self.i2i_height = find_max_resolution(width, height, 2166784) elif v == 2: self.i2i_width, self.i2i_height = find_max_resolution(width, height, 2662400) instant_image_generation(self) self.bind("", 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 self.wildcard_preopen_repeat = 1 self.wildcard_preopen_repeat_flag = False self.wildcard_preopen_repeat_current = 1 self.previous_fix_prompt = None self.i2i_value = 0.7 self.i2i_seed_hold_check = True self.i2i_resolution = 0 self.i2i_width = 0 self.i2i_height = 0 self.i2i_steps = 28 self.image_label.drop_target_register(DND_ALL) self.image_label.dnd_bind("<>", self.on_drop) self.after(500, highlight_text) #세상에 시발 이 위까지 전부 __init__에 들어가있음 def on_drop(self, event): def read_info_from_image_stealth(image): # trying to read stealth pnginfo width, height = image.size pixels = image.load() if image.mode != 'RGBA': return {} binary_data = '' buffer_a = '' index_a = 0 confirming_signature = True reading_param_len = False reading_param = False read_end = False for x in range(width): for y in range(height): r, g, b, a = pixels[x, y] buffer_a += str(a & 1) index_a += 1 if confirming_signature and x == 0: if y == 119: # index_a == len('stealth_pngcomp') * 8: decoded_sig = bytearray(int(buffer_a[i:i + 8], 2) for i in range(0, len(buffer_a), 8)).decode('utf-8', errors='ignore') if decoded_sig == 'stealth_pngcomp': confirming_signature = False reading_param_len = True buffer_a = '' index_a = 0 elif reading_param_len: if y == 151: # index_a == 32: param_len = int(buffer_a, 2) reading_param_len = False reading_param = True buffer_a = '' index_a = 0 elif reading_param: if index_a == param_len: binary_data = buffer_a read_end = True break else: read_end = True break if read_end: break if binary_data != '': # Convert binary string to UTF-8 encoded text byte_data = bytearray(int(binary_data[i:i + 8], 2) for i in range(0, len(binary_data), 8)) try: decoded_data = gzip.decompress( bytes(byte_data)).decode('utf-8') return decoded_data except Exception as e: print(e) pass return {} def download_image_from_url(url): response = requests.get(url) response.raise_for_status() # 에러가 발생했을 경우 예외를 던짐 return Image.open(io.BytesIO(response.content)) def extract_keywords_from_image(image): if image.info and image.info.get('dpi') is None: result = image.info.get('Comment', '') if result == '': result = image.info.get('parameters', '') if result != '': try: result = json.loads(result) except: result = image.info.get('parameters', '') return result else: self.image_label_report.configure(state="normal", text_color = "#FFFF97") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " : 이미지에서 NAI 정보를 얻는데 실패하였습니다. 이미지에 메타데이터가 없습니다.") self.image_label_report.configure(state="disabled") else: return json.loads(result) else: stealth_info = read_info_from_image_stealth(image) if isinstance(stealth_info, str): # 문자열 내의 모든 '\\'를 제거하거나 다른 문자로 대체 try: result = stealth_info.replace("\\", "") comment_data = json.loads(result) return comment_data except: return stealth_info.replace("\\", "") elif stealth_info and 'Comment' in stealth_info: try: # Comment 값이 JSON 문자열인지 확인하고, 파싱 comment_data = json.loads(stealth_info['Comment']) # 'prompt' 키의 값을 추출하여 반환 if 'prompt' in comment_data: return comment_data["prompt"].strip() else: self.image_label_report.configure(state="normal", text_color = "#FFFF97") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " : 이미지에서 NAI 정보를 얻는데 실패하였습니다. comment_data가 존재하지만 NAI와 호환되는 Stable Diffusion 이미지가 아닙니다.") self.image_label_report.configure(state="disabled") except json.JSONDecodeError: self.image_label_report.configure(state="normal", text_color = "#FFFF97") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " : 이미지에서 NAI 정보를 얻는데 실패하였습니다.") self.image_label_report.configure(state="disabled") else: self.image_label_report.configure(state="normal", text_color = "#FFFF97") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " : 이미지에서 NAI 정보를 얻는데 실패하였습니다. 이미지에 메타데이터가 없습니다.") self.image_label_report.configure(state="disabled") file_path_or_url = event.data file_path_or_url = file_path_or_url.strip("{}") from_url = False try: # URL의 유효성 검사 if file_path_or_url.startswith(('http://', 'https://')): from_url = True img = download_image_from_url(file_path_or_url) else: if file_path_or_url.startswith(('blob:')): self.image_label_report.configure(state="normal", text_color = "#FFFF97") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", " : NAI 홈페이지에서 생성한 이미지는 NAIA로 즉시 복사할 수 없습니다. 이미지를 다운로드 한 뒤, 드래그 & 드랍을 통해 NAIA에 전달 해 주세요.") self.image_label_report.configure(state="disabled") return try: img = Image.open(file_path_or_url) except: try: file_path_or_url = file_path_or_url.replace("\\", '') img = Image.open(file_path_or_url) except: try: file_path_or_url = file_path_or_url.replace("\\", '/') img = Image.open(file_path_or_url) except: self.image_label_report.configure(state="normal", text_color = "#FFFF97") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", f" : Tkdnd2로부터 유효하지 않은 file path 또는 url : '{file_path_or_url}' 를 전달 받았습니다.") self.image_label_report.configure(state="disabled") return # 이미지 객체로부터 키워드 추출 description = extract_keywords_from_image(img) if description == '' or description == None: return elif type(description) == type(' '): text_type, contents = 'str', description if '"Software": "NovelAI"' in contents: software = 'NAI' else: software = 'Local' else: text_type, contents = 'dict', description if 'sm' in contents: software = 'NAI' else: software = 'Local' #image window import_window = customtkinter.CTkToplevel() import_window.title("Image with Metadata found!") import_window.attributes('-topmost', True) import_window.resizable(width=False, height=False) import_window_left = customtkinter.CTkFrame(import_window) import_window_left.grid(row=0, column=0, pady=5, padx=5, sticky="nsew") import_window_right = customtkinter.CTkFrame(import_window, width=596) import_window_right.grid(row=0, column=1, pady=5, padx=5, sticky="nsew") width, height = img.size new_size = max(width, height) new_image = Image.new("RGB", (new_size, new_size), 'black') left = (new_size - width) // 2 top = (new_size - height) // 2 new_image.paste(img, (left, top)) import_window_img = customtkinter.CTkImage(new_image, size=(576, 576)) import_window_img_label = customtkinter.CTkLabel(import_window_left, text="", image=import_window_img) import_window_img_label.grid(row=0, column=0) if software == 'Local': local_prompt = customtkinter.CTkTextbox(import_window_right, height=576, width=586, font=customtkinter.CTkFont('Pretendard', 14)) local_prompt.grid(row=0, column=0, pady=5, padx=5, sticky="nsew") contents = 'Image Type : Local Generated \n\n' + str(contents).replace('\n', '\n\n') local_prompt.insert("0.0", contents) else: if text_type == 'str': try: start_marker = '"Comment": "' end_marker = '", "request_type"' start_index = contents.find(start_marker) + len(start_marker) end_index = contents.find(end_marker, start_index) text = contents[start_index:end_index] contents = {} except: local_prompt = customtkinter.CTkTextbox(import_window_right, height=766, width=766, font=customtkinter.CTkFont('Pretendard', 15)) local_prompt.grid(row=0, column=0, pady=5, padx=5, sticky="nsew") contents = 'Image Type : Local Generated \n\n' + str(contents).replace('\n', '\n\n') local_prompt.insert("0.0", contents) try: start_marker = 'prompt": "' end_marker = '", "steps' start_index = text.find(start_marker) + len(start_marker) end_index = text.find(end_marker, start_index) contents['prompt'] = text[start_index:end_index] text = text[end_index:] except: pass try: start_marker = '"uc": "' end_marker = '", "request_type' start_index = text.find(start_marker) + len(start_marker) end_index = text.find(end_marker, start_index) contents['uc'] = text[start_index:] text = text[:start_index] except: pass keys = ["steps", "scale", "uncond_scale", "cfg_rescale", "seed", "sampler", "sm", "sm_dyn"] for key in keys: # 정규 표현식 패턴: key 다음에 나오는 : 공백을 포함한 후 어떤 값이든(숫자, 문자열 등) 매치 pattern = r'"{}":\s*([^,}}]+)'.format(key) match = re.search(pattern, text) if match: # 값을 추출 (그룹 1) value = match.group(1) # 숫자이면 숫자로 변환, 그 외의 경우는 그대로 사용 (True, False, 문자열 등) try: # 정수, 실수 변환 시도 if '.' in value: contents[key] = float(value) else: contents[key] = int(value) except ValueError: # boolean 변환 시도 if value.lower() == "true": contents[key] = True elif value.lower() == "false": contents[key] = False else: # 문자열 그대로 저장 (쌍따옴표 제거) contents[key] = value.strip('"') my_font = customtkinter.CTkFont('Pretendard', 13) large_font = customtkinter.CTkFont('Pretendard', 14) NAI_prompt_label = customtkinter.CTkLabel(import_window_right, width=586, font=my_font, text=" -------------------- 프롬프트 -------------------- ") NAI_prompt_label.grid(row=0, column=0, padx=5, sticky="nsew") NAI_prompt = customtkinter.CTkTextbox(import_window_right, width=586, height=205, font=large_font) NAI_prompt.grid(row=1, column=0, pady=5, padx=5, sticky="nsew") NAI_negative_label = customtkinter.CTkLabel(import_window_right, width=586, font=my_font, text=" --------------- 네거티브 프롬프트 --------------- ") NAI_negative_label.grid(row=2, column=0, padx=5, sticky="nsew") NAI_negative = customtkinter.CTkTextbox(import_window_right, width=586,height=130, font=large_font) NAI_negative.grid(row=3, column=0, pady=5, padx=5, sticky="nsew") NAI_prompt.insert("0.0", contents['prompt']) NAI_prompt.configure(state="disabled") NAI_negative.insert("0.0", contents['uc']) NAI_negative.configure(state="disabled") import_frame1 = customtkinter.CTkFrame(import_window_right, width=586, fg_color="#2B2B2B") import_frame1.grid(row=4, column=0, pady=5, padx=5, sticky="nsew") i_steps_label = customtkinter.CTkLabel(import_frame1, font=my_font, text="Steps : ") i_steps_label.grid(row=0, column=0, padx=5, sticky="nsew") i_steps = customtkinter.CTkEntry(import_frame1, font=my_font, width=35) i_steps.grid(row=0, column=1, padx=5, sticky="nsew") i_steps.insert(0, str(contents['steps'])) i_steps.configure(state="disabled") i_scale_label = customtkinter.CTkLabel(import_frame1, font=my_font, text="CFG Scale : ") i_scale_label.grid(row=0, column=2, padx=5, sticky="nsew") i_scale = customtkinter.CTkEntry(import_frame1, font=my_font, width=40) i_scale.grid(row=0, column=3, padx=5, sticky="nsew") i_scale.insert(0, str(contents['scale'])) i_scale.configure(state="disabled") i_uncond_label = customtkinter.CTkLabel(import_frame1, font=my_font, text="UC Strength : ") i_uncond_label.grid(row=0, column=4, padx=5, sticky="nsew") i_uncond = customtkinter.CTkEntry(import_frame1, font=my_font, width=40) i_uncond.grid(row=0, column=5, padx=5, sticky="nsew") i_uncond.insert(0, str(contents['uncond_scale'])) i_uncond.configure(state="disabled") i_rescale_label = customtkinter.CTkLabel(import_frame1, font=my_font, text="CFG Rescale : ") i_rescale_label.grid(row=0, column=6, padx=5, sticky="nsew") i_rescale = customtkinter.CTkEntry(import_frame1, font=my_font, width=40) i_rescale.grid(row=0, column=7, padx=5, sticky="nsew") i_rescale.insert(0, str(contents['cfg_rescale'])) i_rescale.configure(state="disabled") import_frame2 = customtkinter.CTkFrame(import_window_right, width=586, fg_color="#2B2B2B") import_frame2.grid(row=5, column=0, pady=5, padx=5, sticky="nsew") i_seed_label = customtkinter.CTkLabel(import_frame2, font=my_font, text="Steps : ") i_seed_label.grid(row=0, column=0, padx=5, sticky="nsew") i_seed = customtkinter.CTkEntry(import_frame2, font=my_font, width=100) i_seed.grid(row=0, column=1, padx=5, sticky="nsew") i_seed.insert(0, str(contents['seed'])) i_sampler_label = customtkinter.CTkLabel(import_frame2, font=my_font, text="Steps : ") i_sampler_label.grid(row=0, column=2, padx=5, sticky="nsew") i_sampler = customtkinter.CTkEntry(import_frame2, font=my_font, width=100) i_sampler.grid(row=0, column=3, padx=5, sticky="nsew") i_sampler.insert(0, str(contents['sampler'])) i_smea = customtkinter.CTkCheckBox(import_frame2, font=my_font, text="SMEA") i_smea.grid(row=0, column=4, padx=5, sticky="nsew") if contents['sm'] == True: i_smea.select() else: i_smea.deselect() i_dyn = customtkinter.CTkCheckBox(import_frame2, font=my_font, text="SMEA+DYN") i_dyn.grid(row=0, column=5, padx=5, sticky="nsew") if contents['sm_dyn'] == True: i_dyn.select() else: i_dyn.deselect() i_smea.configure(state="disabled") i_dyn.configure(state="disabled") import_frame3 = customtkinter.CTkFrame(import_window_right, width=586, fg_color="#2B2B2B") import_frame3.grid(row=6, column=0, pady=5, padx=5, sticky="nsew") i_resolution_label = customtkinter.CTkLabel(import_frame3, font=my_font, text="Resolution : ") i_resolution_label.grid(row=0, column=0, padx=5, sticky="nsew") i_resolution = customtkinter.CTkEntry(import_frame3, font=my_font, width=100) i_resolution.grid(row=0, column=1, padx=5, sticky="nsew") i_resolution.insert(0, f"{width} x {height}") import_frame4 = customtkinter.CTkFrame(import_window_right, width=586, fg_color="#2B2B2B") import_frame4.grid(row=7, column=0, pady=10, padx=5, sticky="n") def image_to_base64(image): image_bytesIO = io.BytesIO() image.save(image_bytesIO, format="PNG") return base64.b64encode(image_bytesIO.getvalue()).decode() def save_base64_image(base64_string): image_data = base64.b64decode(base64_string) output_file_path = f"output_NAI\\{self.start_time}\\import" d = Path(output_file_path) d.mkdir(parents=True, exist_ok=True) filename = (d / f"{app.import_image_count:05}.png" ) filename.write_bytes(image_data) return filename def image_to_queue(): if from_url == True: base64_string = image_to_base64(img) filename = save_base64_image(base64_string) app.ext_set_image_to_queue(new_image.copy(), contents['prompt'], str(contents['seed']), filename) app.import_image_count += 1 else: app.ext_set_image_to_queue(new_image.copy(), contents['prompt'], str(contents['seed']), file_path_or_url) app.import_image_negative[len(app.image_queue)-1] = contents['uc'] import_image_to_queue = customtkinter.CTkButton(import_frame4, font=my_font, text="이미지/프롬프트를 큐에 삽입", command=image_to_queue) import_image_to_queue.grid(row=0, column=0, padx=5, sticky="nsew") if text_type == 'str': import_image_to_queue.configure(state="disabled") def prompt_insert(): app.text_input.delete("0.0", "end") app.text_input.insert("0.0", contents['prompt']) app.negative_prompt_input.delete("0.0", "end") app.negative_prompt_input.insert("0.0", contents['uc']) app.automation_button.deselect() import_prompts = customtkinter.CTkButton(import_frame4, font=my_font, text="프롬프트/네거티브 삽입", fg_color="grey", hover_color="grey10", command=prompt_insert) import_prompts.grid(row=0, column=1, padx=5, sticky="nsew") # ["steps", "scale", "uncond_scale", "cfg_rescale", "seed", "sampler", "sm", "sm_dyn" def settings_insert(): app.cfg_scale_var.set(str(contents['scale'])) app.cfg_scale_entry.delete(0, "end") app.cfg_scale_entry.insert(0, str(contents['scale'])) app.uncond_strength_entry.delete(0, "end") app.uncond_strength_entry.insert(0, str(contents['uncond_scale'])) app.prompt_guidance_rescale_var.set(str(contents['cfg_rescale'])) app.prompt_guidance_rescale_entry.delete(0, "end") app.prompt_guidance_rescale_entry.insert(0, str(contents['cfg_rescale'])) app.seed_fix_button.select() app.seed_entry.delete(0, "end") app.seed_entry.insert(0, str(contents['seed'])) app.sampler_var.set(contents['sampler']) app.sampler_button.set(contents['sampler']) if contents['sm'] == True: app.sema_button.select() else: app.sema_button.deselect() if contents['sm_dyn'] == True: app.dyn_button.select() else: app.dyn_button.deselect() app.random_resolution_button.deselect() app.resolution_button.set(f"{width} x {height}") app.resolution_var.set(f"{width} x {height}") app.cond_negative_button.deselect() app.automation_button.deselect() import_settings = customtkinter.CTkButton(import_frame4, font=my_font, text="설정값 일괄 삽입", fg_color="#F5F3C2", hover_color="#A69F40", text_color="black", command=settings_insert) import_settings.grid(row=0, column=2, padx=5, sticky="nsew") import_window.after(1500, lambda: import_window.attributes('-topmost', False)) except Exception as e: self.image_label_report.configure(state="normal", text_color = "#FFFF97") self.image_label_report.delete("0.0", "end") self.image_label_report.insert("0.0", f"Error: {e}") self.image_label_report.configure(state="disabled") def ext_set_image_to_queue(self, imagen, prompt, seed, filename): self.image_queue.append([imagen, prompt, seed, filename]) #self.history_export.configure(text=f"export ({len(self.image_queue)})") self.request_upper_size_button.configure(state="normal") self.current_window = self.window if self.window == len(self.image_queue)-1: self.window+=1 self.update() show_text = str(self.window)+" / "+ str(len(self.image_queue)) self.window_label.configure(text=show_text) def update(self): if len(self.image_queue) <= 5: if len(self.image_queue) >= 1: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) if len(self.image_queue) >= 2: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100))) if len(self.image_queue) >= 3: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100))) self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100))) if len(self.image_queue) >= 4: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100))) self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100))) self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100))) if len(self.image_queue) == 5: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100))) self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100))) self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100))) self.image_history_4.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-5][0], size=(100,100))) else: self.image_history_0.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-1][0], size=(100,100))) self.image_history_1.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-2][0], size=(100,100))) self.image_history_2.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-3][0], size=(100,100))) self.image_history_3.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-4][0], size=(100,100))) self.image_history_4.configure(self.image_history_sub_frame, image=customtkinter.CTkImage(self.image_queue[self.window-5][0], size=(100,100))) if len(self.image_queue) == 6: self.image_history_button_down.configure(state="normal") def save_settings(self): settings = { "NAI_ID": self.NAI_ID if self.NAI_ID else " ", "access_token": self.access_token if self.access_token else " ", "searach_keyword": self.search_label_entry.get() if len(self.search_label_entry.get()) > 3 else " ", "exclude_keyword": self.exclude_label_entry.get() if len(self.exclude_label_entry.get()) > 3 else " ", "explicit": self.rating_select_explicit.get(), "nsfw": self.rating_select_nsfw.get(), "sensitive": self.rating_select_sensitive.get(), "general": self.rating_select_general.get(), "rm_artist": self.rm_artist_name_button.get(), "rm_copyright": self.rm_copyright_name_button.get(), "rm_character": self.rm_characteristic_button.get(), "prompt": self.text_input.get("0.0", "end-1c") if len(self.text_input.get("0.0", "end")) > 4 else " ", "negative": self.negative_prompt_input.get("0.0", "end-1c") if len(self.negative_prompt_input.get("0.0", "end")) > 4 else " ", "fix": self.fixed_prompt_input.get("0.0", "end-1c") if len(self.fixed_prompt_input.get("0.0", "end")) > 4 else " ", "after": self.fixed_prompt_after_input.get("0.0", "end-1c") if len(self.fixed_prompt_after_input.get("0.0", "end")) > 4 else " ", "auto_hide": self.auto_hide_keyword_input.get("0.0", "end-1c") if len(self.auto_hide_keyword_input.get("0.0", "end")) > 4 else " ", "cfg_scale": str(self.cfg_scale_entry.get()), "uncond_scale": str(self.uncond_strength_entry.get()), "guidance": str(self.prompt_guidance_rescale_entry.get()), "sampler": self.sampler_var.get(), "random": self.random_resolution_button.get(), "sema": self.sema_button.get(), "dyn": self.dyn_button.get(), "personal_folder":self.output_file_path_personal, "save_folder":self.output_file_path if self.output_file_path_personal else " ", "png_rule":self.name_var.get(), "quality_toggle":self.auto_quality_toggle.get(), "cond_prompt": self.conditional_prompt_input.get("0.0", "end-1c") if len(self.conditional_prompt_input.get("0.0", "end")) > 4 else " ", "cond_negative": self.conditional_negative_input.get("0.0", "end-1c") if len(self.conditional_negative_input.get("0.0", "end")) > 4 else " ", "activate_cond_prompt": self.cond_prompt_button.get(), "activate_cond_negative": self.cond_negative_button.get(), "prompt_rating": self.current_prompt_rating, "resolution": self.resolution_button.get(), "wildcard_preopen": self.toggle_wildcard_preopen.get(), "i2i": [self.i2i_value, self.i2i_seed_hold_check, self.i2i_resolution] } with open('app_settings.json', 'w', encoding='utf-8') as f: json.dump(settings, f, ensure_ascii=False, indent=4) if type(self.cached_rows) != type(None) and not self.cached_rows.empty: self.cached_rows.to_parquet('txt2img_temp_prompt.parquet') #print("finished") def load_settings(self): if os.path.exists('app_settings.json'): with open('app_settings.json', 'r', encoding='utf-8') as f: try: settings = json.load(f) try: self.NAI_ID = settings["NAI_ID"] if len(settings["NAI_ID"]) > 2 else None except: pass try: self.access_token = settings["access_token"] if len(settings["access_token"]) > 2 else None if self.access_token: self.NAI_Account_Login.configure(state="disabled") self.NAI_Token_Remove.configure(state="normal") self.NAI_Account_State.configure(text="검색 UI 숨기기") self.image_generation_button.configure(state="normal") except: pass try: self.search_label_entry.insert(0, settings["searach_keyword"]) except: pass try: self.exclude_label_entry.insert(0, settings["exclude_keyword"]) except: pass try: self.rating_select_var_explicit.set(settings["explicit"]) if settings["explicit"] == 1: self.rating_select_explicit.select() else: self.rating_select_explicit.deselect() except: pass try: self.rating_select_var_nsfw.set(settings[ "nsfw"]) if settings["nsfw"] == 1: self.rating_select_nsfw.select() else: self.rating_select_nsfw.deselect() except: pass try: self.rating_select_var_sensitive.set(settings["sensitive"]) if settings["sensitive"] == 1: self.rating_select_sensitive.select() else: self.rating_select_sensitive.deselect() except: pass try: self.rating_select_var_general.set(settings["general"]) if settings["general"] == 1: self.rating_select_general.select() else: self.rating_select_general.deselect() except: pass try: self.rm_artist_name_var = settings["rm_artist"] if settings["rm_artist"] == 1: self.rm_artist_name_button.select() else: self.rm_artist_name_button.deselect() except: pass try: self.rm_copyright_name_var = settings["rm_copyright"] if settings["rm_copyright"] == 1: self.rm_copyright_name_button.select() else: self.rm_copyright_name_button.deselect() except: pass try: self.rm_characteristic_var = settings["rm_character"] if settings["rm_character"] == 1: self.rm_characteristic_button.select() else: self.rm_characteristic_button.deselect() except: pass try: self.text_input.insert("0.0", settings["prompt"]) except: pass try: self.negative_prompt_input.delete("0.0", "end") self.negative_prompt_input.insert("0.0", settings["negative"]) except: pass try: self.fixed_prompt_input.insert("0.0", settings["fix"]) except: pass try: self.fixed_prompt_after_input.insert("0.0", settings["after"]) except: pass try: self.auto_hide_keyword_input.insert("0.0", settings[ "auto_hide"]) except: pass try: self.cfg_scale_entry.delete(0, "end") self.cfg_scale_entry.insert(0, str(settings["cfg_scale"])) self.cfg_scale_var.set(settings["cfg_scale"]) except: pass try: self.prompt_guidance_rescale_entry.delete(0, "end") self.prompt_guidance_rescale_entry.insert(0, str(settings["guidance"])) self.prompt_guidance_rescale_var.set(settings["guidance"]) except: pass try: self.sampler_var.set(settings["sampler"]) self.sampler_button.set(settings["sampler"]) except: pass try: self.random_resolution_var.set(settings["random"]) if settings["random"] == 1: self.random_resolution_button.select() else: self.random_resolution_button.deselect() except: pass try: self.sema_button_var.set(settings["sema"]) if settings["sema"] == 1: self.sema_button.select() else: self.sema_button.deselect() except: pass try: self.dyn_button_var.set(settings["dyn"]) if settings["dyn"] == 1: self.dyn_button.select() else: self.dyn_button.deselect() except: pass try: if settings["personal_folder"] == True: self.output_file_path_personal =True self.output_file_path = settings["save_folder"] else: self.output_file_path_personal =False except: pass try: self.name_var.set(settings["png_rule"]) except: pass try: self.auto_quality_toggle_var=settings["quality_toggle"] if settings["quality_toggle"] == 1: self.auto_quality_toggle.select() else: self.auto_quality_toggle.deselect() except: pass try: self.conditional_prompt_input.insert("0.0", settings[ "cond_prompt"]) except: pass try: self.conditional_negative_input.insert("0.0", settings[ "cond_negative"]) except: pass try: self.cond_prompt_button_var.set(settings["activate_cond_prompt"]) if settings["activate_cond_prompt"] == 1: self.cond_prompt_button.select() else: self.cond_prompt_button.deselect() except: pass try: self.cond_prompt_button_var.set(settings["activate_cond_negative"]) if settings["activate_cond_negative"] == 1: self.cond_negative_button.select() else: self.cond_negative_button.deselect() except: pass try: self.current_prompt_rating = settings["prompt_rating"] except: pass try: self.resolution_var.set(settings["resolution"]) self.resolution_button.set(settings["resolution"]) except: pass try: self.toggle_wildcard_preopen_var.set(settings["wildcard_preopen"]) if settings["wildcard_preopen"] == 1: self.toggle_wildcard_preopen.select() else: self.toggle_wildcard_preopen.deselect() except: pass try: self.uncond_strength_entry.delete(0, "end") self.uncond_strength_entry.insert(0, settings["uncond_scale"]) except: pass try: self.i2i_value, self.i2i_seed_hold_check, self.i2i_resolution = settings["i2i"][0], settings["i2i"][1],settings["i2i"][2] except: pass except json.JSONDecodeError as e: self.image_label_report.configure(state="normal", text_color = "#FFFF97") self.image_label_report.insert("0.0", "세이브 파일을 불러오는데 실패하였습니다 : " + str(e)) self.image_label_report.configure(state="disabled") if os.path.exists('txt2img_temp_prompt.parquet'): try: self.cached_rows = pd.read_parquet('txt2img_temp_prompt.parquet') self.cached_prompt_label.configure(text = "남은 프롬프트 행 : "+str(len(self.cached_rows))) if 'id' not in self.cached_rows.columns: self.image_label_report.configure(state="normal", text_color = "#FFFF97") self.image_label_report.insert("0.0", " 0215 버전부터 tags의 구성이 변경되었습니다. favorite 기능을 사용하기 위해 검색을 다시 수행 해 주세요.") self.image_label_report.configure(state="disabled") except: pass def exit_program(self): self.save_settings() app.destroy() def get_max_size(self): width = self.winfo_screenheight() return 768 if width < 1440 else 768 def update_fullscreen_image(self,new_window, new_image_label): last_updated_image = None while True: time.sleep(1) if not new_window.winfo_exists(): break if self.image_queue: current_image = Image.open(self.image_queue[self.window-1][3]) if current_image and current_image != last_updated_image: #resized_image = self.resize_image_to_fit(current_image, new_window.winfo_screenheight()) original_width, original_height = current_image.size ratio = new_window.winfo_screenheight() / float(original_height) new_width = int(original_width * ratio) tk_image = customtkinter.CTkImage(current_image, size=(new_width,new_window.winfo_screenheight())) new_window.after(0, lambda img=tk_image: new_image_label.configure(image=img)) new_image_label.image = tk_image last_updated_image = current_image def show_fullscreen_image(self): new_window = customtkinter.CTkToplevel() new_window.attributes('-fullscreen', True) new_window.state('zoomed') new_window.configure(bg='black') new_image_label = customtkinter.CTkLabel(new_window, text=" ") new_image_label.pack(expand=True, fill='both') new_window.bind("", 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 def open_instant_event(self): my_font = customtkinter.CTkFont('Pretendard', 13) instant_event_window = customtkinter.CTkToplevel() instant_event_window.title("인스턴트 이벤트 (작업 도중 종료하지 마세요)") instant_event_window.attributes('-topmost', True) instant_event_window.resizable(width=False, height=False) tabview = customtkinter.CTkTabview(instant_event_window) tabview.grid(row=0, column=0, padx=5, pady=5) generation_frame = customtkinter.CTkFrame(instant_event_window, height=300) generation_frame.grid(row=0, column=1, padx=5, pady=5) generation_label = customtkinter.CTkLabel(generation_frame, text="0 / 0", font=my_font) generation_label.grid(row=0, column=0, padx=5, pady=5, sticky="n") self.instant_stop_bit = False def stop_gen(): self.instant_stop_bit = True generation_stop_button.configure(state = "disabled") xyz_execute_button.configure(state="normal") def close_window(): stop_gen() instant_event_window.destroy() generation_stop_button = customtkinter.CTkButton(generation_frame, text="Stop", font=my_font, state="disabled", command=stop_gen) generation_stop_button.grid(row=1, column=0, padx=5, pady=25, sticky="n") instant_event_window.protocol("WM_DELETE_WINDOW", close_window) #Tab 관리 tabview.add("X/Y plot") def xyz_excute(): comboboxes = [xyz_box1, xyz_box2] prompts = [xyz_prompt1, xyz_prompt2] xyz_list = [] prompt_list = [] prompt_len = 0 for i, combobox in enumerate(comboboxes): value = combobox.get() #None if value == "None": continue #CFG Scale elif value == "CFG Scale": xyz_list.append("CFG Scale") input_string = prompts[i].get("0.0", "end-1c") split_strings = [s.strip() for s in input_string.split(',')] float_values = [float(s) for s in split_strings] cfg_scale_list = [] while float_values[0] <= float_values[1]: cfg_scale_list.append(float_values[0]) float_values[0] += float_values[2] cfg_scale_list = [round(v, 1) for v in cfg_scale_list] #PG.Rescale elif value == "PG.Rescale": xyz_list.append("PG.Rescale") input_string = prompts[i].get("0.0", "end-1c") split_strings = [s.strip() for s in input_string.split(',')] float_values = [float(s) for s in split_strings] pg_rescale_list = [] while float_values[0] <= float_values[1]: pg_rescale_list.append(float_values[0]) float_values[0] += float_values[2] pg_rescale_list = [round(v, 1) for v in pg_rescale_list] #프롬프트 강조 elif value == "프롬프트 강조": xyz_list.append("프롬프트 강조") input_string = prompts[i].get("0.0", "end-1c") split_strings = [s.strip() for s in input_string.split(',')] split_strings[0] = str(split_strings[0]) split_strings[1] = int(split_strings[1]) split_strings[2] = int(split_strings[2]) split_strings[3] = int(split_strings[3]) keyword = split_strings[0] ### 와일드카드 처리 ### if prompt_len == 0: before_wildcard = self.text_input.get("0.0", "end-1c") before_wildcard = [item.strip() for item in before_wildcard.split(',')] if '<' in self.text_input.get("0.0", "end-1c"): #### 단계 1 : 인스턴트 와일드카드 처리 ### for i, keyword in enumerate(before_wildcard): if keyword.startswith('<') and keyword.endswith('>'): vbar_check = keyword[1:-1] if '|' in vbar_check: choices = vbar_check.split('|') # '|'를 기준으로 split choice_dic = {} for choice in choices: match = re.match(r'(\d*\.?\d+):(.+)', choice) if match: value, keyword = float(match.group(1)), match.group(2).strip() else: value, keyword = 1, choice.strip() choice_dic[keyword] = value keywords = list(choice_dic.keys()) weights = list(choice_dic.values()) selected_instant_wildcard = random.choices(keywords, weights=weights, k=1)[0] before_wildcard[i] = selected_instant_wildcard #### 단계 2 : 글로벌 와일드카드 처리 ### for i, keyword in enumerate(before_wildcard): if "<" in keyword: input_str = keyword.strip('<>').strip() if("__" in input_str): adjectives = re.findall(r'__(.*?)__', input_str) last_keyword = re.split(r'__.*?__', input_str)[-1] adjective_string = "" for adjective in adjectives: adjective_string += (self.get_wildcard(adjective) + " ") before_wildcard[i] = adjective_string + self.get_wildcard(last_keyword) else: before_wildcard[i] = self.get_wildcard(input_str) keyword_index = before_wildcard.index(keyword) start = split_strings[1] end = split_strings[2] step = split_strings[3] prompt_list.append([]) first_prompt = [] for i in range(start, end + 1, step): if i < 0: before_wildcard[keyword_index] = '[' * abs(i) + keyword + ']' * abs(i) first_prompt.append('[' * abs(i) + keyword + ']' * abs(i)) elif i == 0: before_wildcard[keyword_index] = keyword first_prompt.append(keyword) else: before_wildcard[keyword_index] = '{' * i + keyword + '}' * i first_prompt.append('{' * i + keyword + '}' * i) prompt_list[prompt_len].append(before_wildcard.copy()) prompt_len+=1 else: start = split_strings[1] end = split_strings[2] step = split_strings[3] second_prompt = [] for i in range(start, end + 1, step): if i < 0: second_prompt.append('[' * abs(i) + keyword + ']' * abs(i)) elif i == 0: second_prompt.append(keyword) else: second_prompt.append('{' * i + keyword + '}' * i) second_prompt_keyword = keyword #프롬프트 스왑 elif value == "프롬프트 스왑": xyz_list.append("프롬프트 스왑") input_string = prompts[i].get("0.0", "end-1c") split_strings = [s.strip() for s in input_string.split(',')] keyword = split_strings[0] ### 와일드카드 처리 ### if prompt_len == 0: before_wildcard = self.text_input.get("0.0", "end-1c") before_wildcard = [item.strip() for item in before_wildcard.split(',')] if '<' in self.text_input.get("0.0", "end-1c"): #### 단계 1 : 인스턴트 와일드카드 처리 ### for i, keyword in enumerate(before_wildcard): if keyword.startswith('<') and keyword.endswith('>'): vbar_check = keyword[1:-1] if '|' in vbar_check: choices = vbar_check.split('|') # '|'를 기준으로 split choice_dic = {} for choice in choices: match = re.match(r'(\d*\.?\d+):(.+)', choice) if match: value, keyword = float(match.group(1)), match.group(2).strip() else: value, keyword = 1, choice.strip() choice_dic[keyword] = value keywords = list(choice_dic.keys()) weights = list(choice_dic.values()) selected_instant_wildcard = random.choices(keywords, weights=weights, k=1)[0] before_wildcard[i] = selected_instant_wildcard #### 단계 2 : 글로벌 와일드카드 처리 ### for i, keyword in enumerate(before_wildcard): if "<" in keyword: input_str = keyword.strip('<>').strip() if("__" in input_str): adjectives = re.findall(r'__(.*?)__', input_str) last_keyword = re.split(r'__.*?__', input_str)[-1] adjective_string = "" for adjective in adjectives: adjective_string += (self.get_wildcard(adjective) + " ") before_wildcard[i] = adjective_string + self.get_wildcard(last_keyword) else: before_wildcard[i] = self.get_wildcard(input_str) keyword_index = before_wildcard.index(keyword) prompt_list.append([]) first_prompt = [] for i in split_strings: before_wildcard[keyword_index] = i first_prompt.append(i) prompt_list[prompt_len].append(before_wildcard.copy()) prompt_len+=1 else: second_prompt = [] for i in split_strings: second_prompt.append(i) second_prompt_keyword = keyword elif value == "SMEA 0/1/dyn": xyz_list.append("SMEA") smea_list = [(False, False), (True, False), (True, True)] elif value == "Samplers": xyz_list.append("Samplers") sampler_list = ["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde", "k_dpmpp_2m"] #gen_request 생성 NAI_width, NAI_height = self.resolution_button.get().split(' x ') scale_pre = self.cfg_scale_entry.get() try: scale_pre = float(scale_pre) except: scale_pre = 5.0 app.cfg_scale_var.set("5.0") rescale_pre = app.prompt_guidance_rescale_entry.get() try: rescale_pre = float(rescale_pre) except: rescale_pre = 0 app.prompt_guidance_rescale_var.set("0") uncond_pre = self.uncond_strength_entry.get() try: uncond_pre = float(uncond_pre) uncond_pre = round(uncond_pre / 0.05) * 0.05 if (uncond_pre > 1.5): uncond_pre = 1.5 self.uncond_strength_entry.delete(0, "end") self.uncond_strength_entry.insert(0, "1.5") except: uncond_pre = 1.0 self.uncond_strength_entry.delete(0, "end") self.uncond_strength_entry.insert(0, "1.0") _gen_request = { "width":NAI_width, "height":NAI_height, "quality_toggle":self.auto_quality_toggle.get(), "seed":self.seed_entry.get(), "sampler":self.sampler_button.get(), "scale":scale_pre, "uncond_scale":uncond_pre, "sema":self.sema_button.get(), "sema_dyn": self.dyn_button.get(), "cfg_rescale": rescale_pre, "prompt": self.text_input.get("0.0", "end-1c"), "negative":self.negative_prompt_input.get("0.0", "end-1c"), "user_screen_size": self.get_max_size(), "start_time": self.start_time, "access_token": self.access_token, "save_folder": self.output_file_path, "png_rule": self.name_var.get(), "type": "normal", "rating":self.current_prompt_rating } x = [] y = [] z = [] xyzs = [x, y, z] prompt_len = 0 ybar = None for i, xyz in enumerate(xyz_list): if i == 0: if xyz_list[i] == "CFG Scale": for cfg in cfg_scale_list: gen_request = _gen_request.copy() gen_request["scale"] = cfg xyzs[i].append(gen_request.copy()) xbar = [str("CFG: {:.1f}".format(x)) for x in cfg_scale_list] elif xyz_list[i] == "PG.Rescale": for pgr in pg_rescale_list: gen_request = _gen_request.copy() gen_request["cfg_rescale"] = pgr xyzs[i].append(gen_request.copy()) xbar = [str("PGR: {:.1f}".format(x)) for x in pg_rescale_list] elif xyz_list[i] == "프롬프트 강조": for prompt in prompt_list[prompt_len]: gen_request = _gen_request.copy() gen_request["prompt"] = ', '.join(prompt) xyzs[i].append(gen_request.copy()) xbar = first_prompt prompt_len+=1 elif xyz_list[i] == "프롬프트 스왑": for prompt in prompt_list[prompt_len]: gen_request = _gen_request.copy() gen_request["prompt"] = ', '.join(prompt) xyzs[i].append(gen_request.copy()) xbar = first_prompt prompt_len+=1 elif xyz_list[i] == "SMEA": for tp in smea_list: gen_request = _gen_request.copy() gen_request["sema"], gen_request["sema_dyn"] = tp xyzs[i].append(gen_request.copy()) xbar = ['None', "SMEA", "SMEA+DYN"] elif xyz_list[i] == "Samplers": for sam in sampler_list: gen_request = _gen_request.copy() gen_request["sampler"] = sam xyzs[i].append(gen_request.copy()) xbar = ["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde", "k_dpmpp_2m"] elif i == 1: if xyz_list[i] == "CFG Scale": for cfg in cfg_scale_list: _x = copy.deepcopy(x) for value in _x: value["scale"] = cfg y.append(_x) ybar = [str("CFG: {:.1f}".format(x)) for x in cfg_scale_list] elif xyz_list[i] == "PG.Rescale": for pgr in pg_rescale_list: _x = copy.deepcopy(x) for value in _x: value["cfg_rescale"] = pgr y.append(_x) ybar = [str("PGR: {:.1f}".format(x)) for x in pg_rescale_list] elif xyz_list[i] == "프롬프트 강조": if prompt_len == 0: for prompt in prompt_list[prompt_len]: _x = copy.deepcopy(x) for value in _x: value["prompt"] = prompt y.append(_x) ybar = prompt_list[prompt_len] else: for keyword in second_prompt: _x = copy.deepcopy(x) for value in _x: prompt = value["prompt"] prompt = [item.strip() for item in prompt.split(',')] idx = prompt.index(second_prompt_keyword) prompt[idx] = keyword value["prompt"] = ', '.join(prompt) y.append(_x) ybar = second_prompt elif xyz_list[i] == "프롬프트 스왑": if prompt_len == 0: for prompt in prompt_list[prompt_len]: _x = copy.deepcopy(x) for value in _x: value["prompt"] = prompt y.append(_x) ybar = prompt_list[prompt_len] else: for keyword in second_prompt: _x = copy.deepcopy(x) for value in _x: prompt = value["prompt"] prompt = [item.strip() for item in prompt.split(',')] idx = prompt.index(second_prompt_keyword) prompt[idx] = keyword value["prompt"] = ', '.join(prompt) y.append(_x) ybar = second_prompt elif xyz_list[i] == "SMEA": for tp in smea_list: _x = copy.deepcopy(x) for value in _x: value["sema"], value["sema_dyn"] = tp y.append(_x) ybar = ['None', "SMEA", "SMEA+DYN"] elif xyz_list[i] == "Samplers": for sam in sampler_list: _x = copy.deepcopy(x) for value in _x: value["sampler"] = sam y.append(_x) ybar = ["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde", "k_dpmpp_2m"] xyz_list = [] prompt_list = [] prompt_len = 0 def run_generation(xy, xbar, ybar=None): if isinstance(xy[0], list): ydim = len(xy) xdim = len(xy[0]) else: ydim = 1 xdim = len(xy) max_count = str(ydim * xdim) generation_label.configure(text = "0" +' / '+ max_count) if not ybar: ybar = " " label_font_size = 40 label_space = 500 image_width = int(NAI_width) image_height = int(NAI_height) canvas_width = label_space + image_width * xdim canvas_height = image_height * ydim + label_space final_image = Image.new("RGB", (canvas_width, canvas_height), "white") font = ImageFont.truetype("arial.ttf", label_font_size) draw = ImageDraw.Draw(final_image) draw.text( (label_space +((image_width * xdim) / 2), label_space // 3), f"seed : {self.seed_entry.get()}", fill="black", font=font, anchor="mm" ) xyz_execute_button.configure(state = "disabled") generation_stop_button.configure(state = "normal") pass_counter = 0 for yloop in range(ydim): if self.instant_stop_bit: break for xloop in range(xdim): if ydim > 1: gen_request = xy[yloop][xloop] else: gen_request = xy[xloop] app.image_generation_button.configure(border_width = 2) generation_pass = False while_counter = 0 while (not self.instant_stop_bit and not generation_pass): self.state_label.configure(text ="state : NAI 이미지 생성 대기중 ... ", text_color = "#FFFF97") if while_counter >= 15: self.instant_stop_bit = True if gen_request["png_rule"] == "count": app.generation_count += 1 gen_request["count"] =app.generation_count result_image, result_prompt, result_seed, info, filename = NAIA_generation.generate(gen_request) self.state_label.configure(text ="state : idle", text_color = "#DCE4EE") app.image_generation_button.configure(border_width = 0) if info: temp = info.get('Comment', '') temp = temp[temp.find("prompt")+10:temp.find("skip_cfg_below_sigma")-3].replace('"','') generation_pass = True pass_counter += 1 else: temp = result_prompt while_counter += 1 generation_pass = False self.running_flag = False generation_label.configure(text = str(pass_counter) +' / '+ max_count) self.image_label_report.configure(state="normal") self.image_label_report.delete("0.0", "end") self.image_label_report.configure(text_color="#DCE4EE") self.image_label_report.insert("0.0", temp) self.image_label_report.configure(state="disabled") if result_image: if app.state() != 'zoomed': instant_result_image = customtkinter.CTkImage(result_image, size=(620,620)) else: current_image = Image.open(filename) original_width, original_height = current_image.size max_size = app.winfo_screenheight()-100 if original_width > max_size or original_height > max_size: new_image = Image.new("RGB", (max_size, max_size), "black") new_image.paste(current_image, ((max_size - original_width) // 2, (max_size - original_height) // 2)) instant_result_image = customtkinter.CTkImage(new_image, size=(max_size, max_size)) else: instant_result_image = customtkinter.CTkImage(current_image, size=(max_size, max_size)) self.image_label.configure(image=instant_result_image) app.ext_set_image_to_queue(result_image, result_prompt, str(result_seed), filename) x_position = label_space + (xloop * image_width) y_position = label_space + (yloop * image_height) final_image.paste(Image.open(filename), (x_position, y_position)) draw = ImageDraw.Draw(final_image) if yloop == 0: # x축 레이블은 한 번만 추가 draw.text( (x_position + image_width / 2, label_space / 2), xbar[xloop], fill="black", font=font, anchor="mm" ) if xloop == 0: # y축 레이블은 매 행마다 추가 draw.text( (label_space // 2, y_position + image_height // 2), ybar[yloop], fill="black", font=font, anchor="mm" ) if self.instant_stop_bit: break time.sleep(2) image_path = f"xy_plot_{self.start_time}_{self.xy_plot_count}.jpg" final_image.save(image_path) os.startfile(image_path) self.xy_plot_count += 1 generation_stop_button.configure(state = "disabled") xyz_execute_button.configure(state="normal") self.instant_stop_bit = False pass_counter = 0 if y: generation_thread = threading.Thread(target=run_generation, args=(y, xbar, ybar), daemon=True) generation_thread.start() else: generation_thread = threading.Thread(target=run_generation, args=(x, xbar), daemon=True) generation_thread.start() #XYZ plot xyz_frame = customtkinter.CTkFrame(tabview.tab("X/Y plot")) xyz_frame.grid(row=1, column=0, padx=5, pady=5) xyz_label1 = customtkinter.CTkLabel(xyz_frame, text="X value : ", font=my_font) xyz_label1.grid(row=0, column=0, padx=5, pady=5) xyz_label2 = customtkinter.CTkLabel(xyz_frame, text="Y value : ", font=my_font) xyz_label2.grid(row=1, column=0, padx=5, pady=5) xyz_label3 = customtkinter.CTkLabel(xyz_frame, text="Z value : ", font=my_font) #xyz_label3.grid(row=2, column=0, padx=5, pady=5) xyz_values = ['None','CFG Scale', '프롬프트 강조', 'PG.Rescale', 'SMEA 0/1/dyn', 'Samplers', '프롬프트 스왑'] xyz_box1 = customtkinter.CTkComboBox(xyz_frame, values=xyz_values, font=my_font) xyz_box2 = customtkinter.CTkComboBox(xyz_frame, values=xyz_values, font=my_font) xyz_box3 = customtkinter.CTkComboBox(xyz_frame, values=xyz_values, font=my_font, state="disabled") xyz_box1.grid(row=0, column=1, padx=5, pady=5) xyz_box2.grid(row=1, column=1, padx=5, pady=5) #xyz_box3.grid(row=2, column=1, padx=5, pady=5) xyz_prompt1 = customtkinter.CTkTextbox(xyz_frame, width= 300, height=80, font=my_font) xyz_prompt2 = customtkinter.CTkTextbox(xyz_frame, width= 300, height=80, font=my_font) xyz_prompt3 = customtkinter.CTkTextbox(xyz_frame, width= 300, height=80, font=my_font, state="disabled") xyz_prompt1.grid(row=0, column=2, padx=5, pady=5) xyz_prompt2.grid(row=1, column=2, padx=5, pady=5) #xyz_prompt3.grid(row=2, column=2, padx=5, pady=5) xyz_execute_button = customtkinter.CTkButton(xyz_frame, text="작업 시작", font=my_font, command=xyz_excute) xyz_execute_button.grid(row=3, columnspan=3, padx=5, pady=5, sticky="n") ''' self.resolution_button2 = customtkinter.CTkComboBox(self.hidden_frame, width=160,values=["1024 x 1024", "960 x 1088", "896 x 1152", "832 x 1216", "1088 x 960", "1152 x 896", "1216 x 832"], variable=self.resolution_var, font=my_font) self.resolution_button2.grid(row=3, column=1, padx=5, sticky="w")' ''' if __name__ == "__main__": customtkinter.set_appearance_mode("dark") # ----- i2i inpaint를 위한 global 변수 ----- iimg = None img2img_window = None inpaint_mode = False # ----- 여기까지 global 변수 ----- app = App() app.load_settings() app.protocol("WM_DELETE_WINDOW", app.exit_program) app.activate_wildcards() app.get_anlas() app.after(1000, lambda: setattr(app, 'last_window_size', (app.winfo_width(), app.winfo_height()))) app.mainloop()