baqu2213 commited on
Commit
54308cb
โ€ข
1 Parent(s): abd3b42

Upload 2 files

Browse files
.gitattributes CHANGED
@@ -84,3 +84,4 @@ Danbooru[[:space:]]Prompt[[:space:]]Selector/prompt_selector_auto_1129_delay_off
84
  Danbooru[[:space:]]Prompt[[:space:]]Selector/prompt_selector_auto_1129_delay_offset_5.exe filter=lfs diff=lfs merge=lfs -text
85
  Danbooru[[:space:]]Prompt[[:space:]]Selector/prompt_selector_auto_1201.exe filter=lfs diff=lfs merge=lfs -text
86
  Danbooru[[:space:]]Prompt[[:space:]]Selector/TEST/prompt_selector_auto_1201_TEST.exe filter=lfs diff=lfs merge=lfs -text
 
 
84
  Danbooru[[:space:]]Prompt[[:space:]]Selector/prompt_selector_auto_1129_delay_offset_5.exe filter=lfs diff=lfs merge=lfs -text
85
  Danbooru[[:space:]]Prompt[[:space:]]Selector/prompt_selector_auto_1201.exe filter=lfs diff=lfs merge=lfs -text
86
  Danbooru[[:space:]]Prompt[[:space:]]Selector/TEST/prompt_selector_auto_1201_TEST.exe filter=lfs diff=lfs merge=lfs -text
87
+ Danbooru[[:space:]]Prompt[[:space:]]Selector/TEST/prompt_selector_auto_1202_testv2.exe filter=lfs diff=lfs merge=lfs -text
Danbooru Prompt Selector/TEST/prompt_selector_auto_1202_testv2.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:366f71233de7158d28ca6ffdf56d2968f59a4c9af027b2a7bb239b5932cca0ba
3
+ size 83205112
Danbooru Prompt Selector/TEST/prompt_selector_auto_1202_testv2.py ADDED
@@ -0,0 +1,1408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tkinter as tk
2
+ import tkinter.ttk as ttk
3
+ from tkinter import filedialog
4
+ import os
5
+ import csv
6
+ import random
7
+ import time
8
+ from collections import Counter
9
+ import re
10
+ import ast
11
+ import pyautogui
12
+ import threading
13
+ from pynput import keyboard
14
+ from base64 import urlsafe_b64encode
15
+ from hashlib import blake2b
16
+ import argon2
17
+ import requests
18
+ import json
19
+ from os import environ as env
20
+ import zipfile
21
+ import io
22
+ from pathlib import Path
23
+ from datetime import datetime
24
+ import numpy as np
25
+ from PIL import Image, ImageOps, ImageFilter,ImageTk
26
+ from IPython.display import display
27
+ import win32clipboard
28
+ from io import BytesIO
29
+ from datetime import datetime
30
+ import arti_list, tagbag, wlist
31
+ from ttkthemes import ThemedTk
32
+
33
+ BASE_URL="https://api.novelai.net"
34
+
35
+ def argon_hash(email: str, password: str, size: int, domain: str) -> str:
36
+ pre_salt = f"{password[:6]}{email}{domain}"
37
+ # salt
38
+ blake = blake2b(digest_size=16)
39
+ blake.update(pre_salt.encode())
40
+ salt = blake.digest()
41
+ raw = argon2.low_level.hash_secret_raw(
42
+ password.encode(),
43
+ salt,
44
+ 2,
45
+ int(2000000 / 1024),
46
+ 1,
47
+ size,
48
+ argon2.low_level.Type.ID,
49
+ )
50
+ hashed = urlsafe_b64encode(raw).decode()
51
+ return hashed
52
+
53
+ def login(key) -> str:
54
+ response = requests.post(f"{BASE_URL}/user/login", json={ "key": key })
55
+ # catch any errors
56
+ return response.json()["accessToken"]
57
+
58
+ def get_access_key(email: str, password: str) -> str:
59
+ return argon_hash(email, password, 64, "novelai_data_access_key")[:64]
60
+
61
+ def get_max_size():
62
+ global window
63
+ width = window.winfo_screenheight()
64
+ return 768 if width < 1440 else 1024
65
+
66
+ def generate_image(access_token, prompt, model, action, parameters):
67
+ data = {
68
+ "input": prompt,
69
+ "model": model,
70
+ "action": action,
71
+ "parameters": parameters,
72
+ }
73
+
74
+ response = requests.post(f"{BASE_URL}/ai/generate-image", json=data, headers={ "Authorization": f"Bearer {access_token}" })
75
+ # catch any errors
76
+ return response.content
77
+
78
+ def generate(width, height, positive, negative, button):
79
+ global temp_clipboard_image
80
+ global current_sampler
81
+ global NAI_width, NAI_height
82
+ global running_flag
83
+ try:
84
+ scale = float(entry_CFG_value.get())
85
+ except:
86
+ scale = 5.0
87
+ if scale > 7.0: scale = 7.0
88
+ elif scale < 4.0: scale = 4.0
89
+ else: scale = round(scale, 1)
90
+ params = {
91
+ "legacy": False,
92
+ "quality_toggle": False,
93
+ "width": width,
94
+ "height": height,
95
+ "n_samples": 1,
96
+ "seed": random.randint(0,9999999999),
97
+ "extra_noise_seed": random.randint(0,9999999999),
98
+ "sampler": current_sampler,
99
+ "steps": 28,
100
+ "scale": scale,
101
+ "uncond_scale": 1.0,
102
+ "negative_prompt": negative_text.get("1.0", "end-1c").strip(),
103
+ "sm" : sema_button_var.get(),
104
+ "sm_dyn" : dyn_button_var.get(),
105
+ "decrisper": False,
106
+ "controlnet_strength": 1.0,
107
+ "add_original_image": False,
108
+ "cfg_rescale": 0.0,
109
+ "noise_schedule": "native",
110
+ }
111
+
112
+ def resize_and_fill(image, max_size=None):
113
+ if max_size is None:
114
+ max_size = get_max_size()
115
+ original_width, original_height = image.size
116
+ if original_width > max_size or original_height > max_size:
117
+ # ๋น„์œจ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํฌ๊ธฐ ์กฐ์ •
118
+ image.thumbnail((max_size, max_size))
119
+
120
+ # ์ƒˆ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๊ณ„์‚ฐ
121
+ width, height = image.size
122
+ new_image = Image.new("RGB", (max_size, max_size), "black")
123
+ new_image.paste(image, ((max_size - width) // 2, (max_size - height) // 2))
124
+ return new_image
125
+ else:
126
+ return image
127
+
128
+ def log_error(e, output_file_path="output_file_path"):
129
+ # ํ˜„์žฌ ์‹œ๊ฐ„์„ ์–ป์Šต๋‹ˆ๋‹ค
130
+ current_time = datetime.now().strftime("%m/%d %H:%M:%S")
131
+
132
+ # ์—๋Ÿฌ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€
133
+ error_message = f"#### Error occured at {current_time} ####\nError: {e}\n############################################\n"
134
+
135
+ # ์ง€์ •๋œ ์ถœ๋ ฅ ํด๋”์˜ error_log.txt ํŒŒ์ผ์— ์“ฐ๊ธฐ
136
+ with open(f"error_log.txt", "a") as file:
137
+ file.write(error_message)
138
+
139
+ global access_token
140
+ try:
141
+ zipped_bytes = generate_image(access_token, positive, "nai-diffusion-3", "generate", params)
142
+ d = Path("output_NAI")
143
+ d.mkdir(exist_ok=True)
144
+ zipped = zipfile.ZipFile(io.BytesIO(zipped_bytes))
145
+ image_bytes = zipped.read(zipped.infolist()[0])
146
+ (d / f"{datetime.now().strftime('%Y%m%d_%H%M%S')}.png" ).write_bytes(image_bytes)
147
+ i = Image.open(io.BytesIO(image_bytes))
148
+ i = ImageOps.exif_transpose(i).convert("RGB")
149
+ if temp_clipboard_image is not None:
150
+ temp_clipboard_image.close()
151
+ temp_clipboard_image = i
152
+ i_resized = resize_and_fill(i)
153
+ if 'tk_image' in globals():
154
+ globals()['tk_image'] = None
155
+ tk_image = ImageTk.PhotoImage(i_resized)
156
+ image_label.config(image=tk_image)
157
+ image_label.image = tk_image # ์ฐธ์กฐ ์œ ์ง€
158
+ output_file_path = "output_image.jpg"
159
+ i.save(output_file_path)
160
+ except Exception as e:
161
+ #text_output.insert(tk.END, f"Error: {e}", fg='red')
162
+ log_error(e, "path_to_output_folder")
163
+ time.sleep(random.uniform(3.0, 9.0))
164
+ button.config(state=tk.DISABLED)
165
+ window.event_generate(GENERATE_EVENT, when="tail")
166
+
167
+ time.sleep(random.uniform(1.0, 2.5))
168
+ button.config(state=tk.NORMAL)
169
+ running_flag = False
170
+
171
+ if mac_var.get() and not running_flag:
172
+ random_function()
173
+ time.sleep(random.uniform(5.1, 8.5))
174
+ button.config(state=tk.DISABLED)
175
+ window.event_generate(GENERATE_EVENT, when="tail")
176
+
177
+ def filter_csv(input_file, output_file, _search_strings):
178
+ output_directory = os.getcwd()
179
+ output_file = os.path.join(output_directory, output_file)
180
+ search_strings = [s.strip() for s in _search_strings.split(',')]
181
+ with open(input_file, 'r', newline='', encoding='utf-8') as f_in, \
182
+ open(output_file, 'w', newline='', encoding='utf-8') as f_out:
183
+ reader = csv.reader(f_in)
184
+ writer = csv.writer(f_out)
185
+ writer_count = 0
186
+ for row in reader:
187
+ if all(search_str in value for search_str in search_strings for value in row):
188
+ writer.writerow(row)
189
+ writer_count += 1
190
+ return writer_count
191
+
192
+ def open_file():
193
+ initial_dir = os.getcwd()
194
+ filepath = filedialog.askopenfilename(
195
+ initialdir=initial_dir,
196
+ filetypes=[("CSV Files", "*.csv")]
197
+ )
198
+ if filepath:
199
+ entry_file_path.delete(0, tk.END)
200
+ entry_file_path.insert(0, filepath)
201
+
202
+ def search():
203
+ global total_rows, cached_rows # cached_rows๋ฅผ global๋กœ ์„ ์–ธ
204
+ input_file = entry_file_path.get()
205
+ keywords = entry_keyword.get()
206
+
207
+ output_file = 'txt2img_temp_prompt.csv'
208
+ writer_count = filter_csv(input_file, output_file, keywords)
209
+ total_rows = writer_count
210
+ total_rows_count_label.config(text=f".csv ๋‚ด ํ”„๋กฌํ”„ํŠธ ํ–‰: {writer_count}", fg="blue")
211
+ text_output.insert(tk.END, f"์ด {writer_count}๊ฐœ์˜ ๋ฌธ์ž์—ด์ด ๊ฒ€์ƒ‰๋˜์–ด ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n")
212
+
213
+ # ๊ฒ€์ƒ‰ ํ›„ cached_rows ์ดˆ๊ธฐํ™”
214
+ cached_rows = []
215
+
216
+ def exclude():
217
+ global total_rows, cached_rows # cached_rows๋ฅผ global๋กœ ์„ ์–ธ
218
+ input_file = entry_file_path.get()
219
+ keywords = entry_keyword.get()
220
+ output_file = 'txt2img_temp_prompt.csv'
221
+ keyword_label.config(text="๊ฒ€์ƒ‰ํ•  ํ‚ค์›Œ๋“œ: ")
222
+
223
+ output_directory = os.getcwd()
224
+ output_file = os.path.join(output_directory, output_file)
225
+ search_strings = [s.strip() for s in keywords.split(',')]
226
+
227
+ with open(input_file, 'r', newline='', encoding='utf-8') as f_in, \
228
+ open(output_file, 'w', newline='', encoding='utf-8') as f_out:
229
+ reader = csv.reader(f_in)
230
+ writer = csv.writer(f_out)
231
+ writer_count = 0
232
+ for row in reader:
233
+ if not any(search_str in value for search_str in search_strings for value in row):
234
+ writer.writerow(row)
235
+ writer_count += 1
236
+ total_rows = writer_count
237
+ total_rows_count_label.config(text=f".csv ๋‚ด ํ”„๋กฌํ”„ํŠธ ํ–‰: {writer_count}", fg="red")
238
+ text_output.insert(tk.END, f"์ด {writer_count}๊ฐœ์˜ ๋ฌธ์ž์—ด์ด ๊ฒ€์ƒ‰๋˜์–ด ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n")
239
+
240
+ # ์ œ์™ธ ํ›„ cached_rows ์ดˆ๊ธฐํ™”
241
+ cached_rows = []
242
+
243
+ def copy_image_to_clipboard():
244
+ global temp_clipboard_image
245
+ image = temp_clipboard_image
246
+ output = BytesIO()
247
+ image.convert('RGB').save(output, format='BMP')
248
+ data = output.getvalue()[14:] # BMP ํŒŒ์ผ ํ—ค๋” ์ œ๊ฑฐ
249
+ output.close()
250
+
251
+ win32clipboard.OpenClipboard()
252
+ win32clipboard.EmptyClipboard()
253
+ win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
254
+ win32clipboard.CloseClipboard()
255
+
256
+ def reset():
257
+ cached_rows = None
258
+ entry_file_path.delete(0, tk.END)
259
+ entry_keyword.delete(0, tk.END)
260
+ entry_deep_search.delete(0, tk.END)
261
+ text_output.delete('1.0', tk.END)
262
+
263
+ def random_function():
264
+ global last_deep_search_keywords, cached_rows, last_selected_row_keywords, top_100_keywords, previous_artist, top_100_counts
265
+ current_deep_search_keywords = entry_deep_search.get().strip()
266
+ auto_hide_keywords = entry_auto_hide.get().split(',')
267
+ auto_hide_keywords = [keyword.strip() for keyword in auto_hide_keywords if keyword.strip()]
268
+ current_artist = None
269
+
270
+ curly_brackets_keywords = re.findall(r'\{([^}]+)\}', current_deep_search_keywords)
271
+ # ๊ฐ ๋ธŒ๋ž˜ํ‚ท ๋‚ด ํ‚ค์›Œ๋“œ ๊ทธ๋ฃน์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ์™„๋ฒฝ ์ผ์น˜ ํ‚ค์›Œ๋“œ์™€ ์ผ๋ฐ˜ ํ‚ค์›Œ๋“œ๋ฅผ ๊ตฌ๋ถ„
272
+ processed_keywords = []
273
+ for group in curly_brackets_keywords:
274
+ perfect_match_group = [kw[1:].strip() for kw in group.split('|') if kw.startswith('*')]
275
+ regular_group = [kw.strip() for kw in group.split('|') if not kw.startswith('*')]
276
+ processed_keywords.append((perfect_match_group, regular_group))
277
+
278
+ modified_deep_search_keywords = re.sub(r'\{[^}]+\}', '', current_deep_search_keywords)
279
+
280
+ # ๋‚จ์€ ํ‚ค์›Œ๋“œ๋“ค์„ ์‰ผํ‘œ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฒ˜๋ฆฌ
281
+ remaining_keywords = [kw.strip() for kw in modified_deep_search_keywords.split(',') if kw.strip()]
282
+ perfect_match_keywords = [kw[1:].strip() for kw in remaining_keywords if kw.startswith('*')]
283
+
284
+ # exclude_keywords์™€ include_keywords ์ •์˜
285
+ exclude_keywords = [kw[1:].strip() for kw in remaining_keywords if kw.startswith('~') and not kw[1:].startswith('*')]
286
+ include_keywords = [kw for kw in remaining_keywords if not kw.startswith('~') and not kw.startswith('*')]
287
+
288
+ if current_deep_search_keywords != last_deep_search_keywords or not cached_rows:
289
+ entry_auto_hide.delete(0, tk.END)
290
+ entry_auto_hide.insert(tk.END, 'monochrome, doujin cover, bad source, censored, bar censor, photoshop (medium)')
291
+ with open('txt2img_temp_prompt.csv', 'r', newline='', encoding='utf-8') as f:
292
+ reader = csv.reader(f)
293
+ rows = []
294
+ for row in reader:
295
+ if all(re.search(r'(?:^|, )' + re.escape(kw) + r'(?:,|$)', ', '.join(row)) for kw in perfect_match_keywords) \
296
+ and not any(exclude in cell for exclude in exclude_keywords for cell in row) \
297
+ and all(include in cell for include in include_keywords for cell in row):
298
+ # '{}' ์•ˆ์˜ ํ‚ค์›Œ๋“œ ์ฒ˜๋ฆฌ
299
+ if all(any(re.search(r'(?:^|, )' + re.escape(kw) + r'(?:,|$)', ', '.join(cell)) for kw in perfect_group) or
300
+ any(kw in cell for kw in regular_group) for perfect_group, regular_group in processed_keywords for cell in row):
301
+ rows.append(row)
302
+ cached_rows = rows
303
+
304
+ last_deep_search_keywords = current_deep_search_keywords
305
+ if not toggle_prompt_var.get(): text_output.delete('1.0', tk.END)
306
+
307
+ if random_artist_var.get():
308
+ if(not entry_fixed_prompt.get()): entry_fixed_prompt.insert(tk.END,'1girl')
309
+
310
+ if not os.path.exists("counting_result.txt"):
311
+ keyword_counts = analyze_cached_rows(cached_rows)
312
+ excluded_keywords = set(whitelist[:2974])
313
+ with open("counting_result.txt", "w") as file:
314
+ for keyword, count in sorted(keyword_counts.items(), key=lambda item: item[1], reverse=True):
315
+ if keyword not in excluded_keywords and keyword in afilter_30000:
316
+ file.write(f"{keyword}: {count}\n")
317
+ with open("counting_result.txt", "r") as file:
318
+ lines = file.readlines()
319
+ top_100_data = [
320
+ (line.split(":")[0].strip(), int(line.split(":")[1].strip()))
321
+ for line in lines[:3000]
322
+ if line.split(":")[0].strip() in afilter_30000[:8528]
323
+ ]
324
+ top_100_keywords, top_100_counts = zip(*top_100_data) if top_100_data else ([], [])
325
+ elif (not top_100_keywords):
326
+ with open("counting_result.txt", "r") as file:
327
+ lines = file.readlines()
328
+ top_100_data = [
329
+ (line.split(":")[0].strip(), int(line.split(":")[1].strip()))
330
+ for line in lines[:3000]
331
+ if line.split(":")[0].strip() in afilter_30000[:8528]
332
+ ]
333
+ top_100_keywords, top_100_counts = zip(*top_100_data) if top_100_data else ([], [])
334
+
335
+ formatted_artist_random_keyword = []
336
+ if top_100_keywords:
337
+ temp_keyword = []
338
+ temp_keyword += top_100_keywords
339
+ whatthefuck = random.random()
340
+ print(whatthefuck)
341
+ if(whatthefuck > 0.9):
342
+ for i in range(4):
343
+ random_keyword = random.choice(temp_keyword)
344
+ temp_keyword.remove(random_keyword)
345
+ if(i == 0): formatted_artist_random_keyword = "{{{artist:"+random_keyword+"}}}"
346
+ if(i == 1): formatted_artist_random_keyword += ",{artist:"+random_keyword+"}"
347
+ if(i == 2): formatted_artist_random_keyword += ",artist:"+random_keyword
348
+ if(i == 3): formatted_artist_random_keyword += ",[[artist:"+random_keyword+"]]"
349
+ elif(whatthefuck > 0.7):
350
+ for i in range(3):
351
+ random_keyword = random.choice(temp_keyword)
352
+ temp_keyword.remove(random_keyword)
353
+ if(i == 0): formatted_artist_random_keyword = "{{{artist:"+random_keyword+"}}}"
354
+ if(i == 1): formatted_artist_random_keyword += ",{artist:"+random_keyword+"}"
355
+ if(i == 2): formatted_artist_random_keyword += ",[[artist:"+random_keyword+"]]"
356
+ elif(whatthefuck > 0.45):
357
+ for i in range(2):
358
+ random_keyword = random.choice(temp_keyword)
359
+ temp_keyword.remove(random_keyword)
360
+ if(i == 0): formatted_artist_random_keyword = "{{{artist:"+random_keyword+"}}}"
361
+ if(i == 2): formatted_artist_random_keyword += ",[[artist:"+random_keyword+"]]"
362
+ else:
363
+ random_keyword = random.choice(temp_keyword)
364
+ temp_keyword.remove(random_keyword)
365
+ formatted_artist_random_keyword = "{{artist:"+random_keyword+"}}"
366
+ current_artist = formatted_artist_random_keyword
367
+ print(formatted_artist_random_keyword)
368
+ if not top_100_keywords: random_artist_var.set(0)
369
+ else:
370
+ formatted_artist_random_keyword = f"์ž‘๊ฐ€ ํ‚ค์›Œ๋“œ๊ฐ€ ์—†์Œ!!"
371
+
372
+ if cached_rows:
373
+ if toggle_prompt_var.get() and last_selected_row_keywords:
374
+ random_row_keywords = text_output.get("1.0", "end-1c").split(',')
375
+ #random_row_keywords[-1].strip()
376
+ if random_row_keywords[0]=='': random_row_keywords = last_selected_row_keywords
377
+ text_output.delete('1.0', tk.END)
378
+ else:
379
+ random_index = random.randint(0, len(cached_rows) - 1)
380
+ random_row = cached_rows.pop(random_index)
381
+ random_row_keywords = [keyword.strip() for keyword in random_row[0].split(',')]
382
+ last_selected_row_keywords = random_row_keywords
383
+
384
+ if(entry_fixed_prompt.get()):
385
+ entry_text_keywords = entry_fixed_prompt.get()
386
+ if(',' not in entry_text_keywords[-2:]): entry_text_keywords += ','
387
+ entry_text_keywords = entry_text_keywords.split(',')
388
+ entry_text_keywords = [kw.strip() for kw in entry_text_keywords if kw.strip()]
389
+
390
+ temp_first_keywords = []
391
+ #print("1 :", temp_first_keywords)
392
+
393
+ # entry_text_keywords์˜ ๋ชจ๋“  ํ‚ค์›Œ๋“œ๋ฅผ temp_first_keywords์— ์ถ”๊ฐ€
394
+ for et_kw in entry_text_keywords:
395
+ 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):
396
+ temp_first_keywords.append(et_kw)
397
+
398
+ # 'boy' ํ‚ค์›Œ๋“œ ์ฒ˜๋ฆฌ
399
+ boy_keywords = [kw for kw in random_row_keywords if 'boy' in kw and len(kw) <= 7]
400
+
401
+ # 'girl' ํ‚ค์›Œ๋“œ ์ฒ˜๋ฆฌ ๋ฐ ์œ„์น˜ ์กฐ์ •
402
+ girl_keywords = []
403
+ if 'girl' in entry_text_keywords[0] and len(entry_text_keywords[0]) <= 7:
404
+ girl_keywords = [kw for kw in random_row_keywords if 'girl' in kw and len(kw) <= 7]
405
+
406
+ # random_row_keywords์—์„œ boy์™€ girl ํ‚ค์›Œ๋“œ ์ œ๊ฑฐ
407
+ for kw in boy_keywords + girl_keywords:
408
+ if kw in random_row_keywords:
409
+ random_row_keywords.remove(kw)
410
+
411
+ for kw in temp_first_keywords:
412
+ if kw in random_row_keywords:
413
+ random_row_keywords.remove(kw)
414
+
415
+
416
+ # temp_first_keywords์— boy์™€ girl ํ‚ค์›Œ๋“œ๋ฅผ ์ ์ ˆํ•œ ์œ„์น˜์— ์ถ”๊ฐ€
417
+ if(girl_keywords and 'girl' in temp_first_keywords[0]): temp_first_keywords.pop(0)
418
+ print(wildcard_var.get())
419
+ if(wildcard_var2.get() == 1):
420
+ temp_len = len(girl_keywords)
421
+ girl_keywords.append(get_random_keyword('character'))
422
+ if(wildcard_var.get() == 1):
423
+ if(wildcard_var2.get() == 1): girl_keywords.insert(temp_len+1,get_random_keyword('artist'))
424
+ else: girl_keywords.append(get_random_keyword('artist'))
425
+ temp_first_keywords = boy_keywords + girl_keywords + temp_first_keywords
426
+ #print("2 :", temp_first_keywords)
427
+
428
+ if remove_artist_var.get():
429
+ for keyword in random_row_keywords:
430
+ if keyword in afilter_30000:
431
+ random_row_keywords.remove(keyword)
432
+ temp_rm = []
433
+ if rm_characteristic_var.get():
434
+ for keyword in random_row_keywords:
435
+ if keyword in bag_of_tags or "(" in keyword:
436
+ random_row_keywords.remove(keyword)
437
+ temp_rm.append(keyword)
438
+ for keyword in random_row_keywords:
439
+ if "(" in keyword:
440
+ random_row_keywords.remove(keyword)
441
+ temp_rm.append(keyword)
442
+ print('removed : ',temp_rm)
443
+
444
+ for keyword in random_row_keywords[:]: # ๋ณต์‚ฌ๋ณธ์„ ์ˆœํšŒํ•˜์—ฌ ์›๋ณธ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆ˜์ •
445
+ if " (" in keyword:
446
+ temp_first_keywords.append(keyword)
447
+ random_row_keywords.remove(keyword)
448
+ else:
449
+ if not random_row_keywords: random_row_keywords = last_selected_row_keywords
450
+ temp_first_keywords = []
451
+ for keyword in random_row_keywords[:]: # ๋ณต์‚ฌ๋ณธ์„ ์ˆœํšŒํ•˜์—ฌ ์›๋ณธ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆ˜์ •
452
+ if " (" in keyword:
453
+ temp_first_keywords.append(keyword)
454
+ random_row_keywords.remove(keyword)
455
+
456
+ last_selected_row_keywords = random_row_keywords
457
+ #print("3 :", temp_first_keywords)
458
+ if random_artist_var.get():
459
+ temp_first_keywords.append(formatted_artist_random_keyword)
460
+ #print("4 :", temp_first_keywords)
461
+ if (previous_artist and previous_artist in temp_first_keywords): temp_first_keywords.remove(previous_artist)
462
+ if (current_artist is (not None)):
463
+ for i in range (len(current_artist)):
464
+ previous_artist += current_artist[i]
465
+ random_row_keywords = temp_first_keywords + random_row_keywords
466
+ #print("5 :", random_row_keywords)
467
+ elif toggle_prompt_var.get(): random_row_keywords = temp_first_keywords + random_row_keywords
468
+ else: random_row_keywords = temp_first_keywords + random_row_keywords
469
+
470
+ patterns = [r'\b{}\b'.format(re.escape(keyword)) for keyword in auto_hide_keywords]
471
+
472
+ for pattern in patterns:
473
+ random_row_keywords = [re.sub(pattern + '(, )?', '', keyword) for keyword in random_row_keywords]
474
+ random_row_keywords = [re.sub('(?<=, )' + pattern, '', keyword) for keyword in random_row_keywords]
475
+
476
+ if entry_fixed_prompt_after.get():
477
+ entry_after_text = entry_fixed_prompt_after.get().strip().split(',')
478
+ for at_kw in entry_after_text:
479
+ if at_kw not in random_row_keywords and ' '+at_kw not in random_row_keywords:
480
+ random_row_keywords.append(at_kw)
481
+
482
+ random_row_keywords = [keyword.strip(', ') for keyword in random_row_keywords]
483
+ random_row_keywords = [keyword for keyword in random_row_keywords if keyword]
484
+ #print(random_row_keywords)
485
+ text_output.insert(tk.END, f"{', '.join(random_row_keywords)}")
486
+ if auto_copy_var.get():
487
+ copy_to_clipboard()
488
+ else:
489
+ text_output.insert(tk.END, "๊ฒ€์ƒ‰ ์กฐ๊ฑด์— ๋งž๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๊ฑฐ๋‚˜ CSV ํŒŒ์ผ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.\n")
490
+
491
+ cached_rows_count_label.config(text=f"์‹ฌ์ธต๊ฒ€์ƒ‰ ํ”„๋กฌํ”„ํŠธ ํ–‰: {len(cached_rows)}")
492
+
493
+ def add_low_frequency_keywords():
494
+ global keyword_counts, most_common_count
495
+ keyword_counts = analyze_cached_rows(cached_rows)
496
+ if not keyword_counts: # keyword_counts๊ฐ€ ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ ํ•จ์ˆ˜๋ฅผ ๋น ์ ธ๋‚˜์˜ต๋‹ˆ๋‹ค.
497
+ return
498
+
499
+ # ๊ฐ€์žฅ ํ”ํ•œ ํ‚ค์›Œ๋“œ์˜ ๋นˆ๋„์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
500
+ most_common_count = keyword_counts.most_common(1)[0][1]
501
+
502
+ # ์กฐ๊ฑด์— ๋งž๋Š” ํ‚ค์›Œ๋“œ๋“ค์„ ์ฐพ์Šต๋‹ˆ๋‹ค.
503
+ low_freq_keywords = [keyword for keyword, count in keyword_counts.items()
504
+ if keyword not in last_deep_search_keywords and keyword not in whitelist and count / most_common_count <= 0.05]
505
+
506
+ # ์ž๋™ ์ˆจ๊น€ ํ‚ค์›Œ๋“œ ์ž…๋ ฅ์ฐฝ์— ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
507
+ existing_keywords = entry_auto_hide.get().split(',')
508
+ existing_keywords = [keyword.strip() for keyword in existing_keywords if keyword.strip()] # ๊ณต๋ฐฑ ์ œ๊ฑฐ ๋ฐ ๋นˆ ๋ฌธ์ž์—ด ์ œ๊ฑฐ
509
+
510
+ # ๊ธฐ์กด ํ‚ค์›Œ๋“œ์— ์ƒˆ๋กœ์šด ์ €๋นˆ๋„ ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
511
+ updated_keywords = existing_keywords + low_freq_keywords
512
+ unique_keywords = list(set(updated_keywords)) # ์ค‘๋ณต ์ œ๊ฑฐ
513
+ for keyword in unique_keywords:
514
+ if(keyword in afilter_30000):
515
+ unique_keywords.remove(keyword)
516
+ entry_auto_hide.delete(0, tk.END)
517
+ entry_auto_hide.insert(0, ', '.join(unique_keywords))
518
+
519
+ def copy_to_clipboard():
520
+ window.clipboard_clear()
521
+ entry_text = entry_fixed_prompt.get()
522
+ if(',' not in entry_text and entry_text): entry_text += ','
523
+ combined_text = text_output.get("1.0", tk.END)
524
+ window.clipboard_append(combined_text)
525
+
526
+ def exit_program():
527
+ window.destroy()
528
+
529
+ def save_settings():
530
+ global NAI_ID
531
+ with open('app_settings.txt', 'w', encoding='utf-8') as f: #1
532
+ if(len(entry_file_path.get()) > 4):
533
+ f.write(entry_file_path.get() + '\n')
534
+ else: f.write(" "+'\n')
535
+ if(len(entry_keyword.get()) > 3): #2
536
+ f.write(entry_keyword.get() + '\n')
537
+ else: f.write(" "+'\n')
538
+ if(len(entry_deep_search.get()) > 3): #3
539
+ f.write(entry_deep_search.get() + '\n')
540
+ else: f.write(" "+'\n')
541
+ if(len(entry_fixed_prompt.get()) > 4): #4
542
+ f.write(entry_fixed_prompt.get() + '\n')
543
+ else: f.write(" "+'\n')
544
+ if(len(entry_fixed_prompt_after.get()) > 4): #5
545
+ f.write(entry_fixed_prompt_after.get() + '\n')
546
+ else: f.write(" "+'\n')
547
+ if(len(entry_auto_hide.get()) > 3): #6
548
+ f.write(entry_auto_hide.get() + '\n')
549
+ else: f.write(" "+'\n')
550
+ if(len(negative_text.get("1.0", tk.END)) > 4): #7
551
+ f.write(negative_text.get("1.0", tk.END))
552
+ else: f.write(" "+'\n')
553
+ if(NAI_ID): f.write(NAI_ID + '\n' ) #ํ•ญ์ƒ ๋งˆ์ง€๋ง‰์— ์˜ค๋„๋ก ๊ธฐ์–ต #8
554
+
555
+ def load_settings():
556
+ NAI_ID = ""
557
+ if os.path.exists('app_settings.txt'):
558
+ with open('app_settings.txt', 'r', encoding='utf-8') as f:
559
+ settings = f.readlines()
560
+ entry_file_path.insert(0, settings[0].strip())
561
+ entry_keyword.insert(0, settings[1].strip())
562
+ entry_deep_search.insert(0, settings[2].strip())
563
+ entry_fixed_prompt.insert(0, settings[3].strip())
564
+ entry_fixed_prompt_after.insert(0, settings[4].strip())
565
+ entry_auto_hide.insert(0, settings[5].strip())
566
+ if(len(settings)>=7):
567
+ negative_text.insert(tk.END, settings[6].strip())
568
+ if(len(settings)>=8):
569
+ NAI_ID = settings[7].strip() #ํ•ญ์ƒ ๋งˆ์ง€๋ง‰์— ์˜ค๋„๋ก ๊ธฐ์–ต
570
+ return NAI_ID
571
+
572
+ def open_prompt_window():
573
+ # ์ƒˆ ์ฐฝ ์ƒ์„ฑ
574
+ prompt_window = tk.Toplevel(window)
575
+ prompt_title = f"{entry_keyword.get()}+{last_deep_search_keywords}" if last_deep_search_keywords else "์ถ”์ฒœ ํ”„๋กฌํ”„ํŠธ"
576
+ prompt_window.title(prompt_title)
577
+
578
+
579
+ # ์ฒซ ๋ฒˆ์งธ Text Output Box ์„ค์ •
580
+ text_output1 = tk.Text(prompt_window, height=10, width=50)
581
+ text_output1.pack(padx=10, pady=10)
582
+
583
+ # ๊ตต์€ ๊ธ€์”จ ์Šคํƒ€์ผ ํƒœ๊ทธ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
584
+ text_output1.tag_configure('bold', font=('Arial', 10, 'bold'))
585
+
586
+ # ๋‘ ๋ฒˆ์งธ Text Output Box ์„ค์ •
587
+ text_output2 = tk.Text(prompt_window, height=10, width=50)
588
+ text_output2.pack(padx=10, pady=10)
589
+
590
+ # ์„ธ ๋ฒˆ์งธ Text Output Box ์„ค์ •
591
+ text_output3 = tk.Text(prompt_window, height=10, width=50)
592
+ text_output3.pack(padx=10, pady=10)
593
+
594
+ # cached_rows ๋ถ„์„
595
+ keyword_counts = analyze_cached_rows(cached_rows)
596
+
597
+ # ๊ฐ€์žฅ ๋†’์€ count ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
598
+ most_common_count = keyword_counts.most_common(1)[0][1] if keyword_counts else 0
599
+
600
+ # text_output1์— ๊ฐ€์žฅ ํ”ํ•œ ํ‚ค์›Œ๋“œ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ , ์กฐ๊ฑด์— ๋”ฐ๋ผ ๊ตต๊ฒŒ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
601
+ for keyword, count in keyword_counts.most_common(50):
602
+ if count / most_common_count >= 0.5: # count๊ฐ€ ๊ฐ€์žฅ ๋†’์€ ํ‚ค์›Œ๋“œ ๋Œ€๋น„ 60% ์ด์ƒ์ธ ๊ฒฝ์šฐ
603
+ text_output1.insert(tk.END, f"{keyword}, ", 'bold')
604
+ else:
605
+ text_output1.insert(tk.END, f"{keyword}, ")
606
+
607
+ # text_output2์— ๋ชจ๋“  ํ‚ค์›Œ๋“œ์™€ ๋นˆ๋„์ˆ˜ ์ถœ๋ ฅ
608
+ for keyword, count in keyword_counts.most_common(200):
609
+ text_output2.insert(tk.END, f"{keyword}: {count}, ")
610
+
611
+ excluded_keywords = set(whitelist[:2974])
612
+ artist_count = 0
613
+ with open("counting_result.txt", "w") as file:
614
+ for keyword, count in sorted(keyword_counts.items(), key=lambda item: item[1], reverse=True):
615
+ if keyword not in excluded_keywords and keyword in afilter_30000:
616
+ file.write(f"{keyword}: {count}\n")
617
+ if(artist_count < 150):
618
+ text_output3.insert(tk.END, f"{keyword}: {count}, ")
619
+ artist_count += 1
620
+
621
+ # ๋‹ซ๊ธฐ ๋ฒ„ํŠผ ์„ค์ •
622
+ close_button = tk.Button(prompt_window, text="๋‹ซ๊ธฐ", command=prompt_window.destroy)
623
+ close_button.pack(pady=10)
624
+
625
+ def analyze_cached_rows(cached_rows):
626
+ global top_100_keywords
627
+ top_100_keywords = []
628
+ counts = Counter()
629
+ for row in cached_rows:
630
+ substrings = [substring.strip() for value in row for substring in value.split(',') if substring.strip()]
631
+ counts.update(substrings)
632
+ return counts
633
+
634
+ def exit_program():
635
+ save_settings()
636
+ window.destroy()
637
+
638
+ def on_ctrl_enter(event):
639
+ random_function()
640
+
641
+ def on_shift_enter(event):
642
+ random_function()
643
+ copy_to_clipboard()
644
+
645
+ def export_csv():
646
+ source_file = os.path.join(os.getcwd(), 'txt2img_temp_prompt.csv')
647
+ if not os.path.exists(source_file):
648
+ print("์†Œ์Šค ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")
649
+ return
650
+
651
+ # ๊ธฐ๋ณธ ํŒŒ์ผ ์ด๋ฆ„์„ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ๋กœ ์„ค์ •
652
+ default_filename = f"{entry_keyword.get()}.csv" if entry_keyword.get() else "exported.csv"
653
+ file_types = [('CSV ํŒŒ์ผ', '*.csv')]
654
+ dest_file = filedialog.asksaveasfilename(defaultextension='.csv', filetypes=file_types, initialfile=default_filename)
655
+
656
+ if dest_file: # ์‚ฌ์šฉ์ž๊ฐ€ ํŒŒ์ผ ์ด๋ฆ„์„ ์„ ํƒํ–ˆ์„ ๊ฒฝ์šฐ
657
+ import shutil
658
+ shutil.copy(source_file, dest_file)
659
+ print(f"ํŒŒ์ผ์ด ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค: {dest_file}")
660
+
661
+ def export_csv_search():
662
+
663
+ if not cached_rows:
664
+ print("๋น„์–ด์žˆ๋Š” ํ”„๋กฌํ”„ํŠธํ–‰.")
665
+ return
666
+
667
+ # ๊ธฐ๋ณธ ํŒŒ์ผ ์ด๋ฆ„์„ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํ‚ค์›Œ๋“œ๋กœ ์„ค์ •
668
+ default_filename = f"{entry_keyword.get()}.csv" if entry_keyword.get() else "exported.csv"
669
+ file_types = [('CSV ํŒŒ์ผ', '*.csv')]
670
+ dest_file = filedialog.asksaveasfilename(defaultextension='.csv', filetypes=file_types, initialfile=default_filename)
671
+
672
+ if dest_file: # ์‚ฌ์šฉ์ž๊ฐ€ ํŒŒ์ผ ์œ„์น˜๋ฅผ ์„ ํƒํ–ˆ๋‹ค๋ฉด
673
+ with open(dest_file, 'w', newline='', encoding='utf-8') as file:
674
+ writer = csv.writer(file)
675
+ for row in cached_rows:
676
+ writer.writerow(row) # ๊ฐ ํ–‰์„ csv ํŒŒ์ผ์— ์“ด๋‹ค
677
+
678
+ def simulate_shortcuts():
679
+ global listener, on_press_flag
680
+
681
+ on_press_flag = True
682
+ random_function()
683
+ on_press_flag = False
684
+ try:
685
+ current_keys.clear()
686
+ current_keys.add(keyboard.Key.ctrl_l)
687
+ except KeyError:
688
+ pass
689
+
690
+ def on_activate_simulate_shortcuts():
691
+ simulate_shortcuts()
692
+
693
+ def for_canonical(f):
694
+ return lambda k: f(listener.canonical(k))
695
+
696
+ def start_keyboard_listener():
697
+ global listener
698
+ listener = keyboard.Listener(on_press=on_press, on_release=on_release)
699
+ listener.start()
700
+
701
+ def on_press(key):
702
+ global on_press_flag
703
+
704
+ current_keys.add(key)
705
+
706
+ # Ctrl + ` ์กฐํ•ฉ ๊ฐ์ง€
707
+ if keyboard.Key.ctrl_l in current_keys:
708
+ if any(k.vk == 192 for k in current_keys if hasattr(k, 'vk')):
709
+ on_press_flag = True
710
+ simulate_shortcuts()
711
+
712
+ def on_release(key):
713
+ try:
714
+ current_keys.remove(key)
715
+ except KeyError:
716
+ pass
717
+
718
+ def v_automatic(save_position, prompt_position):
719
+ # ํ”„๋กฌํ”„ํŠธ ์ฐฝ ํด๋ฆญ
720
+ copy_to_clipboard()
721
+ pyautogui.click(prompt_position)
722
+ time.sleep(0.5)
723
+ random_function()
724
+ pyautogui.hotkey('ctrl', 'a', 'v','Right','Right','Enter')
725
+ time.sleep(0.5)
726
+ pyautogui.click(save_position)
727
+
728
+ def start_automation(save_position, prompt_position, label, window_to_close, automation_event):
729
+ def automation_task():
730
+ while automation_event.is_set():
731
+ random_delay = random.uniform(17.5, 23.5)
732
+ next_click_time = time.time() + random_delay
733
+ while time.time() < next_click_time and automation_event.is_set():
734
+ time_remaining = max(next_click_time - time.time(), 0)
735
+ label.config(text=f"๋‹ค์Œ ํด๋ฆญ๊นŒ์ง€: {time_remaining:.2f}์ดˆ")
736
+ time.sleep(0.1)
737
+ if automation_event.is_set():
738
+ v_automatic(save_position, prompt_position)
739
+
740
+ automation_thread = threading.Thread(target=automation_task, daemon=True)
741
+ automation_thread.start()
742
+ random_function()
743
+
744
+ def stop_automation():
745
+ automation_event.clear()
746
+ window_to_close.destroy()
747
+
748
+ window_to_close.protocol("WM_DELETE_WINDOW", stop_automation)
749
+
750
+ def stop_automation(window_to_close, automation_event, start_button, stop_button):
751
+ automation_event.clear() # Stop the automation task
752
+ start_button['state'] = 'normal' # Enable the start button
753
+ stop_button['state'] = 'disabled' # Disable the stop button
754
+ window_to_close.destroy() # Close the automation window
755
+ window.deiconify()
756
+
757
+ # ๋ผ๋ฒจ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ํ•จ์ˆ˜
758
+ def update_label(label, text):
759
+ def task():
760
+ label.config(text=text)
761
+ label.after(1000, task) # ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ UI ์—…๋ฐ์ดํŠธ
762
+
763
+ def open_automation_window():
764
+ window.iconify()
765
+ automation_event = threading.Event()
766
+ automation_event.set() # Enable the automation event
767
+ auto_window = tk.Toplevel(window)
768
+ auto_window.title("์ž๋™ํ™” ์„ค์ •")
769
+ auto_window.geometry("300x200") # ์ฐฝ ํฌ๊ธฐ ์กฐ์ •
770
+ auto_window.attributes('-topmost', True) # ์ฐฝ์„ ํ•ญ์ƒ ๋งจ ์œ„์— ์œ„์น˜
771
+ auto_window.focus_force() # ์ฐฝ ์—ด๋ฆด ๋•Œ ํฌ์ปค์Šค ๊ฐ•์ œ ์ด๋™
772
+
773
+ save_position = None
774
+ prompt_position = None
775
+ automation_running = threading.Event()
776
+
777
+ def get_mouse_position(event=None):
778
+ nonlocal save_position, prompt_position
779
+ x, y = pyautogui.position()
780
+ if not save_position:
781
+ save_position = (x, y)
782
+ position_label.config(text=f"์ €์žฅ ๋ฒ„ํŠผ์˜ ์ขŒํ‘œ: {x}, {y}\nํ”„๋กฌํ”„ํŠธ ์ฐฝ์˜ ์ขŒํ‘œ: ")
783
+ elif not prompt_position:
784
+ prompt_position = (x, y)
785
+ position_label.config(text=f"์ €์žฅ ๋ฒ„ํŠผ์˜ ์ขŒํ‘œ: {save_position[0]}, {save_position[1]}\nํ”„๋กฌํ”„ํŠธ ์ฐฝ์˜ ์ขŒํ‘œ: {x}, {y}")
786
+ start_button.config(state="normal")
787
+ if save_position and prompt_position:
788
+ start_button.config(state="normal")
789
+ stop_button.config(state="normal")
790
+
791
+
792
+ position_label = tk.Label(auto_window, text="์—”ํ„ฐ๋ฅผ ๋ˆŒ๋Ÿฌ ๋งˆ์šฐ์Šค ์ขŒํ‘œ๋ฅผ ์ €์žฅํ•˜์„ธ์š”\n(ํด๋ฆญ X, 1.์ €์žฅ->2.ํ”„๋กฌํ”„ํŠธ์ฐฝ ์ˆœ์„œ)", justify=tk.LEFT)
793
+ position_label.pack(pady=10)
794
+
795
+ start_button = tk.Button(auto_window, text="์‹œ์ž‘", state="disabled",
796
+ command=lambda: start_automation(save_position, prompt_position, countdown_label, auto_window, automation_event))
797
+ start_button.pack(side=tk.LEFT, fill='x', expand=True)
798
+
799
+ stop_button = tk.Button(auto_window, text="์ค‘์ง€", state="disabled",
800
+ command=lambda: stop_automation(auto_window, automation_event, start_button, stop_button))
801
+ stop_button.pack(side=tk.RIGHT, fill='x', expand=True)
802
+
803
+ countdown_label = tk.Label(auto_window, text="")
804
+ countdown_label.pack(pady=10)
805
+
806
+ auto_window.bind('<Return>', get_mouse_position)
807
+
808
+ def NAI_generation(width, height, button):
809
+ button.config(state=tk.DISABLED)
810
+ positive = text_output.get("1.0", tk.END)
811
+ negative = negative_text.get("1.0", "end-1c").strip()
812
+ thread = threading.Thread(target=generate, args=(width, height, positive, negative, button))
813
+ thread.start()
814
+
815
+ def NAI_setting(button, button_generate):
816
+ global NAI_ID
817
+ NAI_setting_window = tk.Toplevel(window)
818
+ NAI_setting_window_title = "NAI ๋กœ๊ทธ์ธ"
819
+
820
+ def NAI_close():
821
+ NAI_setting_window.destroy()
822
+
823
+ NAI_ID_label = tk.Label(NAI_setting_window, text="NAI ID: ")
824
+ NAI_ID_label.grid(row=0, column=0, columnspan=2, sticky='w')
825
+ entry_NAI_ID = tk.Entry(NAI_setting_window, width=50)
826
+ entry_NAI_ID.grid(row=0, column=1, columnspan=2, padx=100, pady=5, sticky='e')
827
+ if(NAI_ID): entry_NAI_ID.insert(tk.END,NAI_ID)
828
+ NAI_PW_label = tk.Label(NAI_setting_window, text="NAI PW: ")
829
+ NAI_PW_label.grid(row=1, column=0, columnspan=2, sticky='w')
830
+ entry_NAI_PW = tk.Entry(NAI_setting_window, width=50, show="*")
831
+ entry_NAI_PW.grid(row=1, column=1, columnspan=2, padx=100, pady=5, sticky='e')
832
+
833
+ def NAI_connect(button, connect_button):
834
+ global access_token, NAI_ID
835
+ username = entry_NAI_ID.get().strip()
836
+ password = entry_NAI_PW.get().strip()
837
+ access_key = get_access_key(username, password)
838
+ try:
839
+ access_token = login(access_key)
840
+ access_result = requests.get("https://api.novelai.net/user/information", headers={ "Authorization": f"Bearer {access_token}" })
841
+ NAI_State_label.config(text="(๋กœ๊ทธ์ธ ์„ฑ๊ณต, ๋‹ซ๊ธฐ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š”.)", fg="blue")
842
+ button.config(state=tk.DISABLED)
843
+ button_generate.config(state="normal")
844
+ connect_button.config(state=tk.DISABLED)
845
+ NAI_ID = username
846
+ except Exception as e:
847
+ print(e)
848
+ NAI_close()
849
+
850
+ connect_button = tk.Button(NAI_setting_window, text="์—ฐ๊ฒฐ", command=lambda: NAI_connect(button, connect_button))
851
+ connect_button.grid(row=2, column=1, columnspan=2, padx=5, pady=5, sticky='w')
852
+ close_button = tk.Button(NAI_setting_window, text="๋‹ซ๊ธฐ", command=NAI_close)
853
+ close_button.grid(row=2, column=2, columnspan=2, padx=5, pady=5, sticky='w')
854
+ NAI_State_label = tk.Label(NAI_setting_window, text="ํ•ด๋‹น ์ ‘์†๊ธฐ๋Šฅ์€ ์ •์ƒ์ ์ธ ์ ‘์† ํŒจํ„ด์ด ์•„๋‹Œ์  ์ฐธ๊ณ  ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.", fg="red")
855
+ NAI_State_label.grid(row=3, column=1, sticky='ew')
856
+
857
+ def on_resolution_change(*args):
858
+ global NAI_width, NAI_height
859
+ resolution = selected_resolution.get()
860
+ NAI_width, NAI_height = resolution.split(' x ')
861
+
862
+ def on_option_select(value):
863
+ global current_sampler
864
+ current_sampler = value
865
+
866
+ def open_file_explorer():
867
+ output_file_path = "output_NAI"
868
+ if os.path.exists(output_file_path):
869
+ os.startfile(output_file_path)
870
+
871
+ def on_generate_event(event):
872
+ global running_flag
873
+ if not (running_flag):
874
+ NAI_generation(NAI_width, NAI_height, button_generate)
875
+ running_flag = True
876
+
877
+ def random_artist_management():
878
+ global top_100_keywords, top_100_counts, cached_rows
879
+ if not cached_rows: return
880
+ if not (top_100_keywords):
881
+ if not os.path.exists("counting_result.txt"):
882
+ keyword_counts = analyze_cached_rows(cached_rows)
883
+ excluded_keywords = set(whitelist[:2974])
884
+ with open("counting_result.txt", "w") as file:
885
+ for keyword, count in sorted(keyword_counts.items(), key=lambda item: item[1], reverse=True):
886
+ if keyword not in excluded_keywords and keyword in afilter_30000:
887
+ file.write(f"{keyword}: {count}\n")
888
+ with open("counting_result.txt", "r") as file:
889
+ lines = file.readlines()
890
+ top_100_data = [
891
+ (line.split(":")[0].strip(), int(line.split(":")[1].strip()))
892
+ for line in lines[:3000]
893
+ if line.split(":")[0].strip() in afilter_30000[:8528]
894
+ ]
895
+ top_100_keywords, top_100_counts = zip(*top_100_data) if top_100_data else ([], [])
896
+ elif (not top_100_keywords):
897
+ with open("counting_result.txt", "r") as file:
898
+ lines = file.readlines()
899
+ top_100_data = [
900
+ (line.split(":")[0].strip(), int(line.split(":")[1].strip()))
901
+ for line in lines[:3000]
902
+ if line.split(":")[0].strip() in afilter_30000[:8528]
903
+ ]
904
+ top_100_keywords, top_100_counts = zip(*top_100_data) if top_100_data else ([], [])
905
+
906
+ # top_100_keywords ๋‚ด์˜
907
+ # ์ƒˆ ์ฐฝ ์ƒ์„ฑ
908
+ random_artist_window = tk.Toplevel(window)
909
+
910
+ # ์ฒซ ๋ฒˆ์งธ Text Output Box ์„ค์ •
911
+ text_output1 = tk.Text(random_artist_window, height=40, width=50)
912
+ text_output1.pack(padx=10, pady=10)
913
+ for keyword, count in zip(top_100_keywords, top_100_counts):
914
+ text_output1.insert(tk.END, f"{keyword}: {count}\n")
915
+
916
+ def update_lists():
917
+ # Text ์œ„์ ฏ์—์„œ ๋‚ด์šฉ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
918
+ content = text_output1.get("1.0", tk.END)
919
+ lines = content.strip().split("\n") # ์ค„๋ฐ”๊ฟˆ์œผ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
920
+
921
+ # ๊ฐฑ์‹ ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋‘ ๊ฐœ์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
922
+ updated_keywords = []
923
+ updated_counts = []
924
+
925
+ # ๊ฐ ์ค„์„ ์ฒ˜๋ฆฌ๏ฟฝ๏ฟฝ๏ฟฝ์—ฌ ๋ฆฌ์ŠคํŠธ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
926
+ for line in lines:
927
+ if line: # ๋นˆ ์ค„์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
928
+ parts = line.split(":")
929
+ if len(parts) == 2: # "ํ‚ค์›Œ๋“œ: ์นด์šดํŠธ" ํ˜•์‹์ด ๋งž๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
930
+ updated_keywords.append(parts[0].strip())
931
+ updated_counts.append(int(parts[1].strip()))
932
+
933
+ # ์ „์—ญ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.
934
+ global top_100_keywords, top_100_counts
935
+ top_100_keywords = updated_keywords
936
+ top_100_counts = updated_counts
937
+ with open("random_artist_keywords_"+str(len(top_100_keywords))+".txt", "w") as f:
938
+ for keyword in updated_keywords:
939
+ f.write('100: artist:'+keyword + "\n")
940
+
941
+ # ๋ฒ„ํŠผ๋“ค์„ ๋‹ด์„ ํ”„๋ ˆ์ž„ ์ƒ์„ฑ
942
+ buttons_frame = tk.Frame(random_artist_window)
943
+ buttons_frame.pack(pady=10)
944
+
945
+ # '์ €์žฅ' ๋ฒ„ํŠผ์„ ํ”„๋ ˆ์ž„์˜ ์™ผ์ชฝ์— ๋ฐฐ์น˜
946
+ save_button = tk.Button(buttons_frame, text="์ €์žฅ", command=update_lists)
947
+ save_button.pack(side=tk.LEFT, padx=5)
948
+
949
+ # '๋‹ซ๊ธฐ' ๋ฒ„ํŠผ์„ ํ”„๋ ˆ์ž„์˜ ์˜ค๋ฅธ์ชฝ์— ๋ฐฐ์น˜
950
+ close_button = tk.Button(buttons_frame, text="๋‹ซ๊ธฐ", command=random_artist_window.destroy)
951
+ close_button.pack(side=tk.RIGHT, padx=5)
952
+
953
+ random_artist_label = tk.Label(random_artist_window, text='์ž‘๊ฐ€์ด๋ฆ„ ์ด '+str(len(top_100_keywords))+'๊ฐœ, ์ €์žฅ์œ„์น˜: exeํŒŒ์ผ ์œ„์น˜')
954
+ random_artist_label.pack()
955
+
956
+ def open_wildcard_setting():
957
+ # ์ƒˆ ์ฐฝ ์ƒ์„ฑ
958
+ wildcard_window = tk.Toplevel(window)
959
+ wildcard_window.title("์™€์ผ๋“œ ์นด๋“œ ์„ค์ •")
960
+
961
+ # ์ž‘๊ฐ€๋ช… ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
962
+ artist_label = tk.Label(wildcard_window, text="์ž‘๊ฐ€๋ช… ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ->")
963
+ artist_label.grid(row=0, column=0)
964
+ artist_button = tk.Button(wildcard_window, text="์—ด๊ธฐ", command=lambda: load_wildcard(artist_text, wildcard_window))
965
+ artist_button.grid(row=0, column=1)
966
+
967
+ artist_text = tk.Text(wildcard_window, height=15, width=60)
968
+ artist_text.grid(row=1, column=0, columnspan=2)
969
+
970
+ # ์บ๋ฆญํ„ฐ ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
971
+ character_label = tk.Label(wildcard_window, text="์บ๋ฆญํ„ฐ ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ->")
972
+ character_label.grid(row=2, column=0)
973
+ character_button = tk.Button(wildcard_window, text="์—ด๊ธฐ", command=lambda: load_wildcard(character_text, wildcard_window))
974
+ character_button.grid(row=2, column=1)
975
+
976
+ character_text = tk.Text(wildcard_window, height=15, width=60)
977
+ character_text.grid(row=3, column=0, columnspan=2)
978
+
979
+ # ๋ฒ„ํŠผ๋“ค
980
+ buttons_frame = tk.Frame(wildcard_window)
981
+ buttons_frame.grid(row=4, column=0, columnspan=2)
982
+
983
+ text_label = tk.Label(wildcard_window, text="wildcard ๋ฌธ๋ฒ•(์ž‘๊ฐ€):\noffset:wildcard1 150:null (helloworld)\noffset:wildcard2 100:none (goodbye)\n์—†์œผ๋ฉด 100: ์œผ๋กœ ๊ฐ„์ฃผ\noffset/offset ์ดํ•ฉ: wildcard ํ™•๋ฅ ")
984
+ text_label.grid(row=5, column=0,sticky='ew')
985
+ 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...")
986
+ text_label2.grid(row=6, column=0,sticky='ew')
987
+
988
+ load_button = tk.Button(buttons_frame, text="์™€์ผ๋“œ์นด๋“œ ํƒ‘์žฌ", command=lambda: apply_wildcard(artist_text, character_text, wildcard_window))
989
+ load_button.pack(side=tk.LEFT, padx=10)
990
+
991
+ close_button = tk.Button(buttons_frame, text="๋‹ซ๊ธฐ", command=wildcard_window.destroy)
992
+ close_button.pack(side=tk.RIGHT, padx=10)
993
+
994
+ def apply_wildcard(artist_text, character_text, window):
995
+ artist_wildcard_check = artist_text.get("1.0", tk.END)
996
+ if len(artist_wildcard_check) > 5:
997
+ lines = artist_wildcard_check.strip().split("\n")
998
+ akeywords = []
999
+ current_index = 0
1000
+ for line in lines:
1001
+ parts = line.strip().split(':', 1)
1002
+ if len(parts) == 2 and parts[0].strip().isdigit():
1003
+ weight = int(parts[0].strip())
1004
+ else:
1005
+ weight = 100
1006
+ parts = ['100', line.strip()] # '100:'์„ ์•ž์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
1007
+ keyword = parts[1].strip()
1008
+ akeywords.append((current_index, current_index + weight - 1, keyword))
1009
+ current_index += weight
1010
+ global artist_wildcard
1011
+ artist_wildcard = akeywords
1012
+ check_wildcard.config(state='normal')
1013
+
1014
+ character_wildcard_check = character_text.get("1.0", tk.END)
1015
+ if len(character_wildcard_check) > 5:
1016
+ lines = character_wildcard_check.strip().split("\n")
1017
+ ckeywords = []
1018
+ current_index = 0
1019
+ for line in lines:
1020
+ parts = line.strip().split(':', 1)
1021
+ if len(parts) == 2 and parts[0].strip().isdigit():
1022
+ weight = int(parts[0].strip())
1023
+ else:
1024
+ weight = 100
1025
+ parts = ['100', line.strip()] # '100:'์„ ์•ž์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
1026
+ keyword = parts[1].strip()
1027
+ ckeywords.append((current_index, current_index + weight - 1, keyword))
1028
+ current_index += weight
1029
+ global character_wildcard
1030
+ character_wildcard = ckeywords
1031
+ check_wildcard2.config(state='normal')
1032
+
1033
+ window.destroy()
1034
+
1035
+
1036
+ def load_wildcard(text_widget, window):
1037
+ window.iconify()
1038
+ filepath = filedialog.askopenfilename(filetypes=[("ํ…์ŠคํŠธ ํŒŒ์ผ", "*.txt")])
1039
+ if filepath:
1040
+ with open(filepath, 'r', encoding='utf-8') as file:
1041
+ lines = file.readlines()
1042
+ updated_lines = []
1043
+ for line in lines:
1044
+ line = line.strip()
1045
+ if ':' in line:
1046
+ prefix, _ = line.split(':', 1)
1047
+ if not prefix.strip().isdigit():
1048
+ line = f"100: {line}"
1049
+ else:
1050
+ line = f"100: {line}"
1051
+ updated_lines.append(line)
1052
+
1053
+ text_widget.delete('1.0', tk.END)
1054
+ text_widget.insert('1.0', '\n'.join(updated_lines))
1055
+ window.deiconify()
1056
+
1057
+ def find_keyword(index, keywords):
1058
+ for start, end, keyword in keywords:
1059
+ if start <= index <= end:
1060
+ print(keyword)
1061
+ return keyword
1062
+ return None
1063
+
1064
+ def get_random_keyword(req_keyword):
1065
+ #called from artist_wildcard, character_wildcard
1066
+ global artist_wildcard, character_wildcard
1067
+ if(req_keyword == 'artist'): keywords = artist_wildcard
1068
+ elif(req_keyword == 'character'): keywords = character_wildcard
1069
+ print('lenghth = ',len(keywords))
1070
+ max_index = keywords[-1][1]
1071
+ print(len(keywords))
1072
+ random_index = random.randint(0, max_index)
1073
+ print(random_index)
1074
+ return find_keyword(random_index, keywords)
1075
+
1076
+ on_press_flag = False
1077
+ window = tk.Tk()
1078
+ window.title("Prompt Selector for Danbooru tags")
1079
+ last_deep_search_keywords = None
1080
+ cached_rows = []
1081
+ total_rows = 0
1082
+ last_selected_row_keywords = ['1girl','nahida (genshin impact)', 'looking at viewer', 'garden']
1083
+ top_100_keywords = []
1084
+ top_100_counts = []
1085
+ previous_artist = None
1086
+ listener = None
1087
+ current_keys = set()
1088
+ click_count = 0
1089
+ access_token = None
1090
+ temp_clipboard_image = None
1091
+ NAI_width = 1024
1092
+ NAI_height = 1024
1093
+ current_sampler = "k_euler_ancestral"
1094
+ running_flag = False
1095
+ NAI_ID = None
1096
+ artist_wildcard = []
1097
+ character_wildcard =[]
1098
+
1099
+ whitelist = wlist.whitelist
1100
+ bag_of_tags = tagbag.bag_of_tags
1101
+ afilter_30000 = arti_list.afilter_30000
1102
+
1103
+ current_wildcard_artist = []
1104
+ current_wildcard_character = []
1105
+
1106
+ GENERATE_EVENT = "<<GenerateEvent>>"
1107
+ window.bind(GENERATE_EVENT, on_generate_event)
1108
+
1109
+ left_frame = tk.Frame(window)
1110
+ left_frame.grid(row=0, column=0, sticky="nsew")
1111
+ #left_frame.grid_columnconfigure(0, weight=1)
1112
+ right_frame = tk.Frame(window)
1113
+ right_frame.grid(row=0, column=1, sticky="nsew")
1114
+ window.grid_columnconfigure(0, weight=1)
1115
+ window.grid_columnconfigure(1, weight=1)
1116
+
1117
+ #ํŒŒ์ผ ๊ฒฝ๋กœ ๋ฐ ํ‚ค์›Œ๋“œ ์ž…๋ ฅ์ฐฝ ๊ทธ๋ฆฌ๋“œ ๊ด€๋ฆฌ
1118
+ frame_row0 = tk.Frame(left_frame)
1119
+ frame_row0.grid(row=0, column=0, padx=5, pady=5, sticky='w')
1120
+
1121
+ # ํŒŒ์ผ ๊ฒฝ๋กœ ์ž…๋ ฅ์ฐฝ
1122
+ label_file_path = tk.Label(frame_row0, text="CSV ํŒŒ์ผ ๊ฒฝ๋กœ:")
1123
+ label_file_path.grid(row=0, column=0, sticky='w')
1124
+ entry_file_path = tk.Entry(frame_row0, width=55)
1125
+ entry_file_path.grid(row=0, column=1, columnspan=4, padx=5, pady=5, sticky='ew')
1126
+ button_open_file = tk.Button(frame_row0, text="ํŒŒ์ผ ์—ด๊ธฐ", command=open_file)
1127
+ button_open_file.grid(row=0, column=5, padx=5, pady=6, sticky='e')
1128
+
1129
+ # ํ‚ค์›Œ๋“œ ์ž…๋ ฅ์ฐฝ
1130
+ keyword_label = tk.Label(frame_row0, text="์ดˆ๊ธฐํ™” ํ‚ค์›Œ๋“œ: ")
1131
+ keyword_label.grid(row=1, column=0, sticky='w')
1132
+ entry_keyword = tk.Entry(frame_row0)
1133
+ entry_keyword.grid(row=1, column=1, columnspan=4, padx=5, pady=5, sticky='ew')
1134
+ button_export_csv = tk.Button(frame_row0, text=".csv ๋‚ด๋ณด๋‚ด๊ธฐ", command=export_csv)
1135
+ button_export_csv.grid(row=1, column=5, padx=5, pady=6, sticky='e')
1136
+
1137
+ # ๋ฒ„ํŠผ ํ”„๋ ˆ์ž„
1138
+ frame_buttons = tk.Frame(left_frame)
1139
+ frame_buttons.grid(row=1, column=0, sticky='ew')
1140
+ frame_buttons.columnconfigure(0, weight=1) # ์™ผ์ชฝ์— ๊ฐ€์ค‘์น˜ ๋ถ€์—ฌ
1141
+ frame_buttons.columnconfigure(1, weight=0) # ๋ฒ„ํŠผ ์—ด์€ ๊ฐ€์ค‘์น˜ ์—†์Œ
1142
+ frame_buttons.columnconfigure(2, weight=0) # ๋ฒ„ํŠผ ์—ด์€ ๊ฐ€์ค‘์น˜ ์—†์Œ
1143
+ frame_buttons.columnconfigure(3, weight=1) # ์˜ค๋ฅธ์ชฝ์— ๊ฐ€์ค‘์น˜ ๋ถ€์—ฌ
1144
+
1145
+ # ๋ฒ„ํŠผ๋“ค
1146
+ button_search = tk.Button(frame_buttons, text="ํ•ด๋‹น ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰", command=search)
1147
+ button_search.grid(row=0, column=1, padx=5, sticky='ew') # ๋ณ€๊ฒฝ: column=1
1148
+ button_exclude = tk.Button(frame_buttons, text="ํ•ด๋‹น ํ‚ค์›Œ๋“œ ์ œ์™ธ", command=exclude)
1149
+ button_exclude.grid(row=0, column=2, padx=5, sticky='ew') # ๋ณ€๊ฒฝ: column=2
1150
+
1151
+ total_rows_count_label = tk.Label(frame_buttons, text=".csv ๋‚ด ํ”„๋กฌํ”„ํŠธ ํ–‰: 0")
1152
+ total_rows_count_label.grid(row=0, column=3, padx=5, sticky='ew')
1153
+
1154
+ # ์‹ฌ์ธต๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ ์ž…๋ ฅ์ฐฝ
1155
+ deep_search_frame = tk.Frame(left_frame)
1156
+ deep_search_frame.grid(row=2, column=0, pady=10, sticky='w')
1157
+ deep_search_frame.columnconfigure(0, weight=2)
1158
+ deep_search_frame.columnconfigure(1, weight=2)
1159
+ deep_search_frame.columnconfigure(2, weight=1)
1160
+
1161
+ label_deep_search = tk.Label(deep_search_frame, text="์‹ฌ์ธต๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ ์ž…๋ ฅ: key,*key,~key,{key1|key2} ")
1162
+ label_deep_search.grid(row=0, column=0, sticky='w')
1163
+
1164
+ # Tkinter UI ์„ค์ • ๋ถ€๋ถ„์— ๋ ˆ์ด๋ธ” ์ถ”๊ฐ€
1165
+ cached_rows_count_label = tk.Label(deep_search_frame, text="์‹ฌ์ธต๊ฒ€์ƒ‰ ํ”„๋กฌํ”„ํŠธ ํ–‰: 0")
1166
+ cached_rows_count_label.grid(row=0, column=1, padx=5, sticky='w')
1167
+
1168
+ button_export_deep_csv = tk.Button(deep_search_frame, text=".csv ๋‚ด๋ณด๋‚ด๊ธฐ", command=export_csv_search)
1169
+ button_export_deep_csv.grid(row=0, column=2, padx=5, sticky='e')
1170
+
1171
+ entry_deep_search = tk.Entry(deep_search_frame, width=82)
1172
+ entry_deep_search.grid(row=1, column=0, columnspan=3,padx=5, pady=5, sticky='ew')
1173
+
1174
+ # ๋ฒ„ํŠผ๋“ค์„ ํฌํ•จํ•  ํ”„๋ ˆ์ž„ ์ƒ์„ฑ
1175
+ button_frame = tk.Frame(left_frame)
1176
+ button_frame.grid(row=5, column=0, padx=5, pady=5, sticky='w')
1177
+
1178
+ # ๋ฒ„ํŠผ ํ”„๋ ˆ์ž„ ๋‚ด์˜ ์—ด ์„ค์ •
1179
+ button_frame.columnconfigure(0, weight=1)
1180
+ button_frame.columnconfigure(1, weight=1)
1181
+ button_frame.columnconfigure(2, weight=1)
1182
+ button_frame.columnconfigure(3, weight=1)
1183
+ button_frame.columnconfigure(4, weight=1)
1184
+ button_frame.columnconfigure(5, weight=1)
1185
+ button_frame.columnconfigure(6, weight=1)
1186
+
1187
+ # "๋žœ๋ค" ๋ฒ„ํŠผ
1188
+ button_random = tk.Button(button_frame, text="๋žœ๋ค", command=random_function)
1189
+ button_random.grid(row=0, column=0, sticky='ew')
1190
+
1191
+ # "ํ”„๋กฌํ”„ํŠธ ๊ณ ์ •" ํ† ๊ธ€ ๋ฒ„ํŠผ
1192
+ toggle_prompt_var = tk.IntVar()
1193
+ button_toggle_prompt = tk.Checkbutton(button_frame, text="ํ”„๋กฌํ”„ํŠธ ๊ณ ์ •", variable=toggle_prompt_var)
1194
+ button_toggle_prompt.grid(row=0, column=1, sticky='ew')
1195
+
1196
+ # "์ž๋™ ๋ณต์‚ฌ" ์ฒดํฌ๋ฐ•์Šค
1197
+ auto_copy_var = tk.IntVar()
1198
+ check_auto_copy = tk.Checkbutton(button_frame, text="์ž๋™ ๋ณต์‚ฌ", variable=auto_copy_var)
1199
+ check_auto_copy.grid(row=0, column=2, sticky='ew')
1200
+
1201
+ # "๋ณต์‚ฌ" ๋ฒ„ํŠผ
1202
+ button_copy = tk.Button(button_frame, text="๋ณต์‚ฌ", command=copy_to_clipboard)
1203
+ button_copy.grid(row=0, column=3, sticky='ew')
1204
+
1205
+ # "์ข…๋ฃŒ" ๋ฒ„ํŠผ
1206
+ button_exit = tk.Button(button_frame, text="์ข…๋ฃŒ", command=exit_program)
1207
+ button_exit.grid(row=0, column=4, sticky='ew')
1208
+
1209
+ # "์ƒ์„ฑ" ๋ฒ„ํŠผ
1210
+ button_generate = tk.Button(button_frame, text="NAI ์š”์ฒญ", command=lambda: NAI_generation(NAI_width, NAI_height, button_generate))
1211
+ button_generate.grid(row=0, column=5, sticky='ew')
1212
+ button_generate.config(state='disabled')
1213
+
1214
+ # "์„ค์ •" ๋ฒ„ํŠผ
1215
+ button_setting = tk.Button(button_frame, text="NAI ๋กœ๊ทธ์ธ ์„ค์ •", command=lambda: NAI_setting(button_setting, button_generate))
1216
+ button_setting.grid(row=0, column=6, sticky='ew')
1217
+
1218
+ mac_var = tk.IntVar()
1219
+ mac_button = tk.Checkbutton(button_frame, text="์ž๋™์ƒ์„ฑ", variable=mac_var)
1220
+ mac_button.grid(row=0, column=7, sticky='ew')
1221
+
1222
+ # ํ…์ŠคํŠธ ๋ฐ ๊ณ ์ • ํ”„๋กฌํ”„ํŠธ ๋„ค๊ฑฐํ‹ฐ๋ธŒ ๋“ฑ ํ”„๋กฌํ”„ํŠธ ์ฐฝ
1223
+ text_frame = tk.Frame(left_frame)
1224
+ text_frame.grid(row=6, column=0, padx=5, pady=5, sticky='w')
1225
+ text_frame.columnconfigure(0, weight=1)
1226
+ text_frame.columnconfigure(1, weight=7)
1227
+
1228
+ text_frame2 = tk.Frame(left_frame)
1229
+ text_frame2.grid(row=8, column=0, padx=5, pady=5, sticky='w')
1230
+ text_frame2.columnconfigure(0, weight=1)
1231
+ text_frame2.columnconfigure(1, weight=7)
1232
+
1233
+ _size = get_max_size()
1234
+
1235
+ # ์ถœ๋ ฅ ํ…์ŠคํŠธ ์ฐฝ
1236
+ text_output_label = tk.Label(text_frame, text="ํ”„๋กฌํ”„ํŠธ", borderwidth=1, relief="solid",height=6)
1237
+ text_output_label.grid(row=0, column=0, padx=5, pady=5, sticky='w')
1238
+ if _size<=768: text_output_width = 74
1239
+ else: text_output_width = 65
1240
+ text_output = tk.Text(text_frame, width=text_output_width, height=7)
1241
+ text_output.grid(row=0, column=1, sticky='ew')
1242
+
1243
+ fixed_prompt_frame = tk.Frame(left_frame)
1244
+ fixed_prompt_frame.grid(row=7, column=0, padx=5, pady=5, sticky='w')
1245
+ fixed_prompt_frame.columnconfigure(0, weight=1)
1246
+ fixed_prompt_frame.columnconfigure(1, weight=1)
1247
+
1248
+ fixed_prompt_label_left = tk.Label(fixed_prompt_frame, text="์„ ํ–‰ ๊ณ ์ • ํ”„๋กฌํ”„ํŠธ (ํ”„๋กฌํ”„ํŠธ ์•ž)")
1249
+ fixed_prompt_label_left.grid(row=0, column=0, sticky='ew')
1250
+ fixed_prompt_label_right = tk.Label(fixed_prompt_frame, text="ํ›„ํ–‰ ๊ณ ์ • ํ”„๋กฌํ”„ํŠธ (ํ”„๋กฌํ”„ํŠธ ๋’ค)")
1251
+ fixed_prompt_label_right.grid(row=0, column=1, sticky='ew')
1252
+ entry_fixed_prompt = tk.Entry(fixed_prompt_frame, width=40)
1253
+ entry_fixed_prompt.grid(row=1, column=0,padx=5, pady=5, sticky='ew')
1254
+ entry_fixed_prompt_after = tk.Entry(fixed_prompt_frame, width=40)
1255
+ entry_fixed_prompt_after.grid(row=1, column=1, padx=5, pady=5, sticky='ew')
1256
+
1257
+ # ๋„ค๊ฑฐํ‹ฐ๋ธŒ ํ”„๋กฌํ”„ํŠธ
1258
+ NP_label = tk.Label(text_frame2, text="๋„ค๊ฑฐํ‹ฐ๋ธŒ\nํ”„๋กฌํ”„ํŠธ", borderwidth=1, relief="solid",height=2)
1259
+ NP_label.grid(row=0,column=0, padx=5, pady=5, sticky='ew')
1260
+ negative_text = tk.Text(text_frame2, width=65, height=3)
1261
+ negative_text.grid(row=0, column=1, padx=5, pady=5, sticky='w')
1262
+
1263
+ auto_hide_frame = tk.Frame(left_frame)
1264
+ auto_hide_frame.grid(row=9, column=0, padx=5, pady=5, sticky='w')
1265
+ auto_hide_frame.columnconfigure(0, weight=2)
1266
+ auto_hide_frame.columnconfigure(1, weight=2)
1267
+ auto_hide_frame.columnconfigure(2, weight=1)
1268
+
1269
+ # ์ž๋™ ์ˆจ๊น€ ํ‚ค์›Œ๋“œ ๋ผ๋ฒจ๊ณผ ์ž…๋ ฅ์ฐฝ ์ถ”๊ฐ€
1270
+ auto_hide_label = tk.Label(auto_hide_frame, text="์ž๋™ ์ˆจ๊น€ ํ‚ค์›Œ๋“œ: keyword1, keyword2, ...")
1271
+ auto_hide_label.grid(row=0, column=0, sticky='w')
1272
+ entry_auto_hide = tk.Entry(auto_hide_frame, width=82)
1273
+ entry_auto_hide.grid(row=1, column=0, columnspan=3, padx=5, pady=5, sticky='ew')
1274
+ # ์ถ”์ฒœ ํ”„๋กฌํ”„ํŠธ ์กฐํšŒ ๋ฒ„ํŠผ ์„ค์ •
1275
+ recommend_prompt_button = tk.Button(auto_hide_frame, text="์ถ”์ฒœ ํ”„๋กฌํ”„ํŠธ", command=open_prompt_window)
1276
+ recommend_prompt_button.grid(row=0, column=2, padx=2, pady=5, sticky='e') # sticky ์˜ต์…˜์„ 'e'๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ์˜ค๋ฅธ์ชฝ ์ •๋ ฌ
1277
+
1278
+
1279
+ # ์ฒดํฌ๋ฐ•์Šค๋“ค์„ ํฌํ•จํ•  ํ”„๋ ˆ์ž„ ์ƒ์„ฑ
1280
+ checkbox_frame = tk.Frame(left_frame)
1281
+ checkbox_frame.grid(row=10, column=0, pady=15, sticky='ew')
1282
+ checkbox_frame2 = tk.Frame(left_frame)
1283
+ checkbox_frame2.grid(row=10, column=1, padx=5, pady=15, sticky='ew')
1284
+
1285
+ # ์ฒดํฌ๋ฐ•์Šค ํ”„๋ ˆ์ž„ ๋‚ด์˜ ์—ด ์„ค์ •
1286
+ checkbox_frame.columnconfigure(0, weight=1)
1287
+ checkbox_frame.columnconfigure(1, weight=1)
1288
+ checkbox_frame.columnconfigure(2, weight=1)
1289
+ checkbox_frame.columnconfigure(3, weight=1)
1290
+ checkbox_frame.columnconfigure(4, weight=1)
1291
+ checkbox_frame.columnconfigure(5, weight=1)
1292
+
1293
+
1294
+ # "์ž‘๊ฐ€๋ช… ์ œ๊ฑฐ" ์ฒดํฌ๋ฐ•์Šค
1295
+ remove_artist_var = tk.IntVar() # ์ฒดํฌ๋ฐ•์Šค ์ƒํƒœ๋ฅผ ์ €์žฅํ•  ๋ณ€์ˆ˜
1296
+ check_remove_artist = tk.Checkbutton(checkbox_frame, text="์ž‘๊ฐ€๋ช… ์ œ๊ฑฐ", variable=remove_artist_var)
1297
+ check_remove_artist.grid(row=0, column=0, sticky='ew')
1298
+
1299
+ # "๋žœ๋ค ์ž‘๊ฐ€ ์ถ”๊ฐ€" ์ฒดํฌ๋ฐ•์Šค
1300
+ random_artist_var = tk.IntVar()
1301
+ check_random_artist = tk.Checkbutton(checkbox_frame, text="๋žœ๋ค ์ž‘๊ฐ€ ์ถ”๊ฐ€", variable=random_artist_var)
1302
+ check_random_artist.grid(row=0, column=1, sticky='ew')
1303
+
1304
+ # ๋žœ๋ค์ž‘๊ฐ€ ๊ด€๋ฆฌ
1305
+ random_artist_setting = tk.Button(checkbox_frame, text="๋žœ๋ค ์ž‘๊ฐ€ ๊ด€๋ฆฌ", command=random_artist_management) #output_file_path
1306
+ random_artist_setting.grid(row=0, column=2, sticky='ew')
1307
+
1308
+ # "์บ๋ฆญํ„ฐ ํŠน์ง• ์ œ๊ฑฐ" ์ฒดํฌ๋ฐ•์Šค
1309
+ rm_characteristic_var = tk.IntVar()
1310
+ rm_characteristic_label = tk.Checkbutton(checkbox_frame, text="์บ๋ฆญํ„ฐ ํŠน์ง• ์ œ๊ฑฐ", variable=rm_characteristic_var)
1311
+ rm_characteristic_label.grid(row=0, column=3, sticky='ew')
1312
+
1313
+ # ์™€์ผ๋“œ ์นด๋“œ
1314
+ wildcard_var = tk.IntVar(value= 0)
1315
+ check_wildcard = tk.Checkbutton(checkbox_frame, text="์™€์ผ๋“œ์นด๋“œ(์ž‘๊ฐ€)", variable=wildcard_var, state='disabled')
1316
+ check_wildcard.grid(row=1, column=0, sticky='ew')
1317
+
1318
+ # ์™€์ผ๋“œ ์นด๋“œ2
1319
+ wildcard_var2 = tk.IntVar(value= 0)
1320
+ check_wildcard2 = tk.Checkbutton(checkbox_frame, text="์™€์ผ๋“œ์นด๋“œ(์บ๋ฆญํ„ฐ)", variable=wildcard_var2, state='disabled')
1321
+ check_wildcard2.grid(row=1, column=1, sticky='ew')
1322
+
1323
+ # ์™€์ผ๋“œ ์นด๋“œ ์„ค์ •
1324
+ widldcard_button = tk.Button(checkbox_frame, text="์™€์ผ๋“œ์นด๋“œ ์„ค์ •", command=open_wildcard_setting) #output_file_path
1325
+ widldcard_button.grid(row=1, column=2, sticky='ew')
1326
+
1327
+ #ํด๋” ํ˜ธ์ถœ ๋ฒ„ํŠผ
1328
+ folder_button = tk.Button(checkbox_frame, text="์ €์žฅ ํด๋”", command=open_file_explorer) #output_file_path
1329
+ folder_button.grid(row=1, column=3, padx=5, sticky='ew')
1330
+
1331
+
1332
+ window.bind('<Control-Return>', on_ctrl_enter)
1333
+ window.bind('<Shift-Return>', on_shift_enter)
1334
+
1335
+ NAI_ID = load_settings()
1336
+ if not (entry_keyword.get()): entry_keyword.insert(0, "1girl")
1337
+ if not (entry_fixed_prompt.get()): entry_fixed_prompt.insert(0, '1girl,')
1338
+ if not (entry_fixed_prompt_after.get()): entry_fixed_prompt_after.insert(0, 'great quality, aesthetic, absurdres')
1339
+ if not (entry_auto_hide.get()): entry_auto_hide.insert(0, 'monochrome, doujin cover, bad source, censored, bar censor')
1340
+ if (len(negative_text.get("1.0")) < 4): negative_text.insert(tk.END,'watermark, blurry, very displeasing, lowres, worst quality, monochrome, bad anatomy, bad hands, censored, {{futanari}}, text, sound effect')
1341
+ print(negative_text.get("1.0"))
1342
+
1343
+ resolution1_frame = tk.Frame(left_frame)
1344
+ resolution1_frame.grid(row=15, column=0, padx=5, pady=5, sticky='ew')
1345
+ resolution2_frame = tk.Frame(left_frame)
1346
+ resolution2_frame.grid(row=16, column=0, padx=5, pady=5, sticky='ew')
1347
+ selected_resolution = tk.StringVar(value="1024 x 1024")
1348
+ tk.Radiobutton(resolution1_frame, text="1024 x 1024", variable=selected_resolution, value="1024 x 1024").grid(row=0, column=0, sticky='w')
1349
+ tk.Radiobutton(resolution1_frame, text="960 x 1088", variable=selected_resolution, value="960 x 1088").grid(row=0, column=1, sticky='w')
1350
+ tk.Radiobutton(resolution1_frame, text="896 x 1152", variable=selected_resolution, value="896 x 1152").grid(row=0, column=2, sticky='w')
1351
+ tk.Radiobutton(resolution1_frame, text="832 x 1216", variable=selected_resolution, value="832 x 1216").grid(row=0, column=3, sticky='w')
1352
+ tk.Radiobutton(resolution2_frame, text="1088 x 960", variable=selected_resolution, value="1088 x 960").grid(row=0, column=0, sticky='w')
1353
+ tk.Radiobutton(resolution2_frame, text="1152 x 896", variable=selected_resolution, value="1152 x 896").grid(row=0, column=1, sticky='w')
1354
+ tk.Radiobutton(resolution2_frame, text="1216 x 832", variable=selected_resolution, value="1216 x 832").grid(row=0, column=2, sticky='w')
1355
+ selected_resolution.trace_add('write', on_resolution_change)
1356
+
1357
+ sema_button_var = tk.IntVar(value=1)
1358
+ sema_button = tk.Checkbutton(resolution1_frame, text="SEMA", variable=sema_button_var)
1359
+ sema_button.grid(row=0, column=5, sticky='w')
1360
+
1361
+ dyn_button_var = tk.IntVar()
1362
+ dyn_button = tk.Checkbutton(resolution1_frame, text="+DYN", variable=dyn_button_var)
1363
+ dyn_button.grid(row=0, column=6, sticky='w')
1364
+
1365
+ entry_CFG_value = tk.StringVar()
1366
+ entry_CFG_label = tk.Label(resolution2_frame, text=" CFG Scale : ", justify=tk.LEFT)
1367
+ entry_CFG_label.grid(row=0, column=4, sticky='w')
1368
+ entry_CFG_value.set("5.0")
1369
+
1370
+ entry_CFG = tk.Entry(resolution2_frame, width=5, textvariable=entry_CFG_value)
1371
+ entry_CFG.grid(row=0, column=5, sticky='w')
1372
+
1373
+ options = ["k_euler", "k_euler_ancestral", "k_dpmpp_2s_ancestral", "k_dpmpp_sde"]
1374
+ selected_option = tk.StringVar()
1375
+ selected_option.set(options[1])
1376
+ option_menu = tk.OptionMenu(resolution2_frame, selected_option, *options, command=on_option_select)
1377
+ option_menu.grid(row=0, column=6, padx=5, sticky='ew')
1378
+
1379
+
1380
+
1381
+
1382
+
1383
+
1384
+
1385
+ image_label = tk.Label(right_frame, relief='solid', borderwidth=1)
1386
+ image_label.grid(row=0, column=0, rowspan=15, padx=10, pady=10, sticky="n")
1387
+
1388
+ # ์ €๋นˆ๋„ ํ‚ค์›Œ๋“œ ์ž๋™์ถ”๊ฐ€ ๋ฒ„ํŠผ ์ถ”๊ฐ€
1389
+ btn_add_low_freq = tk.Button(right_frame, text="์ด๋ฏธ์ง€๋ฅผ ํด๋ฆฝ๋ณด๋“œ์— ๋ณต์‚ฌ", fg="blue", command=copy_image_to_clipboard)
1390
+ btn_add_low_freq.grid(row=16, column=0, padx=5, pady=5, sticky='ew')
1391
+
1392
+ # ํ•˜์–€์ƒ‰ ์ด๋ฏธ์ง€ ์ƒ์„ฑ
1393
+ white_image = Image.new('RGB', (_size, _size), 'white')
1394
+ white_photo = ImageTk.PhotoImage(white_image)
1395
+
1396
+ # ๋ผ๋ฒจ์— ์ด๋ฏธ์ง€ ์„ค์ •
1397
+ image_label.config(image=white_photo)
1398
+ image_label.image = white_photo
1399
+
1400
+ # ๋ฆฌ์Šค๋„ˆ ์‹œ์ž‘
1401
+ listener = keyboard.Listener(on_press=on_press, on_release=on_release)
1402
+ listener.start()
1403
+
1404
+ # ํ‚ค๋ณด๋“œ ๋ฆฌ์Šค๋„ˆ ์Šค๋ ˆ๋“œ ์‹œ์ž‘
1405
+ listener_thread = threading.Thread(target=listener.join, daemon=True)
1406
+ listener_thread.start()
1407
+
1408
+ window.mainloop()