PoemForSmallFThings / Danbooru Prompt Selector /prompt_selector_auto_1202.py
baqu2213's picture
Upload 5 files
37e237e
raw
history blame
61.4 kB
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import filedialog
import os
import csv
import random
import time
from collections import Counter
import re
import ast
import pyautogui
import threading
from pynput import keyboard
from base64 import urlsafe_b64encode
from hashlib import blake2b
import argon2
import requests
import json
from os import environ as env
import zipfile
import io
from pathlib import Path
from datetime import datetime
import numpy as np
from PIL import Image, ImageOps, ImageFilter,ImageTk
from IPython.display import display
import win32clipboard
from io import BytesIO
from datetime import datetime
import arti_list, tagbag, wlist
from ttkthemes import ThemedTk
BASE_URL="https://api.novelai.net"
def argon_hash(email: str, password: str, size: int, domain: str) -> str:
pre_salt = f"{password[:6]}{email}{domain}"
# salt
blake = blake2b(digest_size=16)
blake.update(pre_salt.encode())
salt = blake.digest()
raw = argon2.low_level.hash_secret_raw(
password.encode(),
salt,
2,
int(2000000 / 1024),
1,
size,
argon2.low_level.Type.ID,
)
hashed = urlsafe_b64encode(raw).decode()
return hashed
def login(key) -> str:
response = requests.post(f"{BASE_URL}/user/login", json={ "key": key })
# catch any errors
return response.json()["accessToken"]
def get_access_key(email: str, password: str) -> str:
return argon_hash(email, password, 64, "novelai_data_access_key")[:64]
def get_max_size():
global window
width = window.winfo_screenheight()
return 768 if width < 1440 else 1024
def generate_image(access_token, prompt, model, action, parameters):
data = {
"input": prompt,
"model": model,
"action": action,
"parameters": parameters,
}
response = requests.post(f"{BASE_URL}/ai/generate-image", json=data, headers={ "Authorization": f"Bearer {access_token}" })
# catch any errors
return response.content
def generate(width, height, positive, negative, button):
global temp_clipboard_image
global current_sampler
global NAI_width, NAI_height
global running_flag
try:
scale = float(entry_CFG_value.get())
except:
scale = 5.0
if scale > 7.0: scale = 7.0
elif scale < 4.0: scale = 4.0
else: scale = round(scale, 1)
params = {
"legacy": False,
"quality_toggle": False,
"width": width,
"height": height,
"n_samples": 1,
"seed": random.randint(0,9999999999),
"extra_noise_seed": random.randint(0,9999999999),
"sampler": current_sampler,
"steps": 28,
"scale": scale,
"uncond_scale": 1.0,
"negative_prompt": negative_text.get("1.0", "end-1c").strip(),
"sm" : sema_button_var.get(),
"sm_dyn" : dyn_button_var.get(),
"decrisper": False,
"controlnet_strength": 1.0,
"add_original_image": False,
"cfg_rescale": 0.0,
"noise_schedule": "native",
}
def resize_and_fill(image, max_size=None):
if max_size is None:
max_size = get_max_size()
original_width, original_height = image.size
if original_width > max_size or original_height > max_size:
# ๋น„์œจ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํฌ๊ธฐ ์กฐ์ •
image.thumbnail((max_size, max_size))
# ์ƒˆ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๊ณ„์‚ฐ
width, height = image.size
new_image = Image.new("RGB", (max_size, max_size), "black")
new_image.paste(image, ((max_size - width) // 2, (max_size - height) // 2))
return new_image
else:
return image
def log_error(e, output_file_path="output_file_path"):
# ํ˜„์žฌ ์‹œ๊ฐ„์„ ์–ป์Šต๋‹ˆ๋‹ค
current_time = datetime.now().strftime("%m/%d %H:%M:%S")
# ์—๋Ÿฌ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€
error_message = f"#### Error occured at {current_time} ####\nError: {e}\n############################################\n"
# ์ง€์ •๋œ ์ถœ๋ ฅ ํด๋”์˜ error_log.txt ํŒŒ์ผ์— ์“ฐ๊ธฐ
with open(f"error_log.txt", "a") as file:
file.write(error_message)
global access_token
try:
zipped_bytes = generate_image(access_token, positive, "nai-diffusion-3", "generate", params)
d = Path("output_NAI")
d.mkdir(exist_ok=True)
zipped = zipfile.ZipFile(io.BytesIO(zipped_bytes))
image_bytes = zipped.read(zipped.infolist()[0])
(d / f"{datetime.now().strftime('%Y%m%d_%H%M%S')}.png" ).write_bytes(image_bytes)
i = Image.open(io.BytesIO(image_bytes))
i = ImageOps.exif_transpose(i).convert("RGB")
if temp_clipboard_image is not None:
temp_clipboard_image.close()
temp_clipboard_image = i
i_resized = resize_and_fill(i)
if 'tk_image' in globals():
globals()['tk_image'] = None
tk_image = ImageTk.PhotoImage(i_resized)
image_label.config(image=tk_image)
image_label.image = tk_image # ์ฐธ์กฐ ์œ ์ง€
output_file_path = "output_image.jpg"
i.save(output_file_path)
except Exception as e:
#text_output.insert(tk.END, f"Error: {e}", fg='red')
log_error(e, "path_to_output_folder")
time.sleep(random.uniform(3.0, 9.0))
button.config(state=tk.DISABLED)
window.event_generate(GENERATE_EVENT, when="tail")
time.sleep(random.uniform(1.0, 2.5))
button.config(state=tk.NORMAL)
running_flag = False
if mac_var.get() and not running_flag:
random_function()
time.sleep(random.uniform(5.1, 8.5))
button.config(state=tk.DISABLED)
window.event_generate(GENERATE_EVENT, when="tail")
def filter_csv(input_file, output_file, _search_strings):
output_directory = os.getcwd()
output_file = os.path.join(output_directory, output_file)
search_strings = [s.strip() for s in _search_strings.split(',')]
with open(input_file, 'r', newline='', encoding='utf-8') as f_in, \
open(output_file, 'w', newline='', encoding='utf-8') as f_out:
reader = csv.reader(f_in)
writer = csv.writer(f_out)
writer_count = 0
for row in reader:
if all(search_str in value for search_str in search_strings for value in row):
writer.writerow(row)
writer_count += 1
return writer_count
def open_file():
initial_dir = os.getcwd()
filepath = filedialog.askopenfilename(
initialdir=initial_dir,
filetypes=[("CSV Files", "*.csv")]
)
if filepath:
entry_file_path.delete(0, tk.END)
entry_file_path.insert(0, filepath)
def search():
global total_rows, cached_rows # cached_rows๋ฅผ global๋กœ ์„ ์–ธ
input_file = entry_file_path.get()
keywords = entry_keyword.get()
output_file = 'txt2img_temp_prompt.csv'
writer_count = filter_csv(input_file, output_file, keywords)
total_rows = writer_count
total_rows_count_label.config(text=f".csv ๋‚ด ํ”„๋กฌํ”„ํŠธ ํ–‰: {writer_count}", fg="blue")
text_output.insert(tk.END, f"์ด {writer_count}๊ฐœ์˜ ๋ฌธ์ž์—ด์ด ๊ฒ€์ƒ‰๋˜์–ด ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n")
# ๊ฒ€์ƒ‰ ํ›„ cached_rows ์ดˆ๊ธฐํ™”
cached_rows = []
def exclude():
global total_rows, cached_rows # cached_rows๋ฅผ global๋กœ ์„ ์–ธ
input_file = entry_file_path.get()
keywords = entry_keyword.get()
output_file = 'txt2img_temp_prompt.csv'
keyword_label.config(text="๊ฒ€์ƒ‰ํ•  ํ‚ค์›Œ๋“œ: ")
output_directory = os.getcwd()
output_file = os.path.join(output_directory, output_file)
search_strings = [s.strip() for s in keywords.split(',')]
with open(input_file, 'r', newline='', encoding='utf-8') as f_in, \
open(output_file, 'w', newline='', encoding='utf-8') as f_out:
reader = csv.reader(f_in)
writer = csv.writer(f_out)
writer_count = 0
for row in reader:
if not any(search_str in value for search_str in search_strings for value in row):
writer.writerow(row)
writer_count += 1
total_rows = writer_count
total_rows_count_label.config(text=f".csv ๋‚ด ํ”„๋กฌํ”„ํŠธ ํ–‰: {writer_count}", fg="red")
text_output.insert(tk.END, f"์ด {writer_count}๊ฐœ์˜ ๋ฌธ์ž์—ด์ด ๊ฒ€์ƒ‰๋˜์–ด ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n")
# ์ œ์™ธ ํ›„ cached_rows ์ดˆ๊ธฐํ™”
cached_rows = []
def copy_image_to_clipboard():
global temp_clipboard_image
image = temp_clipboard_image
output = BytesIO()
image.convert('RGB').save(output, format='BMP')
data = output.getvalue()[14:] # BMP ํŒŒ์ผ ํ—ค๋” ์ œ๊ฑฐ
output.close()
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
win32clipboard.CloseClipboard()
def reset():
cached_rows = None
entry_file_path.delete(0, tk.END)
entry_keyword.delete(0, tk.END)
entry_deep_search.delete(0, tk.END)
text_output.delete('1.0', tk.END)
def random_function():
global last_deep_search_keywords, cached_rows, last_selected_row_keywords, top_100_keywords, previous_artist, top_100_counts
current_deep_search_keywords = entry_deep_search.get().strip()
auto_hide_keywords = entry_auto_hide.get().split(',')
auto_hide_keywords = [keyword.strip() for keyword in auto_hide_keywords if keyword.strip()]
current_artist = None
curly_brackets_keywords = re.findall(r'\{([^}]+)\}', current_deep_search_keywords)
# ๊ฐ ๋ธŒ๋ž˜ํ‚ท ๋‚ด ํ‚ค์›Œ๋“œ ๊ทธ๋ฃน์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ์™„๋ฒฝ ์ผ์น˜ ํ‚ค์›Œ๋“œ์™€ ์ผ๋ฐ˜ ํ‚ค์›Œ๋“œ๋ฅผ ๊ตฌ๋ถ„
processed_keywords = []
for group in curly_brackets_keywords:
perfect_match_group = [kw[1:].strip() for kw in group.split('|') if kw.startswith('*')]
regular_group = [kw.strip() for kw in group.split('|') if not kw.startswith('*')]
processed_keywords.append((perfect_match_group, regular_group))
modified_deep_search_keywords = re.sub(r'\{[^}]+\}', '', current_deep_search_keywords)
# ๋‚จ์€ ํ‚ค์›Œ๋“œ๋“ค์„ ์‰ผํ‘œ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฒ˜๋ฆฌ
remaining_keywords = [kw.strip() for kw in modified_deep_search_keywords.split(',') if kw.strip()]
perfect_match_keywords = [kw[1:].strip() for kw in remaining_keywords if kw.startswith('*')]
# exclude_keywords์™€ include_keywords ์ •์˜
exclude_keywords = [kw[1:].strip() for kw in remaining_keywords if kw.startswith('~') and not kw[1:].startswith('*')]
include_keywords = [kw for kw in remaining_keywords if not kw.startswith('~') and not kw.startswith('*')]
if current_deep_search_keywords != last_deep_search_keywords or not cached_rows:
entry_auto_hide.delete(0, tk.END)
entry_auto_hide.insert(tk.END, 'monochrome, doujin cover, bad source, censored, bar censor, photoshop (medium)')
with open('txt2img_temp_prompt.csv', 'r', newline='', encoding='utf-8') as f:
reader = csv.reader(f)
rows = []
for row in reader:
if all(re.search(r'(?:^|, )' + re.escape(kw) + r'(?:,|$)', ', '.join(row)) for kw in perfect_match_keywords) \
and not any(exclude in cell for exclude in exclude_keywords for cell in row) \
and all(include in cell for include in include_keywords for cell in row):
# '{}' ์•ˆ์˜ ํ‚ค์›Œ๋“œ ์ฒ˜๋ฆฌ
if all(any(re.search(r'(?:^|, )' + re.escape(kw) + r'(?:,|$)', ', '.join(cell)) for kw in perfect_group) or
any(kw in cell for kw in regular_group) for perfect_group, regular_group in processed_keywords for cell in row):
rows.append(row)
cached_rows = rows
last_deep_search_keywords = current_deep_search_keywords
if not toggle_prompt_var.get(): text_output.delete('1.0', tk.END)
if random_artist_var.get():
if(not entry_fixed_prompt.get()): entry_fixed_prompt.insert(tk.END,'1girl')
if not os.path.exists("counting_result.txt"):
keyword_counts = analyze_cached_rows(cached_rows)
excluded_keywords = set(whitelist[:2974])
with open("counting_result.txt", "w") as file:
for keyword, count in sorted(keyword_counts.items(), key=lambda item: item[1], reverse=True):
if keyword not in excluded_keywords and keyword in afilter_30000:
file.write(f"{keyword}: {count}\n")
with open("counting_result.txt", "r") as file:
lines = file.readlines()
top_100_data = [
(line.split(":")[0].strip(), int(line.split(":")[1].strip()))
for line in lines[:3000]
if line.split(":")[0].strip() in afilter_30000[:8528]
]
top_100_keywords, top_100_counts = zip(*top_100_data) if top_100_data else ([], [])
elif (not top_100_keywords):
with open("counting_result.txt", "r") as file:
lines = file.readlines()
top_100_data = [
(line.split(":")[0].strip(), int(line.split(":")[1].strip()))
for line in lines[:3000]
if line.split(":")[0].strip() in afilter_30000[:8528]
]
top_100_keywords, top_100_counts = zip(*top_100_data) if top_100_data else ([], [])
formatted_artist_random_keyword = []
if top_100_keywords:
temp_keyword = []
temp_keyword += top_100_keywords
whatthefuck = random.random()
print(whatthefuck)
if(whatthefuck > 0.9):
for i in range(4):
random_keyword = random.choice(temp_keyword)
temp_keyword.remove(random_keyword)
if(i == 0): formatted_artist_random_keyword = "{{{artist:"+random_keyword+"}}}"
if(i == 1): formatted_artist_random_keyword += ",{artist:"+random_keyword+"}"
if(i == 2): formatted_artist_random_keyword += ",artist:"+random_keyword
if(i == 3): formatted_artist_random_keyword += ",[[artist:"+random_keyword+"]]"
elif(whatthefuck > 0.7):
for i in range(3):
random_keyword = random.choice(temp_keyword)
temp_keyword.remove(random_keyword)
if(i == 0): formatted_artist_random_keyword = "{{{artist:"+random_keyword+"}}}"
if(i == 1): formatted_artist_random_keyword += ",{artist:"+random_keyword+"}"
if(i == 2): formatted_artist_random_keyword += ",[[artist:"+random_keyword+"]]"
elif(whatthefuck > 0.45):
for i in range(2):
random_keyword = random.choice(temp_keyword)
temp_keyword.remove(random_keyword)
if(i == 0): formatted_artist_random_keyword = "{{{artist:"+random_keyword+"}}}"
if(i == 2): formatted_artist_random_keyword += ",[[artist:"+random_keyword+"]]"
else:
random_keyword = random.choice(temp_keyword)
temp_keyword.remove(random_keyword)
formatted_artist_random_keyword = "{{artist:"+random_keyword+"}}"
current_artist = formatted_artist_random_keyword
print(formatted_artist_random_keyword)
if not top_100_keywords: random_artist_var.set(0)
else:
formatted_artist_random_keyword = f"์ž‘๊ฐ€ ํ‚ค์›Œ๋“œ๊ฐ€ ์—†์Œ!!"
if cached_rows:
if toggle_prompt_var.get() and last_selected_row_keywords:
random_row_keywords = text_output.get("1.0", "end-1c").split(',')
#random_row_keywords[-1].strip()
if random_row_keywords[0]=='': random_row_keywords = last_selected_row_keywords
text_output.delete('1.0', tk.END)
else:
random_index = random.randint(0, len(cached_rows) - 1)
random_row = cached_rows.pop(random_index)
random_row_keywords = [keyword.strip() for keyword in random_row[0].split(',')]
last_selected_row_keywords = random_row_keywords
if(entry_fixed_prompt.get()):
entry_text_keywords = entry_fixed_prompt.get()
if(',' not in entry_text_keywords[-2:]): entry_text_keywords += ','
entry_text_keywords = entry_text_keywords.split(',')
entry_text_keywords = [kw.strip() for kw in entry_text_keywords if kw.strip()]
temp_first_keywords = []
#print("1 :", temp_first_keywords)
# entry_text_keywords์˜ ๋ชจ๋“  ํ‚ค์›Œ๋“œ๋ฅผ temp_first_keywords์— ์ถ”๊ฐ€
for et_kw in entry_text_keywords:
if ('boy' in et_kw or 'girl' in et_kw) or (' '+et_kw not in random_row_keywords and ' '+et_kw not in random_row_keywords):
temp_first_keywords.append(et_kw)
# 'boy' ํ‚ค์›Œ๋“œ ์ฒ˜๋ฆฌ
boy_keywords = [kw for kw in random_row_keywords if 'boy' in kw and len(kw) <= 7]
# 'girl' ํ‚ค์›Œ๋“œ ์ฒ˜๋ฆฌ ๋ฐ ์œ„์น˜ ์กฐ์ •
girl_keywords = []
if 'girl' in entry_text_keywords[0] and len(entry_text_keywords[0]) <= 7:
girl_keywords = [kw for kw in random_row_keywords if 'girl' in kw and len(kw) <= 7]
# random_row_keywords์—์„œ boy์™€ girl ํ‚ค์›Œ๋“œ ์ œ๊ฑฐ
for kw in boy_keywords + girl_keywords:
if kw in random_row_keywords:
random_row_keywords.remove(kw)
for kw in temp_first_keywords:
if kw in random_row_keywords:
random_row_keywords.remove(kw)
# temp_first_keywords์— boy์™€ girl ํ‚ค์›Œ๋“œ๋ฅผ ์ ์ ˆํ•œ ์œ„์น˜์— ์ถ”๊ฐ€
if(girl_keywords and 'girl' in temp_first_keywords[0]): temp_first_keywords.pop(0)
print(wildcard_var.get())
if(wildcard_var2.get() == 1):
temp_len = len(girl_keywords)
girl_keywords.append(get_random_keyword('character'))
if(wildcard_var.get() == 1):
if(wildcard_var2.get() == 1): girl_keywords.insert(temp_len+1,get_random_keyword('artist'))
else: girl_keywords.append(get_random_keyword('artist'))
temp_first_keywords = boy_keywords + girl_keywords + temp_first_keywords
#print("2 :", temp_first_keywords)
if remove_artist_var.get():
for keyword in random_row_keywords:
if keyword in afilter_30000:
random_row_keywords.remove(keyword)
temp_rm = []
if rm_characteristic_var.get():
for keyword in random_row_keywords:
if keyword in bag_of_tags or "(" in keyword:
random_row_keywords.remove(keyword)
temp_rm.append(keyword)
for keyword in random_row_keywords:
if "(" in keyword:
random_row_keywords.remove(keyword)
temp_rm.append(keyword)
print('removed : ',temp_rm)
for keyword in random_row_keywords[:]: # ๋ณต์‚ฌ๋ณธ์„ ์ˆœํšŒํ•˜์—ฌ ์›๋ณธ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆ˜์ •
if " (" in keyword:
temp_first_keywords.append(keyword)
random_row_keywords.remove(keyword)
else:
if not random_row_keywords: random_row_keywords = last_selected_row_keywords
temp_first_keywords = []
for keyword in random_row_keywords[:]: # ๋ณต์‚ฌ๋ณธ์„ ์ˆœํšŒํ•˜์—ฌ ์›๋ณธ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆ˜์ •
if " (" in keyword:
temp_first_keywords.append(keyword)
random_row_keywords.remove(keyword)
last_selected_row_keywords = random_row_keywords
#print("3 :", temp_first_keywords)
if random_artist_var.get():
temp_first_keywords.append(formatted_artist_random_keyword)
#print("4 :", temp_first_keywords)
if (previous_artist and previous_artist in temp_first_keywords): temp_first_keywords.remove(previous_artist)
if (current_artist is (not None)):
for i in range (len(current_artist)):
previous_artist += current_artist[i]
random_row_keywords = temp_first_keywords + random_row_keywords
#print("5 :", random_row_keywords)
elif toggle_prompt_var.get(): random_row_keywords = temp_first_keywords + random_row_keywords
else: random_row_keywords = temp_first_keywords + random_row_keywords
patterns = [r'\b{}\b'.format(re.escape(keyword)) for keyword in auto_hide_keywords]
for pattern in patterns:
random_row_keywords = [re.sub(pattern + '(, )?', '', keyword) for keyword in random_row_keywords]
random_row_keywords = [re.sub('(?<=, )' + pattern, '', keyword) for keyword in random_row_keywords]
if entry_fixed_prompt_after.get():
entry_after_text = entry_fixed_prompt_after.get().strip().split(',')
for at_kw in entry_after_text:
if at_kw not in random_row_keywords and ' '+at_kw not in random_row_keywords:
random_row_keywords.append(at_kw)
random_row_keywords = [keyword.strip(', ') for keyword in random_row_keywords]
random_row_keywords = [keyword for keyword in random_row_keywords if keyword]
#print(random_row_keywords)
text_output.insert(tk.END, f"{', '.join(random_row_keywords)}")
if auto_copy_var.get():
copy_to_clipboard()
else:
text_output.insert(tk.END, "๊ฒ€์ƒ‰ ์กฐ๊ฑด์— ๋งž๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๊ฑฐ๋‚˜ CSV ํŒŒ์ผ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.\n")
cached_rows_count_label.config(text=f"์‹ฌ์ธต๊ฒ€์ƒ‰ ํ”„๋กฌํ”„ํŠธ ํ–‰: {len(cached_rows)}")
def add_low_frequency_keywords():
global keyword_counts, most_common_count
keyword_counts = analyze_cached_rows(cached_rows)
if not keyword_counts: # keyword_counts๊ฐ€ ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ ํ•จ์ˆ˜๋ฅผ ๋น ์ ธ๋‚˜์˜ต๋‹ˆ๋‹ค.
return
# ๊ฐ€์žฅ ํ”ํ•œ ํ‚ค์›Œ๋“œ์˜ ๋นˆ๋„์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
most_common_count = keyword_counts.most_common(1)[0][1]
# ์กฐ๊ฑด์— ๋งž๋Š” ํ‚ค์›Œ๋“œ๋“ค์„ ์ฐพ์Šต๋‹ˆ๋‹ค.
low_freq_keywords = [keyword for keyword, count in keyword_counts.items()
if keyword not in last_deep_search_keywords and keyword not in whitelist and count / most_common_count <= 0.05]
# ์ž๋™ ์ˆจ๊น€ ํ‚ค์›Œ๋“œ ์ž…๋ ฅ์ฐฝ์— ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
existing_keywords = entry_auto_hide.get().split(',')
existing_keywords = [keyword.strip() for keyword in existing_keywords if keyword.strip()] # ๊ณต๋ฐฑ ์ œ๊ฑฐ ๋ฐ ๋นˆ ๋ฌธ์ž์—ด ์ œ๊ฑฐ
# ๊ธฐ์กด ํ‚ค์›Œ๋“œ์— ์ƒˆ๋กœ์šด ์ €๋นˆ๋„ ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
updated_keywords = existing_keywords + low_freq_keywords
unique_keywords = list(set(updated_keywords)) # ์ค‘๋ณต ์ œ๊ฑฐ
for keyword in unique_keywords:
if(keyword in afilter_30000):
unique_keywords.remove(keyword)
entry_auto_hide.delete(0, tk.END)
entry_auto_hide.insert(0, ', '.join(unique_keywords))
def copy_to_clipboard():
window.clipboard_clear()
entry_text = entry_fixed_prompt.get()
if(',' not in entry_text and entry_text): entry_text += ','
combined_text = text_output.get("1.0", tk.END)
window.clipboard_append(combined_text)
def exit_program():
window.destroy()
def save_settings():
global NAI_ID
with open('app_settings.txt', 'w', encoding='utf-8') as f: #1
if(len(entry_file_path.get()) > 4):
f.write(entry_file_path.get() + '\n')
else: f.write(" "+'\n')
if(len(entry_keyword.get()) > 3): #2
f.write(entry_keyword.get() + '\n')
else: f.write(" "+'\n')
if(len(entry_deep_search.get()) > 3): #3
f.write(entry_deep_search.get() + '\n')
else: f.write(" "+'\n')
if(len(entry_fixed_prompt.get()) > 4): #4
f.write(entry_fixed_prompt.get() + '\n')
else: f.write(" "+'\n')
if(len(entry_fixed_prompt_after.get()) > 4): #5
f.write(entry_fixed_prompt_after.get() + '\n')
else: f.write(" "+'\n')
if(len(entry_auto_hide.get()) > 3): #6
f.write(entry_auto_hide.get() + '\n')
else: f.write(" "+'\n')
if(len(negative_text.get("1.0", tk.END)) > 4): #7
f.write(negative_text.get("1.0", tk.END))
else: f.write(" "+'\n')
if(NAI_ID): f.write(NAI_ID + '\n' ) #ํ•ญ์ƒ ๋งˆ์ง€๋ง‰์— ์˜ค๋„๋ก ๊ธฐ์–ต #8
def load_settings():
NAI_ID = ""
if os.path.exists('app_settings.txt'):
with open('app_settings.txt', 'r', encoding='utf-8') as f:
settings = f.readlines()
entry_file_path.insert(0, settings[0].strip())
entry_keyword.insert(0, settings[1].strip())
entry_deep_search.insert(0, settings[2].strip())
entry_fixed_prompt.insert(0, settings[3].strip())
entry_fixed_prompt_after.insert(0, settings[4].strip())
entry_auto_hide.insert(0, settings[5].strip())
if(len(settings)>=7):
negative_text.insert(tk.END, settings[6].strip())
if(len(settings)>=8):
NAI_ID = settings[7].strip() #ํ•ญ์ƒ ๋งˆ์ง€๋ง‰์— ์˜ค๋„๋ก ๊ธฐ์–ต
return NAI_ID
def open_prompt_window():
# ์ƒˆ ์ฐฝ ์ƒ์„ฑ
prompt_window = tk.Toplevel(window)
prompt_title = f"{entry_keyword.get()}+{last_deep_search_keywords}" if last_deep_search_keywords else "์ถ”์ฒœ ํ”„๋กฌํ”„ํŠธ"
prompt_window.title(prompt_title)
# ์ฒซ ๋ฒˆ์งธ Text Output Box ์„ค์ •
text_output1 = tk.Text(prompt_window, height=10, width=50)
text_output1.pack(padx=10, pady=10)
# ๊ตต์€ ๊ธ€์”จ ์Šคํƒ€์ผ ํƒœ๊ทธ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
text_output1.tag_configure('bold', font=('Arial', 10, 'bold'))
# ๋‘ ๋ฒˆ์งธ Text Output Box ์„ค์ •
text_output2 = tk.Text(prompt_window, height=10, width=50)
text_output2.pack(padx=10, pady=10)
# ์„ธ ๋ฒˆ์งธ Text Output Box ์„ค์ •
text_output3 = tk.Text(prompt_window, height=10, width=50)
text_output3.pack(padx=10, pady=10)
# cached_rows ๋ถ„์„
keyword_counts = analyze_cached_rows(cached_rows)
# ๊ฐ€์žฅ ๋†’์€ count ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
most_common_count = keyword_counts.most_common(1)[0][1] if keyword_counts else 0
# text_output1์— ๊ฐ€์žฅ ํ”ํ•œ ํ‚ค์›Œ๋“œ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ , ์กฐ๊ฑด์— ๋”ฐ๋ผ ๊ตต๊ฒŒ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
for keyword, count in keyword_counts.most_common(50):
if count / most_common_count >= 0.5: # count๊ฐ€ ๊ฐ€์žฅ ๋†’์€ ํ‚ค์›Œ๋“œ ๋Œ€๋น„ 60% ์ด์ƒ์ธ ๊ฒฝ์šฐ
text_output1.insert(tk.END, f"{keyword}, ", 'bold')
else:
text_output1.insert(tk.END, f"{keyword}, ")
# text_output2์— ๋ชจ๋“  ํ‚ค์›Œ๋“œ์™€ ๋นˆ๋„์ˆ˜ ์ถœ๋ ฅ
for keyword, count in keyword_counts.most_common(200):
text_output2.insert(tk.END, f"{keyword}: {count}, ")
excluded_keywords = set(whitelist[:2974])
artist_count = 0
with open("counting_result.txt", "w") as file:
for keyword, count in sorted(keyword_counts.items(), key=lambda item: item[1], reverse=True):
if keyword not in excluded_keywords and keyword in afilter_30000:
file.write(f"{keyword}: {count}\n")
if(artist_count < 150):
text_output3.insert(tk.END, f"{keyword}: {count}, ")
artist_count += 1
# ๋‹ซ๊ธฐ ๋ฒ„ํŠผ ์„ค์ •
close_button = tk.Button(prompt_window, text="๋‹ซ๊ธฐ", command=prompt_window.destroy)
close_button.pack(pady=10)
def analyze_cached_rows(cached_rows):
global top_100_keywords
top_100_keywords = []
counts = Counter()
for row in cached_rows:
substrings = [substring.strip() for value in row for substring in value.split(',') if substring.strip()]
counts.update(substrings)
return counts
def exit_program():
save_settings()
window.destroy()
def on_ctrl_enter(event):
random_function()
def on_shift_enter(event):
random_function()
copy_to_clipboard()
def export_csv():
source_file = os.path.join(os.getcwd(), 'txt2img_temp_prompt.csv')
if not os.path.exists(source_file):
print("์†Œ์Šค ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
return
# ๊ธฐ๋ณธ ํŒŒ์ผ ์ด๋ฆ„์„ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ๋กœ ์„ค์ •
default_filename = f"{entry_keyword.get()}.csv" if entry_keyword.get() else "exported.csv"
file_types = [('CSV ํŒŒ์ผ', '*.csv')]
dest_file = filedialog.asksaveasfilename(defaultextension='.csv', filetypes=file_types, initialfile=default_filename)
if dest_file: # ์‚ฌ์šฉ์ž๊ฐ€ ํŒŒ์ผ ์ด๋ฆ„์„ ์„ ํƒํ–ˆ์„ ๊ฒฝ์šฐ
import shutil
shutil.copy(source_file, dest_file)
print(f"ํŒŒ์ผ์ด ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค: {dest_file}")
def export_csv_search():
if not cached_rows:
print("๋น„์–ด์žˆ๋Š” ํ”„๋กฌํ”„ํŠธํ–‰.")
return
# ๊ธฐ๋ณธ ํŒŒ์ผ ์ด๋ฆ„์„ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ๋กœ ์„ค์ •
default_filename = f"{entry_keyword.get()}.csv" if entry_keyword.get() else "exported.csv"
file_types = [('CSV ํŒŒ์ผ', '*.csv')]
dest_file = filedialog.asksaveasfilename(defaultextension='.csv', filetypes=file_types, initialfile=default_filename)
if dest_file: # ์‚ฌ์šฉ์ž๊ฐ€ ํŒŒ์ผ ์œ„์น˜๋ฅผ ์„ ํƒํ–ˆ๋‹ค๋ฉด
with open(dest_file, 'w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
for row in cached_rows:
writer.writerow(row) # ๊ฐ ํ–‰์„ csv ํŒŒ์ผ์— ์“ด๋‹ค
def simulate_shortcuts():
global listener, on_press_flag
on_press_flag = True
random_function()
on_press_flag = False
try:
current_keys.clear()
current_keys.add(keyboard.Key.ctrl_l)
except KeyError:
pass
def on_activate_simulate_shortcuts():
simulate_shortcuts()
def for_canonical(f):
return lambda k: f(listener.canonical(k))
def start_keyboard_listener():
global listener
listener = keyboard.Listener(on_press=on_press, on_release=on_release)
listener.start()
def on_press(key):
global on_press_flag
current_keys.add(key)
# Ctrl + ` ์กฐํ•ฉ ๊ฐ์ง€
if keyboard.Key.ctrl_l in current_keys:
if any(k.vk == 192 for k in current_keys if hasattr(k, 'vk')):
on_press_flag = True
simulate_shortcuts()
def on_release(key):
try:
current_keys.remove(key)
except KeyError:
pass
def v_automatic(save_position, prompt_position):
# ํ”„๋กฌํ”„ํŠธ ์ฐฝ ํด๋ฆญ
copy_to_clipboard()
pyautogui.click(prompt_position)
time.sleep(0.5)
random_function()
pyautogui.hotkey('ctrl', 'a', 'v','Right','Right','Enter')
time.sleep(0.5)
pyautogui.click(save_position)
def start_automation(save_position, prompt_position, label, window_to_close, automation_event):
def automation_task():
while automation_event.is_set():
random_delay = random.uniform(17.5, 23.5)
next_click_time = time.time() + random_delay
while time.time() < next_click_time and automation_event.is_set():
time_remaining = max(next_click_time - time.time(), 0)
label.config(text=f"๋‹ค์Œ ํด๋ฆญ๊นŒ์ง€: {time_remaining:.2f}์ดˆ")
time.sleep(0.1)
if automation_event.is_set():
v_automatic(save_position, prompt_position)
automation_thread = threading.Thread(target=automation_task, daemon=True)
automation_thread.start()
random_function()
def stop_automation():
automation_event.clear()
window_to_close.destroy()
window_to_close.protocol("WM_DELETE_WINDOW", stop_automation)
def stop_automation(window_to_close, automation_event, start_button, stop_button):
automation_event.clear() # Stop the automation task
start_button['state'] = 'normal' # Enable the start button
stop_button['state'] = 'disabled' # Disable the stop button
window_to_close.destroy() # Close the automation window
window.deiconify()
# ๋ผ๋ฒจ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ํ•จ์ˆ˜
def update_label(label, text):
def task():
label.config(text=text)
label.after(1000, task) # ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ UI ์—…๋ฐ์ดํŠธ
def open_automation_window():
window.iconify()
automation_event = threading.Event()
automation_event.set() # Enable the automation event
auto_window = tk.Toplevel(window)
auto_window.title("์ž๋™ํ™” ์„ค์ •")
auto_window.geometry("300x200") # ์ฐฝ ํฌ๊ธฐ ์กฐ์ •
auto_window.attributes('-topmost', True) # ์ฐฝ์„ ํ•ญ์ƒ ๋งจ ์œ„์— ์œ„์น˜
auto_window.focus_force() # ์ฐฝ ์—ด๋ฆด ๋•Œ ํฌ์ปค์Šค ๊ฐ•์ œ ์ด๋™
save_position = None
prompt_position = None
automation_running = threading.Event()
def get_mouse_position(event=None):
nonlocal save_position, prompt_position
x, y = pyautogui.position()
if not save_position:
save_position = (x, y)
position_label.config(text=f"์ €์žฅ ๋ฒ„ํŠผ์˜ ์ขŒํ‘œ: {x}, {y}\nํ”„๋กฌํ”„ํŠธ ์ฐฝ์˜ ์ขŒํ‘œ: ")
elif not prompt_position:
prompt_position = (x, y)
position_label.config(text=f"์ €์žฅ ๋ฒ„ํŠผ์˜ ์ขŒํ‘œ: {save_position[0]}, {save_position[1]}\nํ”„๋กฌํ”„ํŠธ ์ฐฝ์˜ ์ขŒํ‘œ: {x}, {y}")
start_button.config(state="normal")
if save_position and prompt_position:
start_button.config(state="normal")
stop_button.config(state="normal")
position_label = tk.Label(auto_window, text="์—”ํ„ฐ๋ฅผ ๋ˆŒ๋Ÿฌ ๋งˆ์šฐ์Šค ์ขŒํ‘œ๋ฅผ ์ €์žฅํ•˜์„ธ์š”\n(ํด๋ฆญ X, 1.์ €์žฅ->2.ํ”„๋กฌํ”„ํŠธ์ฐฝ ์ˆœ์„œ)", justify=tk.LEFT)
position_label.pack(pady=10)
start_button = tk.Button(auto_window, text="์‹œ์ž‘", state="disabled",
command=lambda: start_automation(save_position, prompt_position, countdown_label, auto_window, automation_event))
start_button.pack(side=tk.LEFT, fill='x', expand=True)
stop_button = tk.Button(auto_window, text="์ค‘์ง€", state="disabled",
command=lambda: stop_automation(auto_window, automation_event, start_button, stop_button))
stop_button.pack(side=tk.RIGHT, fill='x', expand=True)
countdown_label = tk.Label(auto_window, text="")
countdown_label.pack(pady=10)
auto_window.bind('<Return>', get_mouse_position)
def NAI_generation(width, height, button):
button.config(state=tk.DISABLED)
positive = text_output.get("1.0", tk.END)
negative = negative_text.get("1.0", "end-1c").strip()
thread = threading.Thread(target=generate, args=(width, height, positive, negative, button))
thread.start()
def NAI_setting(button, button_generate):
global NAI_ID
NAI_setting_window = tk.Toplevel(window)
NAI_setting_window_title = "NAI ๋กœ๊ทธ์ธ"
def NAI_close():
NAI_setting_window.destroy()
NAI_ID_label = tk.Label(NAI_setting_window, text="NAI ID: ")
NAI_ID_label.grid(row=0, column=0, columnspan=2, sticky='w')
entry_NAI_ID = tk.Entry(NAI_setting_window, width=50)
entry_NAI_ID.grid(row=0, column=1, columnspan=2, padx=100, pady=5, sticky='e')
if(NAI_ID): entry_NAI_ID.insert(tk.END,NAI_ID)
NAI_PW_label = tk.Label(NAI_setting_window, text="NAI PW: ")
NAI_PW_label.grid(row=1, column=0, columnspan=2, sticky='w')
entry_NAI_PW = tk.Entry(NAI_setting_window, width=50, show="*")
entry_NAI_PW.grid(row=1, column=1, columnspan=2, padx=100, pady=5, sticky='e')
def NAI_connect(button, connect_button):
global access_token, NAI_ID
username = entry_NAI_ID.get().strip()
password = entry_NAI_PW.get().strip()
access_key = get_access_key(username, password)
try:
access_token = login(access_key)
access_result = requests.get("https://api.novelai.net/user/information", headers={ "Authorization": f"Bearer {access_token}" })
NAI_State_label.config(text="(๋กœ๊ทธ์ธ ์„ฑ๊ณต, ๋‹ซ๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š”.)", fg="blue")
button.config(state=tk.DISABLED)
button_generate.config(state="normal")
connect_button.config(state=tk.DISABLED)
NAI_ID = username
except Exception as e:
print(e)
NAI_close()
connect_button = tk.Button(NAI_setting_window, text="์—ฐ๊ฒฐ", command=lambda: NAI_connect(button, connect_button))
connect_button.grid(row=2, column=1, columnspan=2, padx=5, pady=5, sticky='w')
close_button = tk.Button(NAI_setting_window, text="๋‹ซ๊ธฐ", command=NAI_close)
close_button.grid(row=2, column=2, columnspan=2, padx=5, pady=5, sticky='w')
NAI_State_label = tk.Label(NAI_setting_window, text="ํ•ด๋‹น ์ ‘์†๊ธฐ๋Šฅ์€ ์ •์ƒ์ ์ธ ์ ‘์† ํŒจํ„ด์ด ์•„๋‹Œ์  ์ฐธ๊ณ  ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.", fg="red")
NAI_State_label.grid(row=3, column=1, sticky='ew')
def on_resolution_change(*args):
global NAI_width, NAI_height
resolution = selected_resolution.get()
NAI_width, NAI_height = resolution.split(' x ')
def on_option_select(value):
global current_sampler
current_sampler = value
def open_file_explorer():
output_file_path = "output_NAI"
if os.path.exists(output_file_path):
os.startfile(output_file_path)
def on_generate_event(event):
global running_flag
if not (running_flag):
NAI_generation(NAI_width, NAI_height, button_generate)
running_flag = True
def random_artist_management():
global top_100_keywords, top_100_counts, cached_rows
if not cached_rows: return
if not (top_100_keywords):
if not os.path.exists("counting_result.txt"):
keyword_counts = analyze_cached_rows(cached_rows)
excluded_keywords = set(whitelist[:2974])
with open("counting_result.txt", "w") as file:
for keyword, count in sorted(keyword_counts.items(), key=lambda item: item[1], reverse=True):
if keyword not in excluded_keywords and keyword in afilter_30000:
file.write(f"{keyword}: {count}\n")
with open("counting_result.txt", "r") as file:
lines = file.readlines()
top_100_data = [
(line.split(":")[0].strip(), int(line.split(":")[1].strip()))
for line in lines[:3000]
if line.split(":")[0].strip() in afilter_30000[:8528]
]
top_100_keywords, top_100_counts = zip(*top_100_data) if top_100_data else ([], [])
elif (not top_100_keywords):
with open("counting_result.txt", "r") as file:
lines = file.readlines()
top_100_data = [
(line.split(":")[0].strip(), int(line.split(":")[1].strip()))
for line in lines[:3000]
if line.split(":")[0].strip() in afilter_30000[:8528]
]
top_100_keywords, top_100_counts = zip(*top_100_data) if top_100_data else ([], [])
# top_100_keywords ๋‚ด์˜
# ์ƒˆ ์ฐฝ ์ƒ์„ฑ
random_artist_window = tk.Toplevel(window)
# ์ฒซ ๋ฒˆ์งธ Text Output Box ์„ค์ •
text_output1 = tk.Text(random_artist_window, height=40, width=50)
text_output1.pack(padx=10, pady=10)
for keyword, count in zip(top_100_keywords, top_100_counts):
text_output1.insert(tk.END, f"{keyword}: {count}\n")
def update_lists():
# Text ์œ„์ ฏ์—์„œ ๋‚ด์šฉ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
content = text_output1.get("1.0", tk.END)
lines = content.strip().split("\n") # ์ค„๋ฐ”๊ฟˆ์œผ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
# ๊ฐฑ์‹ ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋‘ ๊ฐœ์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
updated_keywords = []
updated_counts = []
# ๊ฐ ์ค„์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋ฆฌ์ŠคํŠธ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
for line in lines:
if line: # ๋นˆ ์ค„์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
parts = line.split(":")
if len(parts) == 2: # "ํ‚ค์›Œ๋“œ: ์นด์šดํŠธ" ํ˜•์‹์ด ๋งž๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
updated_keywords.append(parts[0].strip())
updated_counts.append(int(parts[1].strip()))
# ์ „์—ญ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.
global top_100_keywords, top_100_counts
top_100_keywords = updated_keywords
top_100_counts = updated_counts
with open("random_artist_keywords_"+str(len(top_100_keywords))+".txt", "w") as f:
for keyword in updated_keywords:
f.write('100: artist:'+keyword + "\n")
# ๋ฒ„ํŠผ๋“ค์„ ๋‹ด์„ ํ”„๋ ˆ์ž„ ์ƒ์„ฑ
buttons_frame = tk.Frame(random_artist_window)
buttons_frame.pack(pady=10)
# '์ €์žฅ' ๋ฒ„ํŠผ์„ ํ”„๋ ˆ์ž„์˜ ์™ผ์ชฝ์— ๋ฐฐ์น˜
save_button = tk.Button(buttons_frame, text="์ €์žฅ", command=update_lists)
save_button.pack(side=tk.LEFT, padx=5)
# '๋‹ซ๊ธฐ' ๋ฒ„ํŠผ์„ ํ”„๋ ˆ์ž„์˜ ์˜ค๋ฅธ์ชฝ์— ๋ฐฐ์น˜
close_button = tk.Button(buttons_frame, text="๋‹ซ๊ธฐ", command=random_artist_window.destroy)
close_button.pack(side=tk.RIGHT, padx=5)
random_artist_label = tk.Label(random_artist_window, text='์ž‘๊ฐ€์ด๋ฆ„ ์ด '+str(len(top_100_keywords))+'๊ฐœ, ์ €์žฅ์œ„์น˜: exeํŒŒ์ผ ์œ„์น˜')
random_artist_label.pack()
def open_wildcard_setting():
# ์ƒˆ ์ฐฝ ์ƒ์„ฑ
wildcard_window = tk.Toplevel(window)
wildcard_window.title("์™€์ผ๋“œ ์นด๋“œ ์„ค์ •")
# ์ž‘๊ฐ€๋ช… ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
artist_label = tk.Label(wildcard_window, text="์ž‘๊ฐ€๋ช… ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ->")
artist_label.grid(row=0, column=0)
artist_button = tk.Button(wildcard_window, text="์—ด๊ธฐ", command=lambda: load_wildcard(artist_text, wildcard_window))
artist_button.grid(row=0, column=1)
artist_text = tk.Text(wildcard_window, height=15, width=60)
artist_text.grid(row=1, column=0, columnspan=2)
# ์บ๋ฆญํ„ฐ ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
character_label = tk.Label(wildcard_window, text="์บ๋ฆญํ„ฐ ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ->")
character_label.grid(row=2, column=0)
character_button = tk.Button(wildcard_window, text="์—ด๊ธฐ", command=lambda: load_wildcard(character_text, wildcard_window))
character_button.grid(row=2, column=1)
character_text = tk.Text(wildcard_window, height=15, width=60)
character_text.grid(row=3, column=0, columnspan=2)
# ๋ฒ„ํŠผ๋“ค
buttons_frame = tk.Frame(wildcard_window)
buttons_frame.grid(row=4, column=0, columnspan=2)
text_label = tk.Label(wildcard_window, text="wildcard ๋ฌธ๋ฒ•(์ž‘๊ฐ€):\noffset:wildcard1 150:null (helloworld)\noffset:wildcard2 100:none (goodbye)\n์—†์œผ๋ฉด 100: ์œผ๋กœ ๊ฐ„์ฃผ\noffset/offset ์ดํ•ฉ: wildcard ํ™•๋ฅ ")
text_label.grid(row=5, column=0,sticky='ew')
text_label2 = tk.Label(wildcard_window, text="wildcard ๋ฌธ๋ฒ•(์บ๋ฆญ):\n200:{{arona (blue archive)}}, blue hair, blue eyes, hair over one eye, ...\n150:{{nahida (genshin impact)}}, green eyes, pointy ears, ...\n...")
text_label2.grid(row=6, column=0,sticky='ew')
load_button = tk.Button(buttons_frame, text="์™€์ผ๋“œ์นด๋“œ ํƒ‘์žฌ", command=lambda: apply_wildcard(artist_text, character_text, wildcard_window))
load_button.pack(side=tk.LEFT, padx=10)
close_button = tk.Button(buttons_frame, text="๋‹ซ๊ธฐ", command=wildcard_window.destroy)
close_button.pack(side=tk.RIGHT, padx=10)
def apply_wildcard(artist_text, character_text, window):
artist_wildcard_check = artist_text.get("1.0", tk.END)
if len(artist_wildcard_check) > 5:
lines = artist_wildcard_check.strip().split("\n")
akeywords = []
current_index = 0
for line in lines:
parts = line.strip().split(':', 1)
if len(parts) == 2 and parts[0].strip().isdigit():
weight = int(parts[0].strip())
else:
weight = 100
parts = ['100', line.strip()] # '100:'์„ ์•ž์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
keyword = parts[1].strip()
akeywords.append((current_index, current_index + weight - 1, keyword))
current_index += weight
global artist_wildcard
artist_wildcard = akeywords
check_wildcard.config(state='normal')
character_wildcard_check = character_text.get("1.0", tk.END)
if len(character_wildcard_check) > 5:
lines = character_wildcard_check.strip().split("\n")
ckeywords = []
current_index = 0
for line in lines:
parts = line.strip().split(':', 1)
if len(parts) == 2 and parts[0].strip().isdigit():
weight = int(parts[0].strip())
else:
weight = 100
parts = ['100', line.strip()] # '100:'์„ ์•ž์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
keyword = parts[1].strip()
ckeywords.append((current_index, current_index + weight - 1, keyword))
current_index += weight
global character_wildcard
character_wildcard = ckeywords
check_wildcard2.config(state='normal')
window.destroy()
def load_wildcard(text_widget, window):
window.iconify()
filepath = filedialog.askopenfilename(filetypes=[("ํ…์ŠคํŠธ ํŒŒ์ผ", "*.txt")])
if filepath:
with open(filepath, 'r', encoding='utf-8') as file:
lines = file.readlines()
updated_lines = []
for line in lines:
line = line.strip()
if ':' in line:
prefix, _ = line.split(':', 1)
if not prefix.strip().isdigit():
line = f"100: {line}"
else:
line = f"100: {line}"
updated_lines.append(line)
text_widget.delete('1.0', tk.END)
text_widget.insert('1.0', '\n'.join(updated_lines))
window.deiconify()
def find_keyword(index, keywords):
for start, end, keyword in keywords:
if start <= index <= end:
print(keyword)
return keyword
return None
def get_random_keyword(req_keyword):
#called from artist_wildcard, character_wildcard
global artist_wildcard, character_wildcard
if(req_keyword == 'artist'): keywords = artist_wildcard
elif(req_keyword == 'character'): keywords = character_wildcard
print('lenghth = ',len(keywords))
max_index = keywords[-1][1]
print(len(keywords))
random_index = random.randint(0, max_index)
print(random_index)
return find_keyword(random_index, keywords)
on_press_flag = False
window = tk.Tk()
window.title("Prompt Selector for Danbooru tags")
last_deep_search_keywords = None
cached_rows = []
total_rows = 0
last_selected_row_keywords = ['1girl','nahida (genshin impact)', 'looking at viewer', 'garden']
top_100_keywords = []
top_100_counts = []
previous_artist = None
listener = None
current_keys = set()
click_count = 0
access_token = None
temp_clipboard_image = None
NAI_width = 1024
NAI_height = 1024
current_sampler = "k_euler_ancestral"
running_flag = False
NAI_ID = None
artist_wildcard = []
character_wildcard =[]
whitelist = wlist.whitelist
bag_of_tags = tagbag.bag_of_tags
afilter_30000 = arti_list.afilter_30000
current_wildcard_artist = []
current_wildcard_character = []
GENERATE_EVENT = "<<GenerateEvent>>"
window.bind(GENERATE_EVENT, on_generate_event)
left_frame = tk.Frame(window)
left_frame.grid(row=0, column=0, sticky="nsew")
#left_frame.grid_columnconfigure(0, weight=1)
right_frame = tk.Frame(window)
right_frame.grid(row=0, column=1, sticky="nsew")
window.grid_columnconfigure(0, weight=1)
window.grid_columnconfigure(1, weight=1)
#ํŒŒ์ผ ๊ฒฝ๋กœ ๋ฐ ํ‚ค์›Œ๋“œ ์ž…๋ ฅ์ฐฝ ๊ทธ๋ฆฌ๋“œ ๊ด€๋ฆฌ
frame_row0 = tk.Frame(left_frame)
frame_row0.grid(row=0, column=0, padx=5, pady=5, sticky='w')
# ํŒŒ์ผ ๊ฒฝ๋กœ ์ž…๋ ฅ์ฐฝ
label_file_path = tk.Label(frame_row0, text="CSV ํŒŒ์ผ ๊ฒฝ๋กœ:")
label_file_path.grid(row=0, column=0, sticky='w')
entry_file_path = tk.Entry(frame_row0, width=55)
entry_file_path.grid(row=0, column=1, columnspan=4, padx=5, pady=5, sticky='ew')
button_open_file = tk.Button(frame_row0, text="ํŒŒ์ผ ์—ด๊ธฐ", command=open_file)
button_open_file.grid(row=0, column=5, padx=5, pady=6, sticky='e')
# ํ‚ค์›Œ๋“œ ์ž…๋ ฅ์ฐฝ
keyword_label = tk.Label(frame_row0, text="์ดˆ๊ธฐํ™” ํ‚ค์›Œ๋“œ: ")
keyword_label.grid(row=1, column=0, sticky='w')
entry_keyword = tk.Entry(frame_row0)
entry_keyword.grid(row=1, column=1, columnspan=4, padx=5, pady=5, sticky='ew')
button_export_csv = tk.Button(frame_row0, text=".csv ๋‚ด๋ณด๋‚ด๊ธฐ", command=export_csv)
button_export_csv.grid(row=1, column=5, padx=5, pady=6, sticky='e')
# ๋ฒ„ํŠผ ํ”„๋ ˆ์ž„
frame_buttons = tk.Frame(left_frame)
frame_buttons.grid(row=1, column=0, sticky='ew')
frame_buttons.columnconfigure(0, weight=1) # ์™ผ์ชฝ์— ๊ฐ€์ค‘์น˜ ๋ถ€์—ฌ
frame_buttons.columnconfigure(1, weight=0) # ๋ฒ„ํŠผ ์—ด์€ ๊ฐ€์ค‘์น˜ ์—†์Œ
frame_buttons.columnconfigure(2, weight=0) # ๋ฒ„ํŠผ ์—ด์€ ๊ฐ€์ค‘์น˜ ์—†์Œ
frame_buttons.columnconfigure(3, weight=1) # ์˜ค๋ฅธ์ชฝ์— ๊ฐ€์ค‘์น˜ ๋ถ€์—ฌ
# ๋ฒ„ํŠผ๋“ค
button_search = tk.Button(frame_buttons, text="ํ•ด๋‹น ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰", command=search)
button_search.grid(row=0, column=1, padx=5, sticky='ew') # ๋ณ€๊ฒฝ: column=1
button_exclude = tk.Button(frame_buttons, text="ํ•ด๋‹น ํ‚ค์›Œ๋“œ ์ œ์™ธ", command=exclude)
button_exclude.grid(row=0, column=2, padx=5, sticky='ew') # ๋ณ€๊ฒฝ: column=2
total_rows_count_label = tk.Label(frame_buttons, text=".csv ๋‚ด ํ”„๋กฌํ”„ํŠธ ํ–‰: 0")
total_rows_count_label.grid(row=0, column=3, padx=5, sticky='ew')
# ์‹ฌ์ธต๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ ์ž…๋ ฅ์ฐฝ
deep_search_frame = tk.Frame(left_frame)
deep_search_frame.grid(row=2, column=0, pady=10, sticky='w')
deep_search_frame.columnconfigure(0, weight=2)
deep_search_frame.columnconfigure(1, weight=2)
deep_search_frame.columnconfigure(2, weight=1)
label_deep_search = tk.Label(deep_search_frame, text="์‹ฌ์ธต๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ ์ž…๋ ฅ: key,*key,~key,{key1|key2} ")
label_deep_search.grid(row=0, column=0, sticky='w')
# Tkinter UI ์„ค์ • ๋ถ€๋ถ„์— ๋ ˆ์ด๋ธ” ์ถ”๊ฐ€
cached_rows_count_label = tk.Label(deep_search_frame, text="์‹ฌ์ธต๊ฒ€์ƒ‰ ํ”„๋กฌํ”„ํŠธ ํ–‰: 0")
cached_rows_count_label.grid(row=0, column=1, padx=5, sticky='w')
button_export_deep_csv = tk.Button(deep_search_frame, text=".csv ๋‚ด๋ณด๋‚ด๊ธฐ", command=export_csv_search)
button_export_deep_csv.grid(row=0, column=2, padx=5, sticky='e')
entry_deep_search = tk.Entry(deep_search_frame, width=82)
entry_deep_search.grid(row=1, column=0, columnspan=3,padx=5, pady=5, sticky='ew')
# ๋ฒ„ํŠผ๋“ค์„ ํฌํ•จํ•  ํ”„๋ ˆ์ž„ ์ƒ์„ฑ
button_frame = tk.Frame(left_frame)
button_frame.grid(row=5, column=0, padx=5, pady=5, sticky='w')
# ๋ฒ„ํŠผ ํ”„๋ ˆ์ž„ ๋‚ด์˜ ์—ด ์„ค์ •
button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
button_frame.columnconfigure(2, weight=1)
button_frame.columnconfigure(3, weight=1)
button_frame.columnconfigure(4, weight=1)
button_frame.columnconfigure(5, weight=1)
button_frame.columnconfigure(6, weight=1)
# "๋žœ๋ค" ๋ฒ„ํŠผ
button_random = tk.Button(button_frame, text="๋žœ๋ค", command=random_function)
button_random.grid(row=0, column=0, sticky='ew')
# "ํ”„๋กฌํ”„ํŠธ ๊ณ ์ •" ํ† ๊ธ€ ๋ฒ„ํŠผ
toggle_prompt_var = tk.IntVar()
button_toggle_prompt = tk.Checkbutton(button_frame, text="ํ”„๋กฌํ”„ํŠธ ๊ณ ์ •", variable=toggle_prompt_var)
button_toggle_prompt.grid(row=0, column=1, sticky='ew')
# "์ž๋™ ๋ณต์‚ฌ" ์ฒดํฌ๋ฐ•์Šค
auto_copy_var = tk.IntVar()
check_auto_copy = tk.Checkbutton(button_frame, text="์ž๋™ ๋ณต์‚ฌ", variable=auto_copy_var)
check_auto_copy.grid(row=0, column=2, sticky='ew')
# "๋ณต์‚ฌ" ๋ฒ„ํŠผ
button_copy = tk.Button(button_frame, text="๋ณต์‚ฌ", command=copy_to_clipboard)
button_copy.grid(row=0, column=3, sticky='ew')
# "์ข…๋ฃŒ" ๋ฒ„ํŠผ
button_exit = tk.Button(button_frame, text="์ข…๋ฃŒ", command=exit_program)
button_exit.grid(row=0, column=4, sticky='ew')
# "์ƒ์„ฑ" ๋ฒ„ํŠผ
button_generate = tk.Button(button_frame, text="NAI ์š”์ฒญ", command=lambda: NAI_generation(NAI_width, NAI_height, button_generate))
button_generate.grid(row=0, column=5, sticky='ew')
button_generate.config(state='disabled')
# "์„ค์ •" ๋ฒ„ํŠผ
button_setting = tk.Button(button_frame, text="NAI ๋กœ๊ทธ์ธ ์„ค์ •", command=lambda: NAI_setting(button_setting, button_generate))
button_setting.grid(row=0, column=6, sticky='ew')
mac_var = tk.IntVar()
mac_button = tk.Checkbutton(button_frame, text="์ž๋™์ƒ์„ฑ", variable=mac_var)
mac_button.grid(row=0, column=7, sticky='ew')
# ํ…์ŠคํŠธ ๋ฐ ๊ณ ์ • ํ”„๋กฌํ”„ํŠธ ๋„ค๊ฑฐํ‹ฐ๋ธŒ ๋“ฑ ํ”„๋กฌํ”„ํŠธ ์ฐฝ
text_frame = tk.Frame(left_frame)
text_frame.grid(row=6, column=0, padx=5, pady=5, sticky='w')
text_frame.columnconfigure(0, weight=1)
text_frame.columnconfigure(1, weight=7)
text_frame2 = tk.Frame(left_frame)
text_frame2.grid(row=8, column=0, padx=5, pady=5, sticky='w')
text_frame2.columnconfigure(0, weight=1)
text_frame2.columnconfigure(1, weight=7)
_size = get_max_size()
# ์ถœ๋ ฅ ํ…์ŠคํŠธ ์ฐฝ
text_output_label = tk.Label(text_frame, text="ํ”„๋กฌํ”„ํŠธ", borderwidth=1, relief="solid",height=6)
text_output_label.grid(row=0, column=0, padx=5, pady=5, sticky='w')
if _size<=768: text_output_width = 74
else: text_output_width = 65
text_output = tk.Text(text_frame, width=text_output_width, height=7)
text_output.grid(row=0, column=1, sticky='ew')
fixed_prompt_frame = tk.Frame(left_frame)
fixed_prompt_frame.grid(row=7, column=0, padx=5, pady=5, sticky='w')
fixed_prompt_frame.columnconfigure(0, weight=1)
fixed_prompt_frame.columnconfigure(1, weight=1)
fixed_prompt_label_left = tk.Label(fixed_prompt_frame, text="์„ ํ–‰ ๊ณ ์ • ํ”„๋กฌํ”„ํŠธ (ํ”„๋กฌํ”„ํŠธ ์•ž)")
fixed_prompt_label_left.grid(row=0, column=0, sticky='ew')
fixed_prompt_label_right = tk.Label(fixed_prompt_frame, text="ํ›„ํ–‰ ๊ณ ์ • ํ”„๋กฌํ”„ํŠธ (ํ”„๋กฌํ”„ํŠธ ๋’ค)")
fixed_prompt_label_right.grid(row=0, column=1, sticky='ew')
entry_fixed_prompt = tk.Entry(fixed_prompt_frame, width=40)
entry_fixed_prompt.grid(row=1, column=0,padx=5, pady=5, sticky='ew')
entry_fixed_prompt_after = tk.Entry(fixed_prompt_frame, width=40)
entry_fixed_prompt_after.grid(row=1, column=1, padx=5, pady=5, sticky='ew')
# ๋„ค๊ฑฐํ‹ฐ๋ธŒ ํ”„๋กฌํ”„ํŠธ
NP_label = tk.Label(text_frame2, text="๋„ค๊ฑฐํ‹ฐ๋ธŒ\nํ”„๋กฌํ”„ํŠธ", borderwidth=1, relief="solid",height=2)
NP_label.grid(row=0,column=0, padx=5, pady=5, sticky='ew')
negative_text = tk.Text(text_frame2, width=65, height=3)
negative_text.grid(row=0, column=1, padx=5, pady=5, sticky='w')
auto_hide_frame = tk.Frame(left_frame)
auto_hide_frame.grid(row=9, column=0, padx=5, pady=5, sticky='w')
auto_hide_frame.columnconfigure(0, weight=2)
auto_hide_frame.columnconfigure(1, weight=2)
auto_hide_frame.columnconfigure(2, weight=1)
# ์ž๋™ ์ˆจ๊น€ ํ‚ค์›Œ๋“œ ๋ผ๋ฒจ๊ณผ ์ž…๋ ฅ์ฐฝ ์ถ”๊ฐ€
auto_hide_label = tk.Label(auto_hide_frame, text="์ž๋™ ์ˆจ๊น€ ํ‚ค์›Œ๋“œ: keyword1, keyword2, ...")
auto_hide_label.grid(row=0, column=0, sticky='w')
entry_auto_hide = tk.Entry(auto_hide_frame, width=82)
entry_auto_hide.grid(row=1, column=0, columnspan=3, padx=5, pady=5, sticky='ew')
# ์ถ”์ฒœ ํ”„๋กฌํ”„ํŠธ ์กฐํšŒ ๋ฒ„ํŠผ ์„ค์ •
recommend_prompt_button = tk.Button(auto_hide_frame, text="์ถ”์ฒœ ํ”„๋กฌํ”„ํŠธ", command=open_prompt_window)
recommend_prompt_button.grid(row=0, column=2, padx=2, pady=5, sticky='e') # sticky ์˜ต์…˜์„ 'e'๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ์˜ค๋ฅธ์ชฝ ์ •๋ ฌ
# ์ฒดํฌ๋ฐ•์Šค๋“ค์„ ํฌํ•จํ•  ํ”„๋ ˆ์ž„ ์ƒ์„ฑ
checkbox_frame = tk.Frame(left_frame)
checkbox_frame.grid(row=10, column=0, pady=15, sticky='ew')
checkbox_frame2 = tk.Frame(left_frame)
checkbox_frame2.grid(row=10, column=1, padx=5, pady=15, sticky='ew')
# ์ฒดํฌ๋ฐ•์Šค ํ”„๋ ˆ์ž„ ๋‚ด์˜ ์—ด ์„ค์ •
checkbox_frame.columnconfigure(0, weight=1)
checkbox_frame.columnconfigure(1, weight=1)
checkbox_frame.columnconfigure(2, weight=1)
checkbox_frame.columnconfigure(3, weight=1)
checkbox_frame.columnconfigure(4, weight=1)
checkbox_frame.columnconfigure(5, weight=1)
# "์ž‘๊ฐ€๋ช… ์ œ๊ฑฐ" ์ฒดํฌ๋ฐ•์Šค
remove_artist_var = tk.IntVar() # ์ฒดํฌ๋ฐ•์Šค ์ƒํƒœ๋ฅผ ์ €์žฅํ•  ๋ณ€์ˆ˜
check_remove_artist = tk.Checkbutton(checkbox_frame, text="์ž‘๊ฐ€๋ช… ์ œ๊ฑฐ", variable=remove_artist_var)
check_remove_artist.grid(row=0, column=0, sticky='ew')
# "๋žœ๋ค ์ž‘๊ฐ€ ์ถ”๊ฐ€" ์ฒดํฌ๋ฐ•์Šค
random_artist_var = tk.IntVar()
check_random_artist = tk.Checkbutton(checkbox_frame, text="๋žœ๋ค ์ž‘๊ฐ€ ์ถ”๊ฐ€", variable=random_artist_var)
check_random_artist.grid(row=0, column=1, sticky='ew')
# ๋žœ๋ค์ž‘๊ฐ€ ๊ด€๋ฆฌ
random_artist_setting = tk.Button(checkbox_frame, text="๋žœ๋ค ์ž‘๊ฐ€ ๊ด€๋ฆฌ", command=random_artist_management) #output_file_path
random_artist_setting.grid(row=0, column=2, sticky='ew')
# "์บ๋ฆญํ„ฐ ํŠน์ง• ์ œ๊ฑฐ" ์ฒดํฌ๋ฐ•์Šค
rm_characteristic_var = tk.IntVar()
rm_characteristic_label = tk.Checkbutton(checkbox_frame, text="์บ๋ฆญํ„ฐ ํŠน์ง• ์ œ๊ฑฐ", variable=rm_characteristic_var)
rm_characteristic_label.grid(row=0, column=3, sticky='ew')
# ์™€์ผ๋“œ ์นด๋“œ
wildcard_var = tk.IntVar(value= 0)
check_wildcard = tk.Checkbutton(checkbox_frame, text="์™€์ผ๋“œ์นด๋“œ(์ž‘๊ฐ€)", variable=wildcard_var, state='disabled')
check_wildcard.grid(row=1, column=0, sticky='ew')
# ์™€์ผ๋“œ ์นด๋“œ2
wildcard_var2 = tk.IntVar(value= 0)
check_wildcard2 = tk.Checkbutton(checkbox_frame, text="์™€์ผ๋“œ์นด๋“œ(์บ๋ฆญํ„ฐ)", variable=wildcard_var2, state='disabled')
check_wildcard2.grid(row=1, column=1, sticky='ew')
# ์™€์ผ๋“œ ์นด๋“œ ์„ค์ •
widldcard_button = tk.Button(checkbox_frame, text="์™€์ผ๋“œ์นด๋“œ ์„ค์ •", command=open_wildcard_setting) #output_file_path
widldcard_button.grid(row=1, column=2, sticky='ew')
#ํด๋” ํ˜ธ์ถœ ๋ฒ„ํŠผ
folder_button = tk.Button(checkbox_frame, text="์ €์žฅ ํด๋”", command=open_file_explorer) #output_file_path
folder_button.grid(row=1, column=3, padx=5, sticky='ew')
window.bind('<Control-Return>', on_ctrl_enter)
window.bind('<Shift-Return>', on_shift_enter)
NAI_ID = load_settings()
if not (entry_keyword.get()): entry_keyword.insert(0, "1girl")
if not (entry_fixed_prompt.get()): entry_fixed_prompt.insert(0, '1girl,')
if not (entry_fixed_prompt_after.get()): entry_fixed_prompt_after.insert(0, 'great quality, aesthetic, absurdres')
if not (entry_auto_hide.get()): entry_auto_hide.insert(0, 'monochrome, doujin cover, bad source, censored, bar censor')
resolution1_frame = tk.Frame(left_frame)
resolution1_frame.grid(row=15, column=0, padx=5, pady=5, sticky='ew')
resolution2_frame = tk.Frame(left_frame)
resolution2_frame.grid(row=16, column=0, padx=5, pady=5, sticky='ew')
selected_resolution = tk.StringVar(value="1024 x 1024")
tk.Radiobutton(resolution1_frame, text="1024 x 1024", variable=selected_resolution, value="1024 x 1024").grid(row=0, column=0, sticky='w')
tk.Radiobutton(resolution1_frame, text="960 x 1088", variable=selected_resolution, value="960 x 1088").grid(row=0, column=1, sticky='w')
tk.Radiobutton(resolution1_frame, text="896 x 1152", variable=selected_resolution, value="896 x 1152").grid(row=0, column=2, sticky='w')
tk.Radiobutton(resolution1_frame, text="832 x 1216", variable=selected_resolution, value="832 x 1216").grid(row=0, column=3, sticky='w')
tk.Radiobutton(resolution2_frame, text="1088 x 960", variable=selected_resolution, value="1088 x 960").grid(row=0, column=0, sticky='w')
tk.Radiobutton(resolution2_frame, text="1152 x 896", variable=selected_resolution, value="1152 x 896").grid(row=0, column=1, sticky='w')
tk.Radiobutton(resolution2_frame, text="1216 x 832", variable=selected_resolution, value="1216 x 832").grid(row=0, column=2, sticky='w')
selected_resolution.trace_add('write', on_resolution_change)
sema_button_var = tk.IntVar(value=1)
sema_button = tk.Checkbutton(resolution1_frame, text="SEMA", variable=sema_button_var)
sema_button.grid(row=0, column=5, sticky='w')
dyn_button_var = tk.IntVar()
dyn_button = tk.Checkbutton(resolution1_frame, text="+DYN", variable=dyn_button_var)
dyn_button.grid(row=0, column=6, sticky='w')
entry_CFG_value = tk.StringVar()
entry_CFG_label = tk.Label(resolution2_frame, text=" CFG Scale : ", justify=tk.LEFT)
entry_CFG_label.grid(row=0, column=4, sticky='w')
entry_CFG_value.set("5.0")
entry_CFG = tk.Entry(resolution2_frame, width=5, textvariable=entry_CFG_value)
entry_CFG.grid(row=0, column=5, sticky='w')
options = ["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde"]
selected_option = tk.StringVar()
selected_option.set(options[1])
option_menu = tk.OptionMenu(resolution2_frame, selected_option, *options, command=on_option_select)
option_menu.grid(row=0, column=6, padx=5, sticky='ew')
image_label = tk.Label(right_frame, relief='solid', borderwidth=1)
image_label.grid(row=0, column=0, rowspan=15, padx=10, pady=10, sticky="n")
# ์ €๋นˆ๋„ ํ‚ค์›Œ๋“œ ์ž๋™์ถ”๊ฐ€ ๋ฒ„ํŠผ ์ถ”๊ฐ€
btn_add_low_freq = tk.Button(right_frame, text="์ด๋ฏธ์ง€๋ฅผ ํด๋ฆฝ๋ณด๋“œ์— ๋ณต์‚ฌ", fg="blue", command=copy_image_to_clipboard)
btn_add_low_freq.grid(row=16, column=0, padx=5, pady=5, sticky='ew')
# ํ•˜์–€์ƒ‰ ์ด๋ฏธ์ง€ ์ƒ์„ฑ
white_image = Image.new('RGB', (_size, _size), 'white')
white_photo = ImageTk.PhotoImage(white_image)
# ๋ผ๋ฒจ์— ์ด๋ฏธ์ง€ ์„ค์ •
image_label.config(image=white_photo)
image_label.image = white_photo
# ๋ฆฌ์Šค๋„ˆ ์‹œ์ž‘
listener = keyboard.Listener(on_press=on_press, on_release=on_release)
listener.start()
# ํ‚ค๋ณด๋“œ ๋ฆฌ์Šค๋„ˆ ์Šค๋ ˆ๋“œ ์‹œ์ž‘
listener_thread = threading.Thread(target=listener.join, daemon=True)
listener_thread.start()
window.mainloop()