baqu2213 commited on
Commit
ef033f0
ยท
verified ยท
1 Parent(s): 4eea353

Upload NAIA_generation.py

Browse files
Files changed (1) hide show
  1. NAIA/NAIA_2025/NAIA_generation.py +1474 -0
NAIA/NAIA_2025/NAIA_generation.py ADDED
@@ -0,0 +1,1474 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import random
3
+ from PIL import Image, ImageOps, ImageDraw, ImageFont
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+ import io, re, base64, os
7
+ import zipfile
8
+ import math
9
+ import time
10
+ import piexif
11
+ from imghdr import what
12
+
13
+ BASE_URL="https://image.novelai.net"
14
+
15
+ def extract_prompt_info(info, app_mode=""):
16
+ import string
17
+
18
+ # EXIF UserComment ๋””์ฝ”๋”ฉ ํ•จ์ˆ˜
19
+ def decode_user_comment(exif_dict):
20
+ if 'Exif' in exif_dict and 37510 in exif_dict['Exif']:
21
+ user_comment = exif_dict['Exif'][37510]
22
+ if user_comment.startswith(b'UNICODE\x00\x00'):
23
+ try:
24
+ # UNICODE ํ—ค๋”(8๋ฐ”์ดํŠธ) ์ œ๊ฑฐ ํ›„ UTF-16์œผ๋กœ ๋””์ฝ”๋”ฉ
25
+ unicode_data = user_comment[8:]
26
+ decoded_text = unicode_data.decode('utf-16').replace('\x00', '')
27
+ decoded_text = decoded_text.replace("UNICODE", "")
28
+ return re.sub(f"[^{string.printable}]", "", decoded_text)
29
+ except UnicodeDecodeError:
30
+ return None
31
+ return None
32
+
33
+ try:
34
+ # 1. NAI ๋ชจ๋“œ์ธ ๊ฒฝ์šฐ Comment ํ•„๋“œ ํ™•์ธ
35
+ if app_mode == "NAI":
36
+ return info.get('Comment', '')
37
+
38
+ # 2. parameters ํ•„๋“œ ํ™•์ธ
39
+ if 'parameters' in info:
40
+ return info['parameters']
41
+
42
+ # 3. EXIF ๋ฐ์ดํ„ฐ ํ™•์ธ
43
+ if 'exif' in info:
44
+ exif_dict = piexif.load(info['exif'])
45
+
46
+ # UserComment์—์„œ ํ”„๋กฌํ”„ํŠธ ์ถ”์ถœ ์‹œ๋„
47
+ decoded_comment = decode_user_comment(exif_dict)
48
+ if decoded_comment:
49
+ return decoded_comment
50
+
51
+ # ๋‹ค๋ฅธ EXIF ํ•„๋“œ์—์„œ๋„ ํ”„๋กฌํ”„ํŠธ ์ฐพ๊ธฐ ์‹œ๋„
52
+ for ifd in exif_dict:
53
+ if ifd == 'thumbnail':
54
+ continue
55
+ if isinstance(exif_dict[ifd], dict):
56
+ for tag, value in exif_dict[ifd].items():
57
+ # ๋ฌธ์ž์—ด์ด๋‚˜ ๋ฐ”์ดํŠธ ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ
58
+ if isinstance(value, (bytes, str)) and value:
59
+ try:
60
+ if isinstance(value, bytes):
61
+ decoded = value.decode('utf-8', errors='ignore')
62
+ else:
63
+ decoded = value
64
+ if decoded and len(decoded) > 10: # ์˜๋ฏธ ์žˆ๋Š” ๊ธธ์ด์˜ ํ…์ŠคํŠธ๋งŒ ๊ณ ๋ ค
65
+ # ์˜์–ด ๋ฐ ์ˆซ์ž ์ด์™ธ์˜ ๋ฌธ์ž๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ํ•„ํ„ฐ๋ง
66
+ return re.sub(f"[^{string.printable}]", "", decoded)
67
+ except:
68
+ continue
69
+
70
+ # 4. ์•„๋ฌด๊ฒƒ๋„ ์ฐพ์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ ๊ธฐ๋ณธ๊ฐ’ ๋ฐ˜ํ™˜
71
+ return "webp or jpeg prompts"
72
+
73
+ except Exception as e:
74
+ print(f"ํ”„๋กฌํ”„ํŠธ ์ถ”์ถœ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}")
75
+ return "webp or jpeg prompts"
76
+
77
+ def find_max_resolution(width, height, max_pixels=1048576, multiple_of=64):
78
+ ratio = int(width) / int(height)
79
+
80
+ max_width = int((max_pixels * ratio)**0.5)
81
+ max_height = int((max_pixels / ratio)**0.5)
82
+
83
+ max_width = (max_width // multiple_of) * multiple_of
84
+ max_height = (max_height // multiple_of) * multiple_of
85
+
86
+ while max_width * max_height > max_pixels:
87
+ max_width -= multiple_of
88
+ max_height = int(max_width / ratio)
89
+ max_height = (max_height // multiple_of) * multiple_of
90
+
91
+ if max_pixels == 1048576:
92
+ attempts = 0
93
+ max_attempts = 10
94
+ while (max_width % multiple_of + max_height % multiple_of) < 32 and attempts < max_attempts:
95
+ if random.choice([True, False]):
96
+ if (max_width + multiple_of) * max_height <= max_pixels:
97
+ max_width += multiple_of
98
+ else:
99
+ if max_width * (max_height + multiple_of) <= max_pixels:
100
+ max_height += multiple_of
101
+ attempts += 1
102
+
103
+ return (str(max_width), str(max_height))
104
+
105
+ def process_xargs(xargs):
106
+ processed_xargs = []
107
+ skip_until = None # ์ด ๋ณ€์ˆ˜๋Š” ํ˜„์žฌ ์ฒ˜๋ฆฌ ์ค‘์ธ '<...>' ๊ตฌ๋ฌธ์˜ ๋ ์ธ๋ฑ์Šค๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.
108
+
109
+ for i, elem in enumerate(xargs):
110
+ if skip_until is not None and i <= skip_until:
111
+ continue # ์ด๋ฏธ ์ฒ˜๋ฆฌ๋œ ๋ฒ”์œ„๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ธฐ
112
+
113
+ if "add_negative:<" in elem or "rem_negative:<" in elem:
114
+ # '<'๋กœ ์‹œ์ž‘ํ•˜์—ฌ '>'๋กœ ๋๋‚˜๋Š” ๊ตฌ๋ฌธ ์ฒ˜๋ฆฌ
115
+ if elem.endswith(">"):
116
+ processed_xargs.append(elem)
117
+ else:
118
+ combined_elem = elem
119
+ for j in range(i + 1, len(xargs)):
120
+ combined_elem += ',' + xargs[j] # ','๋ฅผ ํฌํ•จํ•˜์—ฌ ์›์†Œ๋“ค์„ ๊ฒฐํ•ฉ
121
+ if xargs[j].endswith(">"):
122
+ skip_until = j # '>'๋กœ ๋๋‚˜๋Š” ์›์†Œ๋ฅผ ์ฐพ์œผ๋ฉด, ์ฒ˜๋ฆฌํ•  ๋ฒ”์œ„์˜ ๋ ์ธ๋ฑ์Šค๋ฅผ ์—…๋ฐ์ดํŠธ
123
+ break
124
+ processed_xargs.append(combined_elem)
125
+ else:
126
+ processed_xargs.append(elem) # ์ผ๋ฐ˜์ ์ธ ์›์†Œ๋Š” ๊ทธ๋Œ€๋กœ ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€
127
+
128
+ return processed_xargs
129
+
130
+ def event_cond_negative(_prompt, negative, user_input, rating):
131
+ def insert_text_after_keyword(negative, user_keyword, user_additional_keyword):
132
+ if user_keyword in negative:
133
+ index = negative.index(user_keyword) + 1
134
+ negative.insert(index, user_additional_keyword)
135
+ return negative
136
+ def parse_conditional_command(command):
137
+ match = re.match(r"\((.*?)\)\:(.*)", command)
138
+ if match:
139
+ return match.groups()
140
+ return '', command
141
+ def check_condition(prompt, condition, rating):
142
+ if not condition:
143
+ return True
144
+ sub_conditions = re.split(r'\)\s*&\s*\(', condition)
145
+ sub_conditions = [re.sub(r'^\(|\)$', '', cond) for cond in sub_conditions]
146
+
147
+ results = []
148
+ for sub_cond in sub_conditions:
149
+ if '&' in sub_cond:
150
+ results.append(all(check_condition(prompt, cond, rating) for cond in sub_cond.split('&')))
151
+ elif '|' in sub_cond:
152
+ results.append(any(check_condition(prompt, cond, rating) for cond in sub_cond.split('|')))
153
+ else:
154
+ if sub_cond in ['e', 'q', 's', 'g']:
155
+ results.append(sub_cond == rating)
156
+ elif sub_cond in ['~e', '~q', '~s', '~g']:
157
+ results.append(sub_cond != rating)
158
+ # PM
159
+ elif sub_cond.startswith('*'):
160
+ results.append(sub_cond[1:] in prompt)
161
+ # NOT IN
162
+ elif sub_cond.startswith('~!'):
163
+ results.append(sub_cond[2:] not in prompt)
164
+ elif sub_cond.startswith('~'):
165
+ results.append(any(sub_cond[1:] not in element for element in prompt))
166
+ # CONTAIN
167
+ else:
168
+ results.append(any(sub_cond in element for element in prompt))
169
+ return all(results)
170
+ def execute_command(negative, command):
171
+ if '+=' in command:
172
+ keyword, addition = command.split('+=', 1)
173
+ addition = addition.replace('^', ', ')
174
+ return insert_text_after_keyword(negative, keyword, addition)
175
+ elif command.startswith('add '):
176
+ keyword = command[4:]
177
+ keyword = keyword.replace('^', ', ')
178
+ keys = keyword.split(',')
179
+ keys = [key.strip() for key in keys]
180
+ for key in keys:
181
+ if key not in negative:
182
+ negative.append(key)
183
+ return negative
184
+ elif command.startswith('rem '):
185
+ keyword = command[4:]
186
+ keyword = keyword.replace('^', ', ')
187
+ keys = keyword.split(',')
188
+ keys = [key.strip() for key in keys]
189
+ for key in keys:
190
+ if key in negative:
191
+ negative.remove(key)
192
+ return negative
193
+ elif '=' in command:
194
+ keyword, replacement = command.split('=', 1)
195
+ if keyword in negative:
196
+ replacement = replacement.replace('^', ', ')
197
+ index = negative.index(keyword)
198
+ negative[index] = replacement
199
+ return negative
200
+ negative = negative.split(',')
201
+ negative = [neg.strip() for neg in negative]
202
+ prompt = _prompt.split(',')
203
+ prompt = [key.strip() for key in prompt]
204
+ commands = [cmd.strip() for cmd in user_input.split(',') if not cmd.strip().startswith('#')]
205
+ for command in commands:
206
+ condition, cmd = parse_conditional_command(command)
207
+ if check_condition(prompt, condition, rating):
208
+ negative = execute_command(negative, cmd)
209
+ return ', '.join(negative)
210
+
211
+ def image_to_base64(image):
212
+ image_bytesIO = io.BytesIO()
213
+ image.save(image_bytesIO, format="PNG")
214
+ return base64.b64encode(image_bytesIO.getvalue()).decode()
215
+
216
+ def make_turbo_prompt(gen_request):
217
+ lines = gen_request['prompt']
218
+ result = {
219
+ "boys": False,
220
+ "girls": False,
221
+ "1girl": False,
222
+ "1boy": False,
223
+ "1other": False,
224
+ "others": False
225
+ }
226
+ state = {
227
+ "nude,": False,
228
+ "pov,": False,
229
+ "cum,": False,
230
+ "after ": False,
231
+ "pussy juice": False,
232
+ "barefoot": False,
233
+ "breasts": False,
234
+ "ejaculation": False,
235
+ }
236
+
237
+ def insert_spaces(source_list, reference_list):
238
+ modified_list = source_list.copy()
239
+ for index, keyword in enumerate(reference_list):
240
+ if keyword not in source_list:
241
+ space_count = len(keyword) # ํ‚ค์›Œ๋“œ ๊ธธ์ด๋งŒํผ์˜ ๊ณต๋ฐฑ ๋ฌธ์ž
242
+ modified_list.insert(index, ' ' * space_count)
243
+ return modified_list
244
+
245
+ keywords = gen_request['prompt'].split(', ')
246
+ filtered_keywords = []
247
+ removed_indices = []
248
+ positive0, positive1, positive2, positive3 = gen_request.copy(),gen_request.copy(),gen_request.copy(),gen_request.copy()
249
+
250
+ for word in result.keys():
251
+ if word in lines:
252
+ result[word] = True
253
+ for word in state.keys():
254
+ if word in gen_request['prompt']:
255
+ state[word] = True
256
+
257
+ key_index = int((len(keywords)/2)-1)
258
+
259
+ if(result["1boy"]) or (result["boys"]):
260
+ if(result["1girl"]):
261
+ if(', sex' in gen_request['prompt'] or 'group sex' in gen_request['prompt']):
262
+ sex_pos_keywords = ['stomach bulge','insertion', 'fucked silly', 'x-ray', 'orgasm', 'cross-section', 'uterus', 'overflow', 'rape', 'vaginal', 'anal']
263
+ facial_keywords = ['tongue','ahegao']
264
+ temp_sex_pos = []
265
+ temp_facial = []
266
+ cum_events = []
267
+ explicit_check = []
268
+ if 'open mouth' in keywords: keywords.remove('open mouth')
269
+ if 'closed mouth' in keywords: keywords.remove('closed mouth')
270
+ if 'after rape' in keywords:
271
+ keywords.remove('after rape')
272
+ explicit_check.append('after rape')
273
+ if 'used condom' in keywords:
274
+ keywords.remove('used condom')
275
+ explicit_check.append('used condom')
276
+ for keyword in keywords:
277
+ if ('sex' not in keyword and 'cum' not in keyword and 'ejaculation' not in keyword and 'vaginal' not in keyword and 'penetration' not in keyword) and all(sex_pos not in keyword for sex_pos in sex_pos_keywords) and all(facial not in keyword for facial in facial_keywords):
278
+ filtered_keywords.append(keyword)
279
+ elif 'sex' in keyword:
280
+ removed_indices.append(keyword)
281
+ elif 'penetration' in keyword:
282
+ removed_indices.append(keyword)
283
+ elif 'cum' in keyword and keyword != 'cum':
284
+ cum_events.append(keyword)
285
+ elif any(sex_pos in keyword for sex_pos in sex_pos_keywords):
286
+ for sex_pos in sex_pos_keywords:
287
+ if sex_pos in keyword:
288
+ temp_sex_pos.append(sex_pos)
289
+ elif any(facial not in keyword for facial in facial_keywords):
290
+ for facial in facial_keywords:
291
+ if facial in keyword:
292
+ temp_facial.append(facial)
293
+ filtered_keywords.insert(int((len(filtered_keywords)/2)-1), ' no penetration, imminent penetration')
294
+ filtered_keywords_positive0 = filtered_keywords.copy()
295
+ filtered_keywords.remove(' no penetration, imminent penetration')
296
+ #0 imminent penetration, imminent sex
297
+ if 'condom' in filtered_keywords and 'condom on penis' not in filtered_keywords:
298
+ t_index = filtered_keywords.index('condom')
299
+ rand_num = random.randint(0,2)
300
+ if rand_num == 1: filtered_keywords.insert(t_index, 'condom on penis')
301
+ for i, keyword in enumerate(filtered_keywords):
302
+ if 'pantyhose' in keyword:
303
+ filtered_keywords[i] = 'torn ' + filtered_keywords[i]
304
+ #1 default
305
+ key_index = int((len(filtered_keywords)/2)-1)
306
+ if 'pussy' in filtered_keywords: key_index = filtered_keywords.index('pussy')
307
+ if 'penis' in filtered_keywords: key_index = filtered_keywords.index('penis')
308
+ filtered_keywords[key_index:key_index] = ['motion lines', 'surprised']
309
+ for keyword in removed_indices:
310
+ if 'cum' not in keyword and 'ejaculation' not in keyword:
311
+ filtered_keywords.insert(key_index,keyword)
312
+ if(temp_sex_pos): filtered_keywords[key_index:key_index] = temp_sex_pos
313
+ if 'group sex' in filtered_keywords and 'sex' not in filtered_keywords:
314
+ t_index = filtered_keywords.index('group sex')
315
+ filtered_keywords.insert(t_index, 'sex')
316
+ if('clothed sex' in filtered_keywords and not 'bottomless' in filtered_keywords): filtered_keywords.insert(filtered_keywords.index('clothed sex')+1, 'bottomless')
317
+ pos1_copied_keywords = filtered_keywords.copy()
318
+ for i, keyword in enumerate(pos1_copied_keywords):
319
+ if 'closed eyes' in keyword:
320
+ rand_num = random.randint(0,2)
321
+ if(rand_num == 0): pos1_copied_keywords[i] = 'half-' + pos1_copied_keywords[i]
322
+ elif(rand_num == 1 and 'closed eyes' in pos1_copied_keywords):
323
+ pos1_copied_keywords.remove('closed eyes')
324
+ filtered_keywords[i] = 'half-closed eyes'
325
+ filtered_keywords_positive1 = pos1_copied_keywords.copy()
326
+ #2 ejaculation,cum in pussy
327
+ key_index = filtered_keywords.index('surprised')
328
+ filtered_keywords.remove('surprised')
329
+ filtered_keywords[key_index:key_index] = ["ejaculation","cum"] if "condom on penis" not in filtered_keywords else ["twitching penis", "[[[[orgasm]]]]"]
330
+ for keyword in removed_indices:
331
+ if 'cum' in keyword:
332
+ filtered_keywords.insert(key_index,keyword)
333
+ if(temp_facial): filtered_keywords[key_index:key_index] =temp_facial
334
+ filtered_keywords_positive2 = filtered_keywords.copy()
335
+ #3 after sex, after ejaculation
336
+ for i, keyword in enumerate(filtered_keywords):
337
+ if 'closed eyes' in keyword:
338
+ rand_num = random.randint(0,2)
339
+ if(rand_num == 0 and filtered_keywords[i] != 'half-closed eyes'): filtered_keywords[i] = 'half-' + filtered_keywords[i]
340
+ elif(rand_num == 1): filtered_keywords[i] = 'empty eyes'
341
+ else: filtered_keywords[i] = 'empty eyes, half-closed eyes'
342
+ if 'sex' in filtered_keywords:
343
+ key_index = filtered_keywords.index('sex')
344
+ elif 'group sex' in filtered_keywords:
345
+ key_index = filtered_keywords.index('group sex')
346
+ if "condom on penis" not in filtered_keywords: filtered_keywords.remove('ejaculation')
347
+ else:
348
+ filtered_keywords.remove('twitching penis')
349
+ filtered_keywords.remove('[[[[orgasm]]]]')
350
+ filtered_keywords[key_index:key_index] = ['cum drip', 'erection'] + cum_events if "condom on penis" not in filtered_keywords else ["used condom", "{{used condom on penis}}"]
351
+ if(explicit_check): filtered_keywords[key_index:key_index] = explicit_check
352
+ if 'sex' in filtered_keywords and 'group sex' not in filtered_keywords:
353
+ if('pussy' in filtered_keywords and not 'anal' in filtered_keywords):
354
+ if "condom on penis" not in filtered_keywords: filtered_keywords.insert(filtered_keywords.index('sex')+1, 'after vaginal, spread pussy')
355
+ else: filtered_keywords.insert(filtered_keywords.index('sex')+1, 'after vaginal, spread pussy, pussy juice puddle')
356
+ elif('anal' in filtered_keywords):
357
+ if "condom on penis" not in filtered_keywords: filtered_keywords.insert(filtered_keywords.index('sex')+1, 'after anal, cum in ass')
358
+ else: filtered_keywords.insert(filtered_keywords.index('sex')+1, 'after anal, pussy juice')
359
+ filtered_keywords.insert(filtered_keywords.index('sex'), 'after sex')
360
+ filtered_keywords.remove('sex')
361
+ elif 'group sex' in filtered_keywords:
362
+ if('vaginal' in filtered_keywords and not 'anal' in filtered_keywords):
363
+ filtered_keywords.insert(filtered_keywords.index('group sex')+1, 'after vaginal, spread pussy')
364
+ if 'multiple penises' in filtered_keywords:
365
+ if "condom on penis" not in filtered_keywords: filtered_keywords.insert(filtered_keywords.index('group sex')+3, 'cum on body, bukkake')
366
+ else: filtered_keywords.insert(filtered_keywords.index('group sex')+3, 'pussy juice, pussy juice puddle')
367
+ elif('anal' in filtered_keywords):
368
+ if "condom on penis" not in filtered_keywords: filtered_keywords.insert(filtered_keywords.index('group sex')+1, 'after anus, cum in ass')
369
+ else: filtered_keywords.insert(filtered_keywords.index('group sex')+1, 'after anus')
370
+ if 'multiple penises' in filtered_keywords:
371
+ if "condom on penis" not in filtered_keywords: filtered_keywords.insert(filtered_keywords.index('group sex')+3, 'cum on body, bukkake')
372
+ else: filtered_keywords.insert(filtered_keywords.index('group sex')+3, 'pussy juice')
373
+ else: filtered_keywords.insert(filtered_keywords.index('group sex')+1, 'cum on body, {bukkake}')
374
+ temp_post_keyword = []
375
+ for keyword in sex_pos_keywords:
376
+ if not (keyword == 'orgasm' or keyword == 'overflow'):
377
+ if keyword in filtered_keywords:
378
+ temp_post_keyword.append(keyword)
379
+ for keyword in temp_post_keyword:
380
+ filtered_keywords.remove(keyword)
381
+
382
+ positive0['prompt'] = ', '.join(insert_spaces(filtered_keywords_positive0, filtered_keywords)).strip()
383
+ positive1['prompt'] = ', '.join(insert_spaces(filtered_keywords_positive1, filtered_keywords)).strip()
384
+ positive2['prompt'] = ', '.join(insert_spaces(filtered_keywords_positive2, filtered_keywords)).strip()
385
+ positive3['prompt'] = ', '.join(filtered_keywords).strip()
386
+ positive0["type"] = "turbo"
387
+ positive1["type"] = "turbo"
388
+ positive2["type"] = "turbo"
389
+ positive3["type"] = "turbo"
390
+ return positive0, positive1, positive2, positive3
391
+
392
+ def generate_image(access_token, prompt, model, action, parameters):
393
+ if re.match(r'^http[s]?://', access_token):
394
+ return generate_image_webui(access_token, prompt, model, action, parameters)
395
+ return generate_image_NAI(access_token, prompt, model, action, parameters)
396
+
397
+ def generate_image_NAI(access_token, prompt, model, action, parameters):
398
+ data = {
399
+ "input": prompt,
400
+ "model": model,
401
+ "action": action,
402
+ "parameters": parameters,
403
+ }
404
+
405
+ if "fts1" in parameters:
406
+ data["input"] = parameters["fts1"] + data["input"]
407
+
408
+ if data['parameters']['qualityToggle'] == True:
409
+ if "nai-diffusion-furry-3" not in data['model']:
410
+ data['input'] += ', best quality, amazing quality, very aesthetic, absurdres'
411
+ elif 'nai-diffusion-4' in data["model"]:
412
+ data['input'] +=", best quality, amazing quality, very aesthetic, absurdres, year 2024"
413
+ else:
414
+ data['input'] += ', {best quality}, {amazing quality}'
415
+
416
+ if data['parameters']['sampler'] not in ["k_euler", "k_euler_ancestral", "k_dpmpp_sde", "k_dpmpp_2s_ancestral", "k_dpmpp_2m", "k_dpmpp_2m_sde"]:
417
+ data['parameters']['sampler'] = "k_euler_ancestral"
418
+
419
+ if data['parameters']['cfg_rescale'] > 1:
420
+ data['parameters']['cfg_rescale'] = 0
421
+
422
+ if 'nai-diffusion-4' in data["model"]:
423
+ data['parameters']['params_version'] = 3
424
+ data['parameters']['add_original_image'] = True
425
+ data['parameters']['characterPrompts'] = []
426
+ data['parameters']['legacy'] = False
427
+ data['parameters']['legacy_v3_extend'] = False
428
+ data['parameters']['prefer_brownian'] = True
429
+ data['parameters']['ucPreset'] = 0
430
+ data['parameters']['use_coords'] = False
431
+ del data['parameters']['sm']
432
+ del data['parameters']['sm_dyn']
433
+ del data['parameters']['enable_hr']
434
+ del data['parameters']['enable_AD']
435
+ if "skip_cfg_above_sigma" in data['parameters']: del data['parameters']['skip_cfg_above_sigma']
436
+ data['parameters']['v4_negative_prompt'] = {
437
+ 'caption' : {
438
+ 'base_caption' : data["parameters"]['negative_prompt'],
439
+ 'char_captions' : []
440
+ },
441
+ }
442
+ data['parameters']['v4_prompt'] = {
443
+ 'caption' : {
444
+ 'base_caption' : data['input'],
445
+ 'char_captions' : []
446
+ },
447
+ 'use_coords' : False,
448
+ 'use_order' : True
449
+ }
450
+ main_pr = [k.strip() for k in data['input'].split(', ')]
451
+ sub_pr = []
452
+ if 'characters' in data['parameters'] and data['parameters']['characters'][0] != '':
453
+ for i, k in enumerate(data['parameters']['characters']):
454
+ _dict = {
455
+ "center": {
456
+ "x": 0.5,
457
+ "y": 0.5
458
+ },
459
+ "prompt": k,
460
+ "uc": data['parameters']['characters_uc'][i]
461
+ }
462
+ for _k in k.split(','):
463
+ sub_pr.append(_k.strip())
464
+ data['parameters']['characterPrompts'].append(_dict.copy())
465
+ del _dict["uc"]
466
+ _dict["centers"] = [ _dict["center"].copy() ]
467
+ del _dict["center"]
468
+ _dict['char_caption'] = _dict['prompt']
469
+ del _dict['prompt']
470
+ data['parameters']['v4_prompt']['caption']['char_captions'].append(_dict.copy())
471
+ _dict['char_caption'] = data['parameters']['characters_uc'][i]
472
+ data['parameters']['v4_negative_prompt']['caption']['char_captions'].append(_dict.copy())
473
+ del data['parameters']['characters']
474
+ del data['parameters']['characters_uc']
475
+ main_pr = [prompt for prompt in main_pr if prompt not in sub_pr]
476
+ main_pr = ', '.join(main_pr)
477
+ data['input'] = main_pr
478
+ data['parameters']['v4_prompt']['caption']['base_caption'] = main_pr
479
+
480
+ response = requests.post(f"{BASE_URL}/ai/generate-image", json=data, headers={ "Authorization": f"Bearer {access_token}" }, timeout=180)
481
+ # catch any errors
482
+ return response.content
483
+
484
+ def augment_image_NAI(gen_request):
485
+ def resize_and_fill(image, max_size=None):
486
+ if max_size is None:
487
+ max_size = gen_request["user_screen_size"]
488
+ original_width, original_height = image.size
489
+ if original_width > max_size or original_height > max_size:
490
+ # ๋น„์œจ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํฌ๊ธฐ ์กฐ์ •
491
+ image.thumbnail((max_size, max_size))
492
+
493
+ # ์ƒˆ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๊ณ„์‚ฐ
494
+ width, height = image.size
495
+ new_image = Image.new("RGB", (max_size, max_size), "black")
496
+ new_image.paste(image, ((max_size - width) // 2, (max_size - height) // 2))
497
+ return new_image
498
+ else:
499
+ return image
500
+ def log_error(e, output_file_path="output_file_path"):
501
+ # ํ˜„์žฌ ์‹œ๊ฐ„์„ ์–ป์Šต๋‹ˆ๋‹ค
502
+ current_time = datetime.now().strftime("%m/%d %H:%M:%S")
503
+
504
+ # ์—๋Ÿฌ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€
505
+ error_message = f"#### Error occured at {current_time} ####\nError: {e}\n############################################\n"
506
+
507
+ # ์ง€์ •๋œ ์ถœ๋ ฅ ํด๋”์˜ error_log.txt ํŒŒ์ผ์— ์“ฐ๊ธฐ
508
+ with open(f"error_log.txt", "a") as file:
509
+ file.write(error_message)
510
+ access_token = gen_request["access_token"]
511
+ mode = gen_request["mode"]
512
+ defry = gen_request["defry"]
513
+ prompt = gen_request["prompt"]
514
+ iw = gen_request["width"]
515
+ ih = gen_request["height"]
516
+ image = gen_request["image"]
517
+ if mode in ["declutter", "lineart", "sketch", "colorize"]: _mode = mode
518
+ else:
519
+ _mode = "emotion"
520
+ mode = mode.lower()
521
+ data = {
522
+ "req_type": _mode,
523
+ "width": iw,
524
+ "height": ih,
525
+ "image" : image_to_base64(image)
526
+ }
527
+ dfval = {
528
+ "Normal" : 0,
529
+ "Slightly Weak" : 1,
530
+ "Weak" : 2,
531
+ "Even Weaker" : 3,
532
+ "Very Weak" : 4,
533
+ "Weakest" : 5
534
+ }
535
+ if _mode == "emotion":
536
+ try: data["prompt"] = mode+";;"+prompt+";"
537
+ except: data["prompt"] = mode+";"
538
+ try: data["defry"] = dfval[defry]
539
+ except: data["defry"] = 0
540
+ prompt = data["prompt"]
541
+ elif _mode == "colorize":
542
+ data["prompt"] = prompt
543
+ try: data["defry"] = dfval[defry]
544
+ except: data["defry"] = 0
545
+ else:
546
+ prompt = ""
547
+ start_time = time.time()
548
+ print(access_token[:10])
549
+ aug_response = requests.post(f"{BASE_URL}/ai/augment-image", json=data, headers={ "Authorization": f"Bearer {access_token}" }, timeout=180)
550
+ save_folder = gen_request["save_folder"]
551
+ additional_folder = ''
552
+ if gen_request["png_rule"] == "count":
553
+ additional_folder = "/" + gen_request["start_time"]
554
+ if "additional_save_folder" in gen_request:
555
+ if gen_request["additional_save_folder"]["command1"] != "":
556
+ additional_folder += "/" + gen_request["additional_save_folder"]["command1"].replace('/',"_")
557
+ if gen_request["additional_save_folder"]["command2"] != "":
558
+ additional_folder += "/" + gen_request["additional_save_folder"]["command2"].replace('/',"_")
559
+ forbidden_chars = r'[\\:*?"<>|]'
560
+ additional_folder = re.sub(forbidden_chars, '_', additional_folder).strip()
561
+ additional_folder += "/director"
562
+ if len(additional_folder) > 200: additional_folder = additional_folder[:200]
563
+ d = Path(save_folder + additional_folder)
564
+ d.mkdir(parents=True, exist_ok=True)
565
+ try:
566
+ zipped = zipfile.ZipFile(io.BytesIO(aug_response.content))
567
+ end_time = time.time()
568
+ response_time = round(end_time - start_time, 2)
569
+ result_list = []
570
+ for idx, file_info in enumerate(zipped.infolist()):
571
+ image_bytes = zipped.read(file_info)
572
+ if gen_request["png_rule"] == "count":
573
+ _count = gen_request["count"]
574
+ if "batch_size" in gen_request: filename = (d / f"{_count:05}_{idx}.png" )
575
+ else: filename = (d / f"{_count:05}.png" )
576
+ else:
577
+ if "batch_size" in gen_request: filename = (d / f"{datetime.now().strftime('%Y%m%d_%H%M%S')}_{idx}.png" )
578
+ else: filename = (d / f"{datetime.now().strftime('%Y%m%d_%H%M%S')}.png" )
579
+ filename.write_bytes(image_bytes)
580
+ i = Image.open(io.BytesIO(image_bytes))
581
+ i = ImageOps.exif_transpose(i).convert("RGB")
582
+ if "artist" not in gen_request:
583
+ i_resized = resize_and_fill(i)
584
+ next = i_resized, prompt, 0, i.info, str(filename)
585
+ result_list.append(next)
586
+ return i_resized, prompt, 0, i.info, str(filename) if len(result_list) ==1 else result_list, response_time
587
+ except Exception as e:
588
+ end_time = time.time()
589
+ response_time = round(end_time - start_time, 2)
590
+ try:
591
+ if aug_response.content is None:
592
+ raise ValueError("Connection broken (Protocol Error)")
593
+ error_message = aug_response.decode('utf-8')[2:-2]
594
+ except Exception as inner_exception:
595
+ error_message = str(inner_exception)
596
+ log_error(error_message, "path_to_output_folder")
597
+ return None, error_message, 0, None, None, response_time
598
+
599
+ def upscale_NAI(access_token, image, gen_request):
600
+ def resize_and_fill(image, max_size=None):
601
+ if max_size is None:
602
+ max_size = gen_request["user_screen_size"]
603
+ original_width, original_height = image.size
604
+ if original_width > max_size or original_height > max_size:
605
+ # ๋น„์œจ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํฌ๊ธฐ ์กฐ์ •
606
+ image.thumbnail((max_size, max_size))
607
+
608
+ # ์ƒˆ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๊ณ„์‚ฐ
609
+ width, height = image.size
610
+ new_image = Image.new("RGB", (max_size, max_size), "black")
611
+ new_image.paste(image, ((max_size - width) // 2, (max_size - height) // 2))
612
+ return new_image
613
+ else:
614
+ return image
615
+ def log_error(e, output_file_path="output_file_path"):
616
+ # ํ˜„์žฌ ์‹œ๊ฐ„์„ ์–ป์Šต๋‹ˆ๋‹ค
617
+ current_time = datetime.now().strftime("%m/%d %H:%M:%S")
618
+
619
+ # ์—๋Ÿฌ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€
620
+ error_message = f"#### Error occured at {current_time} ####\nError: {e}\n############################################\n"
621
+
622
+ # ์ง€์ •๋œ ์ถœ๋ ฅ ํด๋”์˜ error_log.txt ํŒŒ์ผ์— ์“ฐ๊ธฐ
623
+ with open(f"error_log.txt", "a") as file:
624
+ file.write(error_message)
625
+ img_str = image_to_base64(image)
626
+ _width, _height = image.size
627
+ data = {
628
+ "image": img_str,
629
+ "width": _width,
630
+ "height": _height,
631
+ "scale": 2,
632
+ }
633
+ response = requests.post(f"https://api.novelai.net/ai/upscale", json=data, headers={ "Authorization": f"Bearer {access_token}" })
634
+ save_folder = gen_request["save_folder"]
635
+ additional_folder = ''
636
+ if gen_request["png_rule"] == "count":
637
+ additional_folder = "/" + gen_request["start_time"]
638
+ additional_folder += "/upscale"
639
+ if len(additional_folder) > 200: additional_folder = additional_folder[:200]
640
+ d = Path(save_folder + additional_folder)
641
+ forbidden_chars = r'[\\:*?"<>|]'
642
+ additional_folder = re.sub(forbidden_chars, '_', additional_folder).strip()
643
+ d.mkdir(parents=True, exist_ok=True)
644
+ try:
645
+ zipped = zipfile.ZipFile(io.BytesIO(response.content))
646
+ result_list = []
647
+ for idx, file_info in enumerate(zipped.infolist()):
648
+ image_bytes = zipped.read(file_info)
649
+ if gen_request["png_rule"] == "count":
650
+ _count = gen_request["count"]
651
+ filename = (d / f"{_count:05}.png" )
652
+ else:
653
+ filename = (d / f"{datetime.now().strftime('%Y%m%d_%H%M%S')}.png" )
654
+ filename.write_bytes(image_bytes)
655
+ i = Image.open(io.BytesIO(image_bytes))
656
+ i = ImageOps.exif_transpose(i).convert("RGB")
657
+ if "artist" not in gen_request:
658
+ i_resized = resize_and_fill(i)
659
+ next = i_resized, gen_request["prompt"], 0, i.info, str(filename)
660
+ result_list.append(next)
661
+ return i_resized, gen_request["prompt"], 0, i.info, str(filename) if len(result_list) ==1 else result_list
662
+ except Exception as e:
663
+ try:
664
+ if response.content is None:
665
+ raise ValueError("Connection broken (Protocol Error)")
666
+ error_message = response.decode('utf-8')[2:-2]
667
+ except Exception as inner_exception:
668
+ error_message = str(inner_exception)
669
+ log_error(error_message, "path_to_output_folder")
670
+ return None, error_message, 0, None, None
671
+
672
+
673
+ def convert_prompt(prompt):
674
+ keywords = [keyword.strip() for keyword in prompt.split(',')]
675
+ converted_keywords = []
676
+ for keyword in keywords:
677
+ #if 'artist:' in keyword:
678
+ # keyword = keyword.replace('artist:', '')
679
+ #if '(' in keyword:
680
+ # keyword = keyword.replace('(', '\(').replace(')', '\)')
681
+ if '{' in keyword:
682
+ keyword = keyword.replace('{', '(').replace('}', ')')
683
+ converted_keywords.append(keyword)
684
+ return ', '.join(converted_keywords)
685
+
686
+ def convert_prompt_ad(prompt, data):
687
+ keywords = [keyword.strip() for keyword in prompt.split(',')]
688
+ converted_keywords = []
689
+ closed_eyes_check = False if "closed eyes" not in keywords else True
690
+ for idx, keyword in enumerate(keywords):
691
+ if idx > 4 and (keyword in data.bag_of_tags):
692
+ if ("eyes" in keyword or "pupils" in keyword) and closed_eyes_check:
693
+ continue
694
+ keywords[idx] = "((" + keyword + "))"
695
+ if 'artist:' in keyword:
696
+ keyword = keyword.replace('artist:', '').replace('[','').replace(']','')
697
+ keyword = keyword
698
+ if '(' in keyword:
699
+ keyword = keyword.replace('(', '\(').replace(')', '\)')
700
+ if '{' in keyword:
701
+ keyword = keyword.replace('{', '(').replace('}', ')')
702
+ if '}' in keyword:
703
+ keyword = keyword.replace('}', ')')
704
+ converted_keywords.append(keyword)
705
+ return ', '.join(converted_keywords)
706
+
707
+ def interrogate_webui(img, access_token):
708
+ img_str = image_to_base64(img)
709
+
710
+ req_img = {
711
+ "image": img_str,
712
+ "threshold": 0.35,
713
+ "model": "wd-v1-4-moat-tagger.v2",
714
+ "queue": ""
715
+ }
716
+
717
+ try:
718
+ res = requests.post(f"{access_token}/tagger/v1/interrogate", json=req_img)
719
+ if res.status_code != 200:
720
+ raise Exception(f"Error code: {res.status_code}")
721
+
722
+ text = res.json().get('caption', {}).get('tag', {})
723
+ text_list = [txt.replace("_", " ") for txt in text.keys()]
724
+ _rating = res.json().get('caption', {}).get('rating', {})
725
+ rating = max(_rating, key=_rating.get)
726
+ if rating == "sensitive": rv = "s"
727
+ elif rating == "questionable": rv = "q"
728
+ elif rating == "explicit": rv = "e"
729
+ else: rv = "g"
730
+ return ", ".join(text_list), rv
731
+ except Exception as e:
732
+ return f"{e} : WEBUI์˜ Extension์— stable-diffusion-webui-wd14-tagger ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์„ค์น˜๋˜์–ด์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. (WD14 ๊ธฐ์ค€๋ฒ„์ „ : e72d984b, 2023-11-04)", None
733
+
734
+ def generate_image_webui(access_token, prompt, model, action, parameters):
735
+ try:
736
+ samplers = {
737
+ "k_euler": "Euler",
738
+ "k_euler_ancestral": "Euler a",
739
+ "k_dpmpp_2s_ancestral": "DPM++ 2S a",
740
+ "k_dpmpp_sde": "DPM++ SDE",
741
+ "k_dpm_3m_sde": "DPM++ 3M SDE"
742
+ }
743
+
744
+ # matching data format
745
+ data = {
746
+ "input": prompt,
747
+ "model": model,
748
+ "action": action,
749
+ "parameters": parameters,
750
+ }
751
+
752
+ if data['parameters']['sampler'] in samplers:
753
+ data['parameters']['sampler'] = samplers[data['parameters']['sampler']]
754
+
755
+ params = {
756
+ "prompt": convert_prompt(data['input']) if "nai_enable_AD" not in parameters else convert_prompt_ad(data['input'], parameters["ad_data"]),
757
+ "negative_prompt": convert_prompt(data['parameters']['negative_prompt']) if "nai_enable_AD" not in parameters else convert_prompt_ad(data['parameters']['negative_prompt'], parameters["ad_data"]),
758
+ "steps": math.floor(data['parameters']['cfg_rescale'] / 0.5) * 0.5 if "nai-diffusion" not in model else data['parameters']['steps'],
759
+ "width": data['parameters']['width'],
760
+ "height": data['parameters']['height'],
761
+ "cfg_scale": data['parameters']['scale'],
762
+ "sampler_index": data['parameters']['sampler'],
763
+ "sampler_name": data['parameters']['sampler'],
764
+ "seed": data['parameters']['seed'],
765
+ "seed_resize_from_h": -1,
766
+ "seed_resize_from_w": -1,
767
+ "denoising_strength": None if "denoising_strength" not in parameters else parameters["denoising_strength"],
768
+ "n_iter": "1",
769
+ "batch_size": data['parameters']['n_samples']
770
+ }
771
+
772
+ if "sampler_awai" in parameters:
773
+ data['parameters']['sampler'] = parameters["sampler_awai"]
774
+ params["sampler_index"] = parameters["sampler_awai"]
775
+
776
+ if 'scheduler' in parameters:
777
+ params["scheduler"] = data['parameters']['scheduler']
778
+
779
+ if "scheduler_awai" in parameters:
780
+ params["scheduler"] = parameters["scheduler_awai"]
781
+
782
+ if data['parameters']['enable_hr'] == True:
783
+ params['enable_hr'] = True
784
+ params["hr_upscaler"] = data['parameters']["hr_upscaler"]
785
+ params["hr_scale"] = data['parameters']["hr_scale"]
786
+ params["hr_second_pass_steps"] = data['parameters']["hr_second_pass_steps"]
787
+ params["denoising_strength"] = data['parameters']["denoising_strength"]
788
+ #params["hr_checkpoint_name"] = "bijutsubu_v10.safetensors" #bijutsubu_v10.safetensors [0a35ea21f1]
789
+ #params["hr_sampler_name"] = "Use same scheduler"
790
+ params["hr_scheduler"] = "Automatic"
791
+ params["hr_prompt"] = params["prompt"]
792
+ params["hr_negative_prompt"] = params["negative_prompt"]
793
+ if params["height"] * params["width"] > 1048576:
794
+ params["width"], params["height"] = find_max_resolution(params["width"], params["height"])
795
+
796
+ if data['parameters']['enable_AD'] == True:
797
+ params["alwayson_scripts"] = {"ADetailer":
798
+ {
799
+ "args": [
800
+ True,
801
+ False if ("nai_enable_AD" not in parameters or "denoising_strength" in parameters) else True,
802
+ {
803
+ "ad_cfg_scale": data['parameters']['scale'],
804
+ "ad_checkpoint": "Use same checkpoint",
805
+ "ad_clip_skip": 1,
806
+ "ad_confidence": 0.3,
807
+ "ad_controlnet_guidance_end": 1,
808
+ "ad_controlnet_guidance_start": 0,
809
+ "ad_controlnet_model": "None",
810
+ "ad_controlnet_module": "None",
811
+ "ad_controlnet_weight": 1,
812
+ "ad_denoising_strength": 0.4 if "nai_enable_AD" not in parameters else parameters["ad_data_str"],
813
+ "ad_dilate_erode": 4,
814
+ "ad_inpaint_height": 768,
815
+ "ad_inpaint_only_masked": True,
816
+ "ad_inpaint_only_masked_padding": 32,
817
+ "ad_inpaint_width": 768,
818
+ "ad_mask_blur": 4,
819
+ "ad_mask_filter_method": "Area",
820
+ "ad_mask_k": 0,
821
+ "ad_mask_max_ratio": 1,
822
+ "ad_mask_merge_invert": "None",
823
+ "ad_mask_min_ratio": 0,
824
+ "ad_model": "face_yolov8n.pt",
825
+ "ad_model_classes": "",
826
+ "ad_negative_prompt": params["negative_prompt"],
827
+ "ad_noise_multiplier": 1,
828
+ "ad_prompt": params["prompt"],
829
+ "ad_restore_face": False,
830
+ "ad_sampler": data['parameters']['sampler'],
831
+ "ad_scheduler": "Use same scheduler",
832
+ "ad_steps": params["steps"],
833
+ "ad_tab_enable": True,
834
+ "ad_use_cfg_scale": False,
835
+ "ad_use_checkpoint": False,
836
+ "ad_use_clip_skip": False,
837
+ "ad_use_inpaint_width_height": True,
838
+ "ad_use_noise_multiplier": False,
839
+ "ad_use_sampler": False,
840
+ "ad_use_steps": False,
841
+ "ad_use_vae": False,
842
+ "ad_vae": "Use same VAE",
843
+ "ad_x_offset": 0,
844
+ "ad_y_offset": 0,
845
+ "is_api": True
846
+ },
847
+ ]
848
+ }
849
+ }
850
+ if "nai_enable_AD" in parameters:
851
+ params["steps"] = 28
852
+ else:
853
+ params["alwayson_scripts"] = {}
854
+ if 'enable_TV' in data['parameters'] and data['parameters']['enable_TV'] == True:
855
+ params["alwayson_scripts"]["Tiled VAE"] = {}
856
+ params["alwayson_scripts"]["Tiled VAE"]["args"] = data['parameters']["tiled_vae_args"]
857
+
858
+ if 'pag' in parameters:
859
+ params["alwayson_scripts"]["Incantations"] = {}
860
+ pag_pre = math.floor(float(data['parameters']['pag']) / 0.5) * 0.5
861
+ params["alwayson_scripts"]["Incantations"]["args"] = [True,pag_pre, 0, 150, False, "Constant", 0, 100, False,False,2,0.1,0.5,0,"",0,25, 1, False,False,False,"BREAK","-",0.2,10]
862
+
863
+ if "image" in data['parameters']:
864
+ params['init_images'] = [data['parameters']['image']]
865
+ params['include_init_images'] = True
866
+
867
+ if "strength" in data['parameters']:
868
+ params['denoising_strength'] = data['parameters']['strength']
869
+
870
+ if 'denoising_strength' in data['parameters']:
871
+ params['denoising_strength'] = data['parameters']['denoising_strength']
872
+ params['inpainting_fill'] = 1
873
+ params["initial_noise_multiplier"] = 1
874
+ if "steps" not in params: params["steps"] = 28
875
+
876
+ if "mask" in data['parameters']:
877
+ params['mask'] = data['parameters']['mask']
878
+ params['inpainting_fill'] = 1
879
+ params['inpaint_full_res'] = data['parameters']['add_original_image']
880
+ params['inpaint_full_res_padding'] = 32
881
+ if 'denoising_strength' not in params: params['denoising_strength'] = 0.7
882
+
883
+ res = requests.post(f"{access_token}/sdapi/v1/img2img", json=params)
884
+ else: res = requests.post(f"{access_token}/sdapi/v1/txt2img", json=params)
885
+ res.raise_for_status()
886
+
887
+ try:
888
+ response_json = res.json()
889
+ except ValueError:
890
+ error_message = f"Invalid JSON response from server. Status code: {res.status_code}, Response: {res.text}"
891
+ raise RuntimeError(error_message)
892
+
893
+ if 'images' not in response_json:
894
+ error_message = f"No 'images' in response. Status code: {res.status_code}, Response: {res.text}"
895
+ raise RuntimeError(error_message)
896
+
897
+ imageb64s = res.json()['images']
898
+ if not imageb64s:
899
+ raise RuntimeError("No images generated")
900
+ content = None
901
+ for b64 in imageb64s:
902
+ img = b64.encode()
903
+ content = base64.b64decode(img)
904
+
905
+ s = io.BytesIO()
906
+ zf = zipfile.ZipFile(s, "w")
907
+ for idx, b64 in enumerate(imageb64s):
908
+ content = base64.b64decode(b64)
909
+ zf.writestr(f"generated_{idx}.png", content)
910
+ zf.close()
911
+ return s.getvalue()
912
+ except requests.exceptions.RequestException as e:
913
+ error_message = f"Network error: {str(e)}"
914
+ if hasattr(e.response, 'status_code') and hasattr(e.response, 'text'):
915
+ error_message = f"Server error {e.response.status_code}: {e.response.text}"
916
+ raise RuntimeError(error_message)
917
+ except Exception as e:
918
+ raise RuntimeError(f"Error during image generation: {str(e)}")
919
+
920
+ def generate_guide_image_webui(access_token, parameters):
921
+ samplers = {
922
+ "k_euler": "Euler",
923
+ "k_euler_ancestral": "Euler a",
924
+ "k_dpmpp_2s_ancestral": "DPM++ 2S a",
925
+ "k_dpmpp_sde": "DPM++ SDE",
926
+ "k_dpm_3m_sde": "DPM++ 3M SDE"
927
+ }
928
+
929
+ params = {
930
+ "prompt": convert_prompt(parameters['prompt']),
931
+ "negative_prompt": convert_prompt(parameters['negative prompt']),
932
+ "steps": parameters['steps'],
933
+ "width": parameters["width"],
934
+ "height": parameters["height"],
935
+ "cfg_scale": parameters['cfg_scale'],
936
+ "sampler_index": samplers[parameters['sampler']] if parameters['sampler'] in samplers else parameters['sampler'],
937
+ "seed": parameters['seed'],
938
+ "seed_resize_from_h": -1,
939
+ "seed_resize_from_w": -1,
940
+ "denoising_strength": None,
941
+ "n_iter": "1",
942
+ "batch_size": 1
943
+ }
944
+ additional_folder = "/guide"
945
+ if "start_time" in parameters and parameters["png_rule"] == "count":
946
+ additional_folder = "/" + parameters["start_time"] + "/guide"
947
+ if "save_folder" in parameters:
948
+ save_folder = parameters["save_folder"]
949
+ try:
950
+ res = requests.post(f"{access_token}/sdapi/v1/txt2img", json=params)
951
+ imageb64s = res.json()['images']
952
+ image_data = base64.b64decode(imageb64s[0])
953
+ image_file = io.BytesIO(image_data)
954
+ i = Image.open(image_file)
955
+ if "save_folder" in parameters:
956
+ s = io.BytesIO()
957
+ zf = zipfile.ZipFile(s, "w")
958
+ for idx, b64 in enumerate(imageb64s):
959
+ img_data = base64.b64decode(b64)
960
+ img = Image.open(io.BytesIO(img_data))
961
+ output = io.BytesIO()
962
+ if 'parameters' in img.info or 'exif' in img.info:
963
+ exif_dict = {"Exif": {}}
964
+ if 'parameters' in img.info: exif_dict["Exif"][piexif.ExifIFD.UserComment] = img.info['parameters'].encode('utf-8')
965
+ else:
966
+ temp = extract_prompt_info(img.info)
967
+ exif_dict["Exif"][piexif.ExifIFD.UserComment] = temp.encode('utf-8')
968
+ exif_bytes = piexif.dump(exif_dict)
969
+ img.save(output, format="JPEG", exif=exif_bytes)
970
+ else:
971
+ img.save(output, format="JPEG")
972
+ jpeg_content = output.getvalue()
973
+ zf.writestr(f"generated_{idx}.jpg", jpeg_content)
974
+ zf.close()
975
+ if len(additional_folder) > 200: additional_folder = additional_folder[:200]
976
+ forbidden_chars = r'[\\:*?"<>|]'
977
+ additional_folder = re.sub(forbidden_chars, '_', additional_folder).strip()
978
+ d = Path(save_folder + additional_folder)
979
+ d.mkdir(parents=True, exist_ok=True)
980
+ zipped = zipfile.ZipFile(io.BytesIO(s.getvalue()))
981
+ result_list = []
982
+ for idx, file_info in enumerate(zipped.infolist()):
983
+ image_bytes = zipped.read(file_info)
984
+ filename = (d / f"{datetime.now().strftime('%Y%m%d_%H%M%S')}.png" )
985
+ filename.write_bytes(image_bytes)
986
+ except:
987
+ i = Image.new('RGB', (768, 768), 'white')
988
+ filename = ""
989
+ return i, params["prompt"], params["seed"], filename
990
+
991
+ def generate_typer_image_webui(access_token, parameters):
992
+ params = {
993
+ "prompt": convert_prompt(parameters['prompt']),
994
+ "negative_prompt": convert_prompt(parameters['negative prompt']),
995
+ "steps": parameters['steps'],
996
+ "width": parameters["width"],
997
+ "height": parameters["height"],
998
+ "cfg_scale": parameters['cfg_scale'],
999
+ "sampler_index": parameters['sampler'],
1000
+ "seed": parameters['seed'],
1001
+ "seed_resize_from_h": -1,
1002
+ "seed_resize_from_w": -1,
1003
+ "denoising_strength": None,
1004
+ "n_iter": "1",
1005
+ "batch_size": 1
1006
+ }
1007
+ if "scheduler" in parameters:
1008
+ params["scheduler"] = parameters["scheduler"]
1009
+ try:
1010
+ res = requests.post(f"{access_token}/sdapi/v1/txt2img", json=params)
1011
+ imageb64s = res.json()['images']
1012
+ image_data = base64.b64decode(imageb64s[0])
1013
+ image_file = io.BytesIO(image_data)
1014
+ i = Image.open(image_file)
1015
+ except:
1016
+ i = Image.new('RGB', (768, 768), 'white')
1017
+ return i
1018
+
1019
+ def generate_dtg(access_token, parameters):
1020
+ params = {
1021
+ "prompt": parameters['prompt'],
1022
+ "negative_prompt": parameters['negative prompt'],
1023
+ "steps": 1,
1024
+ "width": 64,
1025
+ "height": 64,
1026
+ "cfg_scale": 1,
1027
+ "sampler_index": "Euler a",
1028
+ "seed": 1,
1029
+ "seed_resize_from_h": -1,
1030
+ "seed_resize_from_w": -1,
1031
+ "denoising_strength": None,
1032
+ "n_iter": "1",
1033
+ "batch_size": 1,
1034
+ }
1035
+ if parameters["format"] == "Animagine":
1036
+ format = "<|special|>, <|characters|>, <|copyrights|>, <|artist|>, <|general|>, <|quality|>, <|meta|>, <|rating|>"
1037
+ elif parameters["format"] == "Pony":
1038
+ format = "<|quality|>, <|special|>, <|characters|>, <|copyrights|>, <|artist|>, <|general|>, <|meta|>, <|rating|>"
1039
+
1040
+ params["alwayson_scripts"] = {}
1041
+ params["alwayson_scripts"]["DanTagGen"] = {
1042
+ "args" : [
1043
+ True,
1044
+ "After applying other prompt processings",
1045
+ -1, #random.randint(0, 4294967295 - params["seed"])
1046
+ parameters["length"],
1047
+ params["negative_prompt"],
1048
+ format,
1049
+ parameters["temp"],
1050
+ 0.95,
1051
+ 100,
1052
+ "KBlueLeaf/DanTagGen-delta-rev2",
1053
+ False,
1054
+ False
1055
+ ]
1056
+ }
1057
+ try:
1058
+ res = requests.post(f"{access_token}/sdapi/v1/txt2img", json=params)
1059
+ imageb64s = res.json()['images']
1060
+ image_data = base64.b64decode(imageb64s[0])
1061
+ image_file = io.BytesIO(image_data)
1062
+ i = Image.open(image_file)
1063
+ except:
1064
+ return ""
1065
+ return i.info
1066
+
1067
+ def generate(gen_request, _naia):
1068
+ def parse_and_execute_commands(_prompt, negative, user_input, rating):
1069
+ negative = negative.split(',')
1070
+ negative = [neg.strip() for neg in negative]
1071
+ prompt = _prompt.split(',')
1072
+ prompt = [key.strip() for key in prompt]
1073
+ commands = [cmd.strip() for cmd in user_input.split(',') if not cmd.strip().startswith('#')]
1074
+ for command in commands:
1075
+ condition, cmd = parse_conditional_command(command)
1076
+ if check_condition(prompt, condition, rating):
1077
+ negative = execute_command(negative, cmd)
1078
+ return ', '.join(negative)
1079
+
1080
+ def parse_conditional_command(command):
1081
+ match = re.match(r"\((.*?)\)\:(.*)", command)
1082
+ if match:
1083
+ return match.groups()
1084
+ return '', command
1085
+
1086
+ def check_condition(prompt, condition, rating):
1087
+ if not condition:
1088
+ return True
1089
+ sub_conditions = re.split(r'\)\s*&\s*\(', condition)
1090
+ sub_conditions = [re.sub(r'^\(|\)$', '', cond) for cond in sub_conditions]
1091
+
1092
+ results = []
1093
+ for sub_cond in sub_conditions:
1094
+ if '&' in sub_cond:
1095
+ results.append(all(check_condition(prompt, cond, rating) for cond in sub_cond.split('&')))
1096
+ elif '|' in sub_cond:
1097
+ results.append(any(check_condition(prompt, cond, rating) for cond in sub_cond.split('|')))
1098
+ else:
1099
+ if sub_cond in ['e', 'q', 's', 'g']:
1100
+ results.append(sub_cond == rating)
1101
+ elif sub_cond in ['~e', '~q', '~s', '~g']:
1102
+ results.append(sub_cond != rating)
1103
+ # PM
1104
+ elif sub_cond.startswith('*'):
1105
+ results.append(sub_cond[1:] in prompt)
1106
+ # NOT IN
1107
+ elif sub_cond.startswith('~!'):
1108
+ results.append(sub_cond[2:] not in prompt)
1109
+ elif sub_cond.startswith('~'):
1110
+ results.append(all(sub_cond[1:] not in element for element in prompt))
1111
+ # CONTAIN
1112
+ else:
1113
+ results.append(any(sub_cond in element for element in prompt))
1114
+ return all(results)
1115
+
1116
+ def execute_command(negative, command):
1117
+ if '+=' in command:
1118
+ keyword, addition = command.split('+=', 1)
1119
+ addition = addition.replace('^', ', ')
1120
+ return insert_text_after_keyword(negative, keyword, addition)
1121
+ elif command.startswith('add '):
1122
+ keyword = command[4:]
1123
+ keyword = keyword.replace('^', ', ')
1124
+ keys = keyword.split(',')
1125
+ keys = [key.strip() for key in keys]
1126
+ for key in keys:
1127
+ if key not in negative:
1128
+ negative.append(key)
1129
+ return negative
1130
+ elif command.startswith('rem '):
1131
+ keyword = command[4:]
1132
+ keyword = keyword.replace('^', ', ')
1133
+ keys = keyword.split(',')
1134
+ keys = [key.strip() for key in keys]
1135
+ for key in keys:
1136
+ if key in negative:
1137
+ negative.remove(key)
1138
+ return negative
1139
+ elif '=' in command:
1140
+ keyword, replacement = command.split('=', 1)
1141
+ if keyword in negative:
1142
+ replacement = replacement.replace('^', ', ')
1143
+ index = negative.index(keyword)
1144
+ negative[index] = replacement
1145
+ return negative
1146
+
1147
+ def insert_text_after_keyword(negative, user_keyword, user_additional_keyword):
1148
+ if user_keyword in negative:
1149
+ index = negative.index(user_keyword) + 1
1150
+ negative.insert(index, user_additional_keyword)
1151
+ return negative
1152
+
1153
+ def open_random_png(folderpath):
1154
+ files = os.listdir(folderpath)
1155
+ png_files = [f for f in files if f.endswith('.png')]
1156
+
1157
+ if not png_files:
1158
+ return None
1159
+
1160
+ random_png = random.choice(png_files)
1161
+ img = Image.open(os.path.join(folderpath, random_png))
1162
+
1163
+ return img
1164
+
1165
+ try: seed = int(gen_request["seed"])
1166
+ except: seed = random.randint(0,9999999999)
1167
+
1168
+ try:
1169
+ width = int(gen_request["width"])
1170
+ height = int(gen_request["height"])
1171
+ except:
1172
+ width, height= 1024, 1024
1173
+
1174
+ params = {
1175
+ "legacy": False,
1176
+ "qualityToggle": True if gen_request["quality_toggle"] == 1 else False,
1177
+ "width": width,
1178
+ "height": height,
1179
+ "n_samples": 1 if "batch_size" not in gen_request else gen_request["batch_size"],
1180
+ "seed": seed,
1181
+ "extra_noise_seed": random.randint(0,9999999999),
1182
+ "sampler": gen_request["sampler"],
1183
+ "steps": 28 if "steps" not in gen_request and gen_request["type"]!="upper" else gen_request["steps"],
1184
+ "scale": gen_request["scale"],
1185
+ "negative_prompt": ', '.join([keyword.strip() for keyword in gen_request["negative"].split(',') if not keyword.strip().startswith('#')]),
1186
+ "sm" : True if gen_request["sema"] == 1 else False,
1187
+ "sm_dyn" : True if gen_request["sema_dyn"] == 1 else False,
1188
+ "dynamic_thresholding": True if ("dynamic_thresholding" in gen_request and gen_request["dynamic_thresholding"] == True) else False,
1189
+ "controlnet_strength": 1.0,
1190
+ "add_original_image": False,
1191
+ "cfg_rescale": gen_request["cfg_rescale"],
1192
+ "noise_schedule": gen_request["noise_schedule"],
1193
+ "enable_hr" : gen_request["enable_hr"],
1194
+ "enable_AD" : gen_request["enable_AD"]
1195
+ }
1196
+
1197
+ if "fts1" in gen_request:
1198
+ params["fts1"] = gen_request["fts1"] + " :" + gen_request["fts1_val"].strip() +" | "
1199
+
1200
+ if "skip_cfg_above_sigma" in gen_request and gen_request["skip_cfg_above_sigma"] == True:
1201
+ if float(gen_request["uncond_scale"]) == 19.19:
1202
+ params["skip_cfg_above_sigma"] = 19.191344202730882
1203
+ else:
1204
+ try:
1205
+ _scale = float(gen_request["uncond_scale"])
1206
+ params["skip_cfg_above_sigma"] = _scale
1207
+ except:
1208
+ params["skip_cfg_above_sigma"] = 19.191344202730882
1209
+
1210
+ if params["enable_hr"] == True:
1211
+ params["hr_upscaler"] = gen_request["hr_upscaler"]
1212
+ params["hr_scale"] = gen_request["hr_scale"]
1213
+ params["hr_second_pass_steps"] = gen_request["hr_second_pass_steps"]
1214
+ params["denoising_strength"] = gen_request["denoising_strength"]
1215
+ if "enable_TV" in gen_request and gen_request["enable_TV"] == True:
1216
+ params["enable_TV"] = True
1217
+ params["tiled_vae_args"] = gen_request["tiled_vae_args"]
1218
+
1219
+ if "reference_image" in gen_request:
1220
+ params["reference_image_multiple"] = gen_request["reference_image"] if isinstance(gen_request["reference_image"], list) else [gen_request["reference_image"]]
1221
+ params["reference_information_extracted_multiple"] = gen_request["reference_information_extracted"] if isinstance(gen_request["reference_information_extracted"], list) else [gen_request["reference_information_extracted"]]
1222
+ params["reference_strength_multiple"] = gen_request["reference_strength"] if isinstance(gen_request["reference_strength"], list) else [gen_request["reference_strength"]]
1223
+
1224
+ if gen_request["type"]=="inpaint":
1225
+ if "mask" in gen_request:
1226
+ params["mask"] = gen_request["mask"]
1227
+ params['add_original_image'] = gen_request['add_original_image']
1228
+
1229
+ positive = gen_request["prompt"]
1230
+ positive = re.sub(r'#.*?(\n|,|$)', '', positive)
1231
+ keywords = [key.strip() for key in positive.split(',')]
1232
+
1233
+ if "cond_negative" in gen_request and gen_request["cond_negative"]:
1234
+ user_input = gen_request["cond_negative"]
1235
+ rating = gen_request["rating"]
1236
+ params["negative_prompt"] = parse_and_execute_commands(positive, params["negative_prompt"], user_input, rating)
1237
+
1238
+ if "repeat" in gen_request:
1239
+ max = gen_request["repeat_max"]
1240
+
1241
+ for i, key in enumerate(keywords):
1242
+ if "->" in key:
1243
+ instant_keyword = [k for k in key.split('->')]
1244
+ if len(instant_keyword) > gen_request["repeat"]:
1245
+ current_key = instant_keyword[gen_request["repeat"]]
1246
+ else:
1247
+ current_key = instant_keyword[gen_request["repeat"] % len(instant_keyword)]
1248
+ keywords[i] = ', '.join(current_key.split('^'))
1249
+
1250
+ filename_rule = gen_request["png_rule"]
1251
+ save_folder = gen_request["save_folder"]
1252
+
1253
+ access_token = gen_request["access_token"]
1254
+ additional_folder = ""
1255
+
1256
+ request_type = "generate"
1257
+
1258
+ if "*i2i:(" in gen_request["prompt"] and "image" not in gen_request:
1259
+ try:
1260
+ start_index = gen_request["prompt"].index('*i2i:(') + len('*i2i:(')
1261
+ end_index = gen_request["prompt"].index(')', start_index)
1262
+ i2i_content = gen_request["prompt"][start_index:end_index]
1263
+ _img, _str = [item.strip() for item in i2i_content.split(':')]
1264
+ _str = float(_str)
1265
+ _img = open_random_png(_img)
1266
+ if _img:
1267
+ gen_request["image"] = image_to_base64(_img)
1268
+ gen_request["strength"] = _str
1269
+ gen_request["noise"] = 0
1270
+ except:
1271
+ pass
1272
+
1273
+ if "nai_enable_AD" in gen_request:
1274
+ params["nai_enable_AD"] = True
1275
+ params["ad_data"] = gen_request["ad_data"]
1276
+ params["ad_data_str"] = gen_request["ad_data_str"]
1277
+
1278
+ if "denoising_strength" in gen_request:
1279
+ params["denoising_strength"] = gen_request["denoising_strength"]
1280
+
1281
+ if "scheduler" in gen_request:
1282
+ params["scheduler"] = gen_request["scheduler"]
1283
+ if "pag" in gen_request:
1284
+ params["pag"] = gen_request["pag"]
1285
+
1286
+ if "image" in gen_request:
1287
+ params["image"] = gen_request["image"]
1288
+ if "strength" in gen_request:
1289
+ params["strength"] = gen_request["strength"]
1290
+ params["noise"] = gen_request["noise"]
1291
+ params["sm"] = False
1292
+ params["sm_dyn"] = False
1293
+ request_type = "img2img" if "mask" not in gen_request else "infill"
1294
+
1295
+ temp_del = []
1296
+ for key in keywords:
1297
+ if key.startswith('*'):
1298
+ temp_del.append(key)
1299
+ for key in temp_del:
1300
+ if key in keywords:
1301
+ keywords.remove(key)
1302
+
1303
+ positive = ', '.join(k for k in keywords if k.strip())
1304
+
1305
+ def resize_and_fill(image, max_size=None):
1306
+ if max_size is None:
1307
+ max_size = gen_request["user_screen_size"]
1308
+ original_width, original_height = image.size
1309
+ if original_width > max_size or original_height > max_size:
1310
+ # ๋น„์œจ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํฌ๊ธฐ ์กฐ์ •
1311
+ image.thumbnail((max_size, max_size))
1312
+
1313
+ # ์ƒˆ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๊ณ„์‚ฐ
1314
+ width, height = image.size
1315
+ new_image = Image.new("RGB", (max_size, max_size), "black")
1316
+ new_image.paste(image, ((max_size - width) // 2, (max_size - height) // 2))
1317
+ return new_image
1318
+ else:
1319
+ return image
1320
+
1321
+ def resize_and_fill_artist(image, max_size=None, _text=""):
1322
+ if _text != "":
1323
+ if "_" in _text:
1324
+ _text0 = _text.split("_")[0]
1325
+ _text1 = _text.split("_")[1]
1326
+ _text = _text1+ " : "+_text0
1327
+ else:
1328
+ _text1 = _text
1329
+ if max_size is None:
1330
+ max_size = gen_request["user_screen_size"]
1331
+ original_width, original_height = image.size
1332
+ max_size = (max_size, max_size)
1333
+ if original_width > max_size[0] or original_height > max_size[1]:
1334
+ # ๋น„์œจ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํฌ๊ธฐ ์กฐ์ •
1335
+ image.thumbnail(max_size)
1336
+
1337
+ # ์ƒˆ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๊ณ„์‚ฐ
1338
+ width, height = image.size
1339
+ new_image = Image.new("RGB", (max_size[0], max_size[1]), "black") # ํ•˜์–€ ์ƒ์ž๋ฅผ ์œ„ํ•ด ๋†’์ด์— 100 ์ถ”๊ฐ€
1340
+ new_image.paste(image, ((max_size[0] - width) // 2, (max_size[1] - height) // 2))
1341
+
1342
+ # ํ…์ŠคํŠธ ์ถ”๊ฐ€
1343
+ draw = ImageDraw.Draw(new_image)
1344
+ font_size = 24
1345
+ font = ImageFont.truetype("arial.ttf", font_size) # ํฐํŠธ ํŒŒ์ผ ๊ฒฝ๋กœ ํ™•์ธ ํ•„์š”
1346
+ # textbbox ์‚ฌ์šฉํ•˜์—ฌ ํ…์ŠคํŠธ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ๊ณ„์‚ฐ
1347
+ text_x = (max_size[0]) // 2
1348
+ text_y = (max_size[1] - 40) + (font_size) // 2
1349
+ bbox = draw.textbbox((text_x, text_y), _text, font=font, anchor="mm")
1350
+ text_width = bbox[2] - bbox[0]
1351
+ text_height = bbox[3] - bbox[1]
1352
+
1353
+ # ํ…์ŠคํŠธ ๋ฐฐ๊ฒฝ ๊ทธ๋ฆฌ๊ธฐ (ํ•˜์–€ ์ƒ์ž)
1354
+ draw.rectangle([text_x - text_width // 2 - 10, text_y - text_height // 2 - 10, text_x + text_width // 2 + 10, text_y + text_height // 2 + 10], fill="white")
1355
+
1356
+ # ํ…์ŠคํŠธ ๊ทธ๋ฆฌ๊ธฐ
1357
+ draw.text((text_x, text_y), _text, fill="black", font=font, anchor="mm")
1358
+
1359
+ return new_image, _text1
1360
+
1361
+
1362
+ def log_error(e, output_file_path="output_file_path"):
1363
+ # ํ˜„์žฌ ์‹œ๊ฐ„์„ ์–ป์Šต๋‹ˆ๋‹ค
1364
+ current_time = datetime.now().strftime("%m/%d %H:%M:%S")
1365
+
1366
+ # ์—๋Ÿฌ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€
1367
+ error_message = f"#### Error occured at {current_time} ####\nError: {e}\n############################################\n"
1368
+
1369
+ # ์ง€์ •๋œ ์ถœ๋ ฅ ํด๋”์˜ error_log.txt ํŒŒ์ผ์— ์“ฐ๊ธฐ
1370
+ with open(f"error_log.txt", "a") as file:
1371
+ file.write(error_message)
1372
+
1373
+ if _naia == "NAID3-Furry":
1374
+ _m1 = "nai-diffusion-furry-3"
1375
+ _m2 = "nai-diffusion-furry-3-inpainting"
1376
+ elif _naia == "NAID4":
1377
+ _m1 = "nai-diffusion-4-curated-preview"
1378
+ _m2 = "nai-diffusion-3-inpainting"
1379
+ if "characters" in gen_request:
1380
+ params['characters'] = gen_request['characters']
1381
+ params['characters_uc'] = gen_request['characters_uc']
1382
+ else:
1383
+ _m1 = "nai-diffusion-3"
1384
+ _m2 = "nai-diffusion-3-inpainting"
1385
+
1386
+ if "sampler_awai" in gen_request:
1387
+ params["sampler_awai"] = gen_request["sampler_awai"]
1388
+
1389
+ if "scheduler_awai" in gen_request:
1390
+ params["scheduler_awai"] = gen_request["scheduler_awai"]
1391
+
1392
+ start_time = time.time()
1393
+ try:
1394
+ zipped_bytes = None
1395
+ error_message = None
1396
+ try:
1397
+ zipped_bytes = generate_image(access_token, positive, _m1 if "mask" not in params else _m2, request_type, params)
1398
+ end_time = time.time()
1399
+ response_time = round(end_time - start_time, 2)
1400
+ if gen_request["png_rule"] == "count":
1401
+ additional_folder = "/" + gen_request["start_time"]
1402
+ if "additional_save_folder" in gen_request:
1403
+ if gen_request["additional_save_folder"]["command1"] != "":
1404
+ additional_folder += "/" + gen_request["additional_save_folder"]["command1"].replace('/',"_")
1405
+ if gen_request["additional_save_folder"]["command2"] != "":
1406
+ additional_folder += "/" + gen_request["additional_save_folder"]["command2"].replace('/',"_")
1407
+ if gen_request["type"] == "turbo":
1408
+ additional_folder += "/turbo"
1409
+ if ("hires" in gen_request and gen_request["hires"]) or ("enable_hr" in gen_request and gen_request["enable_hr"] and "http" in access_token) or (int(gen_request["width"]) * int(gen_request["height"]) > 1048576):
1410
+ additional_folder += "/hires"
1411
+ if "auto_i2i" in gen_request and gen_request["auto_i2i"]:
1412
+ if gen_request["png_rule"] == "count": additional_folder = "/" + gen_request["start_time"] + "/autoi2i"
1413
+ else: additional_folder = "/autoi2i"
1414
+ if "nai_enable_AD" in gen_request and gen_request["nai_enable_AD"]:
1415
+ additional_folder += "/Adetailer"
1416
+ if "webui_nai_i2i" in gen_request and gen_request["webui_nai_i2i"] and "http" not in access_token:
1417
+ additional_folder += "/webui_nai_i2i"
1418
+ if len(additional_folder) > 200: additional_folder = additional_folder[:200]
1419
+ forbidden_chars = r'[\\:*?"<>|]'
1420
+ additional_folder = re.sub(forbidden_chars, '_', additional_folder).strip()
1421
+ d = Path(save_folder + additional_folder)
1422
+ d.mkdir(parents=True, exist_ok=True)
1423
+ zipped = zipfile.ZipFile(io.BytesIO(zipped_bytes))
1424
+ result_list = []
1425
+ for idx, file_info in enumerate(zipped.infolist()):
1426
+ image_bytes = zipped.read(file_info)
1427
+ image_format = what(None, h=image_bytes)
1428
+ if image_format is None:
1429
+ if image_bytes.startswith(b'RIFF') and b'WEBP' in image_bytes[:12]:
1430
+ image_format = 'webp'
1431
+ else:
1432
+ image_format = 'png'
1433
+ if gen_request["png_rule"] == "count":
1434
+ _count = gen_request["count"]
1435
+ if "batch_size" in gen_request: filename = (d / f"{_count:05}_{idx}.{image_format}" )
1436
+ else: filename = (d / f"{_count:05}.{image_format}" )
1437
+ else:
1438
+ if "batch_size" in gen_request: filename = (d / f"{datetime.now().strftime('%Y%m%d_%H%M%S')}_{idx}.{image_format}" )
1439
+ else: filename = (d / f"{datetime.now().strftime('%Y%m%d_%H%M%S')}.{image_format}" )
1440
+ filename.write_bytes(image_bytes)
1441
+ i = Image.open(io.BytesIO(image_bytes))
1442
+ i = ImageOps.exif_transpose(i).convert("RGB")
1443
+ if "artist" not in gen_request:
1444
+ i_resized = resize_and_fill(i)
1445
+ else:
1446
+ i_resized, _i_temp = resize_and_fill_artist(i, None, gen_request["artist"])
1447
+ if not os.path.exists(f"artist_thumb"):
1448
+ os.makedirs(f"artist_thumb")
1449
+ model_name = gen_request["artist_model"]
1450
+ if not os.path.exists(f"artist_thumb/{model_name}"):
1451
+ os.makedirs(f"artist_thumb/{model_name}")
1452
+ #_counts = gen_request["artist"].split("_")[0]
1453
+ forbidden_chars = r'[\\/:*?"<>|]'
1454
+ _i_temp = re.sub(forbidden_chars, '_', _i_temp)
1455
+ i_resized.save(f"artist_thumb/{model_name}/{_i_temp}.jpg")
1456
+ next = i_resized, positive, params['seed'], i.info, str(filename)
1457
+ result_list.append(next)
1458
+ return i_resized, positive, params['seed'], i.info, str(filename) if len(result_list) ==1 else result_list, response_time
1459
+ except Exception as e:
1460
+ error_message = str(e)
1461
+ raise
1462
+ except Exception as e:
1463
+ end_time = time.time()
1464
+ response_time = round(end_time - start_time, 2)
1465
+ if not error_message:
1466
+ if zipped_bytes is not None:
1467
+ try:
1468
+ error_message = zipped_bytes.decode('utf-8')[2:-2]
1469
+ except:
1470
+ error_message = str(e)
1471
+ else:
1472
+ error_message = str(e)
1473
+ log_error(error_message, "path_to_output_folder")
1474
+ return None, error_message, params['seed'], None, None, response_time