ssboost commited on
Commit
05a72e6
ยท
verified ยท
1 Parent(s): 5f55148

Update src/app.py

Browse files
Files changed (1) hide show
  1. src/app.py +730 -1
src/app.py CHANGED
@@ -1,2 +1,731 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
- exec(os.environ.get('APP'))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pillow_heif
3
+ import spaces
4
+ import torch
5
+ from PIL import Image, ImageEnhance, ImageFilter # ImageFilter ์ถ”๊ฐ€
6
+ from refiners.fluxion.utils import manual_seed, no_grad
7
+
8
+ from utils import load_ic_light, resize_modulo_8
9
+
10
+ import zipfile
11
+ from io import BytesIO
12
+ import tempfile
13
+ import cv2 # OpenCV ์ถ”๊ฐ€
14
+ import numpy as np # NumPy ์ถ”๊ฐ€
15
+
16
+ # HEIF/AVIF ์ด๋ฏธ์ง€ ์ง€์› ๋“ฑ๋ก
17
+ pillow_heif.register_heif_opener()
18
+ pillow_heif.register_avif_opener()
19
+
20
+ # GPU ์„ค์ •
21
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
22
+ DTYPE = torch.float16 if torch.cuda.is_available() and torch.cuda.is_bf16_supported() else torch.float32
23
+ ic_light = load_ic_light(device=DEVICE, dtype=DTYPE)
24
+
25
+ # ๋ชจ๋ธ์„ ์ง€์ •๋œ ๋””๋ฐ”์ด์Šค๋กœ ์ด๋™
26
+ ic_light.to(device=DEVICE, dtype=DTYPE)
27
+ ic_light.device = DEVICE
28
+ ic_light.dtype = DTYPE
29
+ ic_light.solver = ic_light.solver.to(device=DEVICE, dtype=DTYPE)
30
+
31
+ # ๋ฒˆ์—ญ ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐ ์„ค์ •
32
  import os
33
+ from openai import OpenAI
34
+ import uuid
35
+ import time
36
+ import logging
37
+ import random
38
+ from datetime import datetime, timedelta
39
+
40
+ # ๋กœ๊น… ์„ค์ •
41
+ logging.basicConfig(
42
+ level=logging.INFO,
43
+ format='%(asctime)s - %(message)s'
44
+ )
45
+ logger = logging.getLogger(__name__)
46
+
47
+ # API ํ‚ค ์„ค์ •
48
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
49
+
50
+ # API ํด๋ผ์ด์–ธํŠธ ์„ค์ •
51
+ openai_client = OpenAI(api_key=OPENAI_API_KEY)
52
+
53
+ def validate_input(text: str) -> bool:
54
+ """์ž…๋ ฅ ํ…์ŠคํŠธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ"""
55
+ if not text.strip():
56
+ return False
57
+ if not any('\u3131' <= char <= '\u318F' or '\uAC00' <= char <= '\uD7A3' for char in text):
58
+ return False
59
+ return True
60
+
61
+ def translate_to_english(input_text: str):
62
+ """ํ•œ๊ตญ์–ด๋ฅผ ์˜์–ด๋กœ ๋ฒˆ์—ญํ•˜๋Š” ํ•จ์ˆ˜ (GPT-4-mini ์‚ฌ์šฉ)"""
63
+ logger.info("GPT-4-mini ๋ฒˆ์—ญ ์‹œ์ž‘")
64
+
65
+ if not validate_input(input_text):
66
+ logger.info("์œ ํšจํ•˜์ง€ ์•Š์€ ์ž…๋ ฅ์ž…๋‹ˆ๋‹ค.")
67
+ return "์œ ํšจํ•˜์ง€ ์•Š์€ ์ž…๋ ฅ์ž…๋‹ˆ๋‹ค. ํ•œ๊ธ€์„ ํฌํ•จํ•œ ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
68
+
69
+ try:
70
+ current_time = int(time.time() * 1000)
71
+ random.seed(current_time)
72
+
73
+ temperature = random.uniform(0.4, 0.85)
74
+ top_p = random.uniform(0.9, 0.98)
75
+
76
+ request_id = str(uuid.uuid4())[:8]
77
+ timestamp_micro = int(time.time() * 1000000) % 1000
78
+ system_msg = f"REQ-{request_id}-{timestamp_micro}"
79
+
80
+ current_hour = datetime.now().hour
81
+ time_context = f"Consider the current time is {current_hour}:00. "
82
+
83
+ response = openai_client.chat.completions.create(
84
+ model="gpt-4o-mini",
85
+ messages=[
86
+ {
87
+ "role": "system",
88
+ "content": system_msg
89
+ },
90
+ {
91
+ "role": "user",
92
+ "content": f"""
93
+ 1. Translate the input Korean text into English with these rules:
94
+ 2. Output ONLY the English translation.
95
+ 3. Create a coherent, brief scene using provided words/phrases.
96
+ 4. Stay strictly within the scope of input words.
97
+ 5. Maintain flow and natural transitions.
98
+ 6. Keep scene descriptions concise but complete.
99
+ 7. Do not add external elements.
100
+ 8. Focus on core scene elements.
101
+ 9. Preserve original meaning and intent.
102
+ 10. No explanations or meta-commentary.
103
+ 11. No formatting beyond basic text.
104
+ 12. Just the direct English translation.
105
+ Additional guidance:
106
+ 13. Use input words harmoniously.
107
+ 14. Create clear mental imagery.
108
+ 15. Keep scene contained and focused.
109
+ 16. Ensure logical connections.
110
+ 17. Maintain narrative flow.
111
+ Input: {input_text} [Seed: {current_time}]
112
+ """
113
+ }
114
+ ],
115
+ max_tokens=100,
116
+ temperature=temperature,
117
+ top_p=top_p,
118
+ seed=current_time
119
+ )
120
+ translated = response.choices[0].message.content.strip()
121
+ logger.info("GPT-4-mini ๋ฒˆ์—ญ ์™„๋ฃŒ")
122
+ return translated
123
+
124
+ except Exception as e:
125
+ logger.error(f"๋ฒˆ์—ญ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}")
126
+ return f"๋ฒˆ์—ญ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
127
+
128
+ @spaces.GPU(duration=120)
129
+ @no_grad()
130
+ def generate_images(
131
+ image: Image.Image,
132
+ prompt: str,
133
+ ) -> tuple[Image.Image, Image.Image, Image.Image, Image.Image]:
134
+ assert image.mode == "RGBA", "์ž…๋ ฅ ์ด๋ฏธ์ง€๋Š” RGBA ๋ชจ๋“œ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."
135
+
136
+ seed = torch.seed()
137
+ manual_seed(seed)
138
+
139
+ negative_prompt = "dirty, messy, worst quality, low quality, watermark, signature, jpeg artifacts, deformed, monochrome, black and white"
140
+
141
+ condition_scale = 1.25
142
+ num_inference_steps = 25
143
+ strength_first_pass = 0.9
144
+ strength_second_pass = 0.5
145
+
146
+ image = resize_modulo_8(image, 768)
147
+
148
+ mask = image.getchannel("A")
149
+ image_rgb = image.convert("RGB")
150
+
151
+ clip_text_embedding = ic_light.compute_clip_text_embedding(text=prompt, negative_text=negative_prompt)
152
+ ic_light.set_ic_light_condition(image=image_rgb, mask=mask)
153
+
154
+ light_pref_image = None
155
+
156
+ if light_pref_image is None:
157
+ x = torch.randn_like(ic_light._ic_light_condition) # pyright: ignore[reportPrivateUsage]
158
+ strength_first_pass = 1.0
159
+ else:
160
+ x = ic_light.lda.image_to_latents(light_pref_image)
161
+ x = ic_light.solver.add_noise(x, noise=torch.randn_like(x), step=0)
162
+
163
+ num_steps = int(round(num_inference_steps / strength_first_pass))
164
+ first_step = int(num_steps * (1 - strength_first_pass))
165
+ ic_light.set_inference_steps(num_steps, first_step)
166
+
167
+ for step in ic_light.steps:
168
+ x = ic_light(
169
+ x,
170
+ step=step,
171
+ clip_text_embedding=clip_text_embedding,
172
+ condition_scale=condition_scale,
173
+ )
174
+
175
+ num_steps = int(round(num_inference_steps / strength_second_pass))
176
+ first_step = int(num_steps * (1 - strength_second_pass))
177
+ ic_light.set_inference_steps(num_steps, first_step)
178
+
179
+ x = ic_light.solver.add_noise(x, noise=torch.randn_like(x), step=first_step)
180
+
181
+ for step in ic_light.steps:
182
+ x = ic_light(
183
+ x,
184
+ step=step,
185
+ clip_text_embedding=clip_text_embedding,
186
+ condition_scale=condition_scale,
187
+ )
188
+
189
+ bg_image = ic_light.lda.latents_to_image(x)
190
+
191
+ result = Image.composite(image_rgb, bg_image, mask)
192
+
193
+ return image_rgb, bg_image, mask, result
194
+
195
+ @no_grad()
196
+ def adjust_final_image(
197
+ bg_image: Image.Image,
198
+ mask: Image.Image,
199
+ bg_brightness: float,
200
+ bg_contrast: float,
201
+ bg_saturation: float,
202
+ bg_temperature: float,
203
+ bg_vibrance: float,
204
+ bg_color_mixer_blues: float,
205
+ bg_shadows: float,
206
+ ) -> Image.Image:
207
+ print("Adjusting Final Image with the following parameters:")
208
+ print(f"Background - Brightness: {bg_brightness}, Contrast: {bg_contrast}, "
209
+ f"Saturation: {bg_saturation}, Temperature: {bg_temperature}, "
210
+ f"Vibrance: {bg_vibrance}, Blues: {bg_color_mixer_blues}, Shadows: {bg_shadows}")
211
+
212
+ enhancer = ImageEnhance.Brightness(bg_image)
213
+ bg_image = enhancer.enhance(bg_brightness)
214
+
215
+ enhancer = ImageEnhance.Contrast(bg_image)
216
+ bg_image = enhancer.enhance(bg_contrast)
217
+
218
+ enhancer = ImageEnhance.Color(bg_image)
219
+ bg_image = enhancer.enhance(bg_saturation)
220
+
221
+ if bg_temperature != 0.0:
222
+ cv_image = cv2.cvtColor(np.array(bg_image), cv2.COLOR_RGB2BGR).astype(np.float32)
223
+
224
+ value = float(bg_temperature) * 30
225
+ if value > 0:
226
+ cv_image[:, :, 2] = cv_image[:, :, 2] + value
227
+ cv_image[:, :, 0] = cv_image[:, :, 0] - value
228
+ else:
229
+ cv_image[:, :, 2] = cv_image[:, :, 2] + value
230
+ cv_image[:, :, 0] = cv_image[:, :, 0] - value
231
+
232
+ cv_image[:, :, 2] = np.clip(cv_image[:, :, 2], 0, 255)
233
+ cv_image[:, :, 0] = np.clip(cv_image[:, :, 0], 0, 255)
234
+
235
+ bg_image = Image.fromarray(cv2.cvtColor(cv_image.astype(np.uint8), cv2.COLOR_BGR2RGB))
236
+
237
+ if bg_vibrance != 0.0:
238
+ converter = ImageEnhance.Color(bg_image)
239
+ factor = 1 + (bg_vibrance / 100.0)
240
+ bg_image = converter.enhance(factor)
241
+
242
+ if bg_color_mixer_blues != 0.0:
243
+ r, g, b = bg_image.split()
244
+ b = b.point(lambda p: min(255, max(0, p + bg_color_mixer_blues)))
245
+ bg_image = Image.merge("RGB", (r, g, b))
246
+
247
+ if bg_shadows != 0.0:
248
+ grayscale = bg_image.convert("L")
249
+ mask_dark = grayscale.point(lambda p: p < 128 and 255)
250
+ mask_dark = mask_dark.convert("L")
251
+ mask_dark = mask_dark.filter(ImageFilter.GaussianBlur(radius=10))
252
+
253
+ if bg_shadows < 0:
254
+ factor = 1 + (bg_shadows / 100.0)
255
+ enhancer = ImageEnhance.Brightness(bg_image)
256
+ dark_adjusted = enhancer.enhance(factor)
257
+ else:
258
+ factor = 1 + (bg_shadows / 100.0)
259
+ enhancer = ImageEnhance.Brightness(bg_image)
260
+ dark_adjusted = enhancer.enhance(factor)
261
+
262
+ bg_image = Image.composite(dark_adjusted, bg_image, mask_dark)
263
+
264
+ return bg_image
265
+
266
+ def get_korean_timestamp():
267
+ korea_time = datetime.utcnow() + timedelta(hours=9)
268
+ return korea_time.strftime('%Y%m%d_%H%M%S')
269
+
270
+ def download_image(image, input_image_name):
271
+ if image is None:
272
+ return None
273
+
274
+ timestamp = get_korean_timestamp()
275
+ if input_image_name and hasattr(input_image_name, 'name'):
276
+ base_name = input_image_name.name.split('.')[0]
277
+ else:
278
+ base_name = "์ด๋ฏธ์ง€"
279
+
280
+ file_name = f"[๋์žฅAI]๋ฐฐ๊ฒฝ๋ฐ”๊พธ๊ธฐ_{base_name}_{timestamp}.jpg"
281
+
282
+ temp_file_path = tempfile.gettempdir() + "/" + file_name
283
+ image.save(temp_file_path, format="JPEG")
284
+ return temp_file_path
285
+
286
+ def download_all(original_image, bg_image, final_image):
287
+ if original_image is None or bg_image is None or final_image is None:
288
+ print("Download function received None input.")
289
+ return None
290
+ print("Preparing images for download...")
291
+
292
+ if original_image.mode != "RGB":
293
+ original_image = original_image.convert("RGB")
294
+ if bg_image.mode != "RGB":
295
+ bg_image = bg_image.convert("RGB")
296
+ if final_image.mode != "RGB":
297
+ final_image = final_image.convert("RGB")
298
+
299
+ class InputFileName:
300
+ def __init__(self, name):
301
+ self.name = name
302
+
303
+ timestamp = get_korean_timestamp()
304
+ original_path = download_image(original_image, InputFileName("original_image.jpg"))
305
+ bg_path = download_image(bg_image, InputFileName("background_image.jpg"))
306
+ final_path = download_image(final_image, InputFileName("final_image.jpg"))
307
+
308
+ zip_name = f"[๋์žฅAI]๋ฐฐ๊ฒฝ๋ฐ”๊พธ๊ธฐ_{timestamp}.zip"
309
+ zip_path = tempfile.gettempdir() + "/" + zip_name
310
+
311
+ with zipfile.ZipFile(zip_path, 'w') as zip_file:
312
+ zip_file.write(original_path, os.path.basename(original_path))
313
+ zip_file.write(bg_path, os.path.basename(bg_path))
314
+ zip_file.write(final_path, os.path.basename(final_path))
315
+
316
+ print(f"ZIP file created at {zip_path}")
317
+ return zip_path
318
+
319
+ def reset_sliders(initial_result):
320
+ print("Resetting sliders to default values.")
321
+ return (
322
+ "ํ•„ํ„ฐ์—†์Œ",
323
+ gr.update(value=1.0),
324
+ gr.update(value=1.0),
325
+ gr.update(value=1.0),
326
+ gr.update(value=0.0),
327
+ gr.update(value=0.0),
328
+ gr.update(value=0.0),
329
+ gr.update(value=0.0),
330
+ initial_result,
331
+ )
332
+
333
+ def create_interface():
334
+ css = """
335
+ /* ํ”„๋กฌํ”„ํŠธ ํ…์ŠคํŠธ๋ฐ•์Šค ๋ผ๋ฒจ๊ณผ ์ž…๋ ฅ ํ…์ŠคํŠธ๋งŒ ๊ฒ€์€์ƒ‰์œผ๋กœ ์„ค์ • */
336
+ .gr-textbox > label {
337
+ color: #000 !important;
338
+ }
339
+ .gr-textbox input {
340
+ color: #000 !important;
341
+ }
342
+
343
+ /* ํ•„ํ„ฐ ์„ ํƒ ๋ผ๋””์˜ค ๋ฒ„ํŠผ ๋ผ๋ฒจ๋งŒ ๊ฒ€์€์ƒ‰์œผ๋กœ ์„ค์ • */
344
+ .gradio-radio > label {
345
+ color: #000 !important;
346
+ }
347
+
348
+ /* ์Šฌ๋ผ์ด๋” ๋ผ๋ฒจ๊ณผ ํ˜„์žฌ ๊ฐ’ ํ…์ŠคํŠธ๋งŒ ๊ฒ€์€์ƒ‰์œผ๋กœ ์„ค์ • */
349
+ .gr-slider > label {
350
+ color: #000 !important;
351
+ }
352
+ .gr-slider .slider-value {
353
+ color: #000 !important;
354
+ }
355
+
356
+ .gradio-radio label[aria-checked="true"] {
357
+ color: #000 !important;
358
+ background-color: #fff !important;
359
+ padding: 4px 8px;
360
+ border-radius: 4px;
361
+ border: 1px solid #000 !important;
362
+ }
363
+
364
+ .gradio-radio label[aria-checked="false"] {
365
+ color: #000 !important;
366
+ background-color: #fff !important;
367
+ border: 1px solid #000 !important;
368
+ }
369
+
370
+ .gradio-radio input[type="radio"] + label::before {
371
+ display: none;
372
+ }
373
+
374
+ .gradio-radio input[type="radio"]:checked + label::after {
375
+ content: "";
376
+ display: none;
377
+ }
378
+
379
+ .btn-primary, .btn-secondary, .gr-button {
380
+ color: #000 !important;
381
+ }
382
+
383
+ /* JPG ์ด๋ฏธ์ง€ ๋‹ค์šด๋ฐ›๊ธฐ ๋ฒ„ํŠผ ๋ฐฐ๊ฒฝ์ƒ‰ ๊ฒ€์€์ƒ‰/๊ธ€์ž์ƒ‰ ํฐ์ƒ‰ ๊ฐ•์ œ ์ ์šฉ */
384
+ .download-container .download-button.gr-button {
385
+ background-color: #000 !important;
386
+ color: #fff !important;
387
+ border: none !important;
388
+ }
389
+
390
+ .download-container .download-button.gr-button:hover {
391
+ background-color: #333 !important;
392
+ color: #fff !important;
393
+ }
394
+ """
395
+
396
+ filters = [
397
+ {
398
+ "name": "ํ•„ํ„ฐ์—†์Œ",
399
+ "bg_brightness": 1.0,
400
+ "bg_contrast": 1.0,
401
+ "bg_saturation": 1.0,
402
+ "bg_temperature": 0.0,
403
+ "bg_vibrance": 0.0,
404
+ "bg_color_mixer_blues": 0.0,
405
+ "bg_shadows": 0.0
406
+ },
407
+ {
408
+ "name": "๊นจ๋—ํ•œ",
409
+ "bg_brightness": 1.3,
410
+ "bg_contrast": 1.2,
411
+ "bg_saturation": 1.0,
412
+ "bg_temperature": -0.2,
413
+ "bg_vibrance": -20.0,
414
+ "bg_color_mixer_blues": 5.0,
415
+ "bg_shadows": -10.0
416
+ },
417
+ {
418
+ "name": "๋”ฐ์Šคํ•œ",
419
+ "bg_brightness": 1.3,
420
+ "bg_contrast": 1.2,
421
+ "bg_saturation": 0.8,
422
+ "bg_temperature": 0.0,
423
+ "bg_vibrance": -10.0,
424
+ "bg_color_mixer_blues": 2.0,
425
+ "bg_shadows": -10.0
426
+ },
427
+ {
428
+ "name": "ํ‘ธ๋ฅธ๋น›",
429
+ "bg_brightness": 1.3,
430
+ "bg_contrast": 1.0,
431
+ "bg_saturation": 1.0,
432
+ "bg_temperature": 0.0,
433
+ "bg_vibrance": 0.0,
434
+ "bg_color_mixer_blues": 10.0,
435
+ "bg_shadows": 5.0
436
+ }
437
+ ]
438
+
439
+ default_filter = next(filter for filter in filters if filter["name"] == "๊นจ๋—ํ•œ")
440
+
441
+ with gr.Blocks(theme=gr.themes.Soft(
442
+ primary_hue=gr.themes.Color(
443
+ c50="#FFF7ED",
444
+ c100="#FFEDD5",
445
+ c200="#FED7AA",
446
+ c300="#FDBA74",
447
+ c400="#FB923C",
448
+ c500="#F97316",
449
+ c600="#EA580C",
450
+ c700="#C2410C",
451
+ c800="#9A3412",
452
+ c900="#7C2D12",
453
+ c950="#431407",
454
+ ),
455
+ secondary_hue="zinc",
456
+ neutral_hue="zinc",
457
+ font=("Pretendard", "sans-serif")
458
+ ), css=css) as demo:
459
+
460
+ with gr.Row():
461
+ with gr.Column(scale=1):
462
+ input_image = gr.Image(
463
+ label="์ด๋ฏธ์ง€ ์ถ”๊ฐ€",
464
+ image_mode="RGBA",
465
+ type="pil",
466
+ )
467
+ prompt = gr.Textbox(
468
+ label="ํ”„๋กฌํ”„ํŠธ (ํ•œ๊ตญ์–ด)",
469
+ placeholder="๋ˆˆ๋ฎ์ธ ํžˆ๋ง๋ผ์•ผ, ๋ญ‰๊ฒŒ๊ตฌ๋ฆ„, ํฐ์ƒ‰ ๋ฐ”๋‹ฅ์— ๋†“์—ฌ์žˆ๋Š” ์–‘๋ง",
470
+ )
471
+ run_button = gr.Button(
472
+ value="์ด๋ฏธ์ง€ ์ƒ์„ฑ",
473
+ variant="primary",
474
+ size="lg"
475
+ )
476
+ reset_button = gr.Button(
477
+ value="ํ•„ํ„ฐ ์ดˆ๊ธฐํ™”",
478
+ variant="secondary",
479
+ size="lg"
480
+ )
481
+
482
+ filter_radio = gr.Radio(
483
+ label="ํ•„ํ„ฐ ์„ ํƒ",
484
+ choices=["ํ•„ํ„ฐ์—†์Œ", "๊นจ๋—ํ•œ", "๋”ฐ์Šคํ•œ", "ํ‘ธ๋ฅธ๋น›"],
485
+ value="๊นจ๋—ํ•œ",
486
+ type="value",
487
+ )
488
+
489
+ bg_brightness = gr.Slider(label="๋ฐ๊ธฐ", minimum=0.1, maximum=5.0, value=default_filter["bg_brightness"], step=0.1)
490
+ bg_contrast = gr.Slider(label="๋Œ€๋น„", minimum=0.1, maximum=5.0, value=default_filter["bg_contrast"], step=0.1)
491
+ bg_saturation = gr.Slider(label="์ฑ„๋„", minimum=0.0, maximum=5.0, value=default_filter["bg_saturation"], step=0.1)
492
+ bg_temperature = gr.Slider(
493
+ label="์ƒ‰์˜จ๋„",
494
+ minimum=-1.0,
495
+ maximum=1.0,
496
+ value=default_filter["bg_temperature"],
497
+ step=0.1
498
+ )
499
+ bg_vibrance = gr.Slider(label="ํ™œ๊ธฐ", minimum=-100.0, maximum=100.0, value=default_filter["bg_vibrance"], step=1.0)
500
+ bg_color_mixer_blues = gr.Slider(label="์ปฌ๋Ÿฌ ๋ฏน์„œ (๋ธ”๋ฃจ)", minimum=-100.0, maximum=100.0, value=default_filter["bg_color_mixer_blues"], step=1.0)
501
+ bg_shadows = gr.Slider(label="๊ทธ๋ฆผ์ž", minimum=-100.0, maximum=100.0, value=default_filter["bg_shadows"], step=1.0)
502
+
503
+ with gr.Column(scale=2):
504
+ background_output = gr.Image(
505
+ label="์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€",
506
+ type="pil",
507
+ interactive=False
508
+ )
509
+ final_output = gr.Image(
510
+ label="ํ•„ํ„ฐ ์ ์šฉ ์ด๋ฏธ์ง€",
511
+ type="pil",
512
+ interactive=False
513
+ )
514
+ with gr.Row(elem_classes="download-container"):
515
+ download_button = gr.Button(
516
+ value="JPG๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ",
517
+ elem_classes="download-button",
518
+ variant="primary",
519
+ size="lg"
520
+ )
521
+ with gr.Row(elem_classes="download-container"):
522
+ download_output = gr.File(label="JPG ์ด๋ฏธ์ง€ ๋‹ค์šด๋ฐ›๊ธฐ", elem_classes="download-output")
523
+
524
+ mask_state = gr.State()
525
+ image_rgb_state = gr.State()
526
+ initial_result = gr.State()
527
+
528
+ def apply_filter_preset(selected_filter):
529
+ for f in filters:
530
+ if f["name"] == selected_filter:
531
+ return (
532
+ gr.update(value=f["bg_brightness"]),
533
+ gr.update(value=f["bg_contrast"]),
534
+ gr.update(value=f["bg_saturation"]),
535
+ gr.update(value=f["bg_temperature"]),
536
+ gr.update(value=f["bg_vibrance"]),
537
+ gr.update(value=f["bg_color_mixer_blues"]),
538
+ gr.update(value=f["bg_shadows"]),
539
+ )
540
+ return (
541
+ gr.update(value=1.0),
542
+ gr.update(value=1.0),
543
+ gr.update(value=1.0),
544
+ gr.update(value=0.0),
545
+ gr.update(value=0.0),
546
+ gr.update(value=0.0),
547
+ gr.update(value=0.0),
548
+ )
549
+
550
+ filter_radio.change(
551
+ fn=apply_filter_preset,
552
+ inputs=[filter_radio],
553
+ outputs=[
554
+ bg_brightness,
555
+ bg_contrast,
556
+ bg_saturation,
557
+ bg_temperature,
558
+ bg_vibrance,
559
+ bg_color_mixer_blues,
560
+ bg_shadows,
561
+ ],
562
+ )
563
+
564
+ def on_generate(image, prompt, bg_brightness, bg_contrast, bg_saturation, bg_temperature, bg_vibrance, bg_color_mixer_blues, bg_shadows):
565
+ if not prompt.strip():
566
+ logger.info("ํ”„๋กฌํ”„ํŠธ๊ฐ€ ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.")
567
+ final_prompt = "high-quality professional studio photography, Realistic soft white tone bright lighting, HEIC, CR2, NEF"
568
+ else:
569
+ translated_prompt = translate_to_english(prompt)
570
+ if translated_prompt.startswith("์œ ํšจํ•˜์ง€ ์•Š์€ ์ž…๋ ฅ") or translated_prompt.startswith("๋ฒˆ์—ญ ์ค‘ ์˜ค๋ฅ˜"):
571
+ return None, None, None, None, None
572
+
573
+ final_prompt = f"{translated_prompt}, high-quality professional studio photography, Realistic soft white tone bright lighting, HEIC, CR2, NEF"
574
+
575
+ image_rgb, bg_img, mask, result = generate_images(image, final_prompt)
576
+ print("Image generation completed.")
577
+
578
+ if bg_img is not None and mask is not None and image_rgb is not None:
579
+ adjusted_bg = adjust_final_image(
580
+ bg_image=bg_img,
581
+ mask=mask,
582
+ bg_brightness=bg_brightness,
583
+ bg_contrast=bg_contrast,
584
+ bg_saturation=bg_saturation,
585
+ bg_temperature=bg_temperature,
586
+ bg_vibrance=bg_vibrance,
587
+ bg_color_mixer_blues=bg_color_mixer_blues,
588
+ bg_shadows=bg_shadows,
589
+ )
590
+ final_result = Image.composite(image_rgb, adjusted_bg, mask)
591
+ else:
592
+ final_result = result
593
+
594
+ initial_result.value = final_result
595
+
596
+ return bg_img, mask, final_result, image_rgb, final_result
597
+
598
+ run_button.click(
599
+ fn=on_generate,
600
+ inputs=[
601
+ input_image,
602
+ prompt,
603
+ bg_brightness,
604
+ bg_contrast,
605
+ bg_saturation,
606
+ bg_temperature,
607
+ bg_vibrance,
608
+ bg_color_mixer_blues,
609
+ bg_shadows,
610
+ ],
611
+ outputs=[
612
+ background_output,
613
+ mask_state,
614
+ final_output,
615
+ image_rgb_state,
616
+ initial_result,
617
+ ],
618
+ )
619
+
620
+ def on_adjust(
621
+ image_rgb,
622
+ bg_image, mask,
623
+ bg_brightness, bg_contrast, bg_saturation, bg_temperature, bg_vibrance, bg_color_mixer_blues, bg_shadows,
624
+ ):
625
+ if bg_image is None or mask is None or image_rgb is None:
626
+ print("Adjust function received None input.")
627
+ return None
628
+ print(f"Adjusting background image... Current slider values:")
629
+ print(f"Brightness: {bg_brightness}, Contrast: {bg_contrast}, Saturation: {bg_saturation}, "
630
+ f"Temperature: {bg_temperature}, Vibrance: {bg_vibrance}, Blues: {bg_color_mixer_blues}, Shadows: {bg_shadows}")
631
+
632
+ adjusted_bg = adjust_final_image(
633
+ bg_image=bg_image,
634
+ mask=mask,
635
+ bg_brightness=bg_brightness,
636
+ bg_contrast=bg_contrast,
637
+ bg_saturation=bg_saturation,
638
+ bg_temperature=bg_temperature,
639
+ bg_vibrance=bg_vibrance,
640
+ bg_color_mixer_blues=bg_color_mixer_blues,
641
+ bg_shadows=bg_shadows,
642
+ )
643
+
644
+ print(f"adjusted_bg size: {adjusted_bg.size}, mode: {adjusted_bg.mode}")
645
+ adjusted_bg.save("adjusted_bg_debug.jpg")
646
+
647
+ input_image_rgb = image_rgb
648
+ print(f"input_image_rgb size: {input_image_rgb.size}, mode: {input_image_rgb.mode}")
649
+ print(f"adjusted_bg size: {adjusted_bg.size}, mode: {adjusted_bg.mode}")
650
+ print(f"mask size: {mask.size}, mode: {mask.mode}")
651
+
652
+ if input_image_rgb.size != adjusted_bg.size:
653
+ print(f"Resizing input_image_rgb from {input_image_rgb.size} to {adjusted_bg.size}")
654
+ input_image_rgb = input_image_rgb.resize(adjusted_bg.size)
655
+
656
+ mask = mask.convert("L")
657
+
658
+ try:
659
+ final_result = Image.composite(input_image_rgb, adjusted_bg, mask)
660
+ except ValueError as e:
661
+ print(f"Composite error: {e}")
662
+ return None
663
+
664
+ final_result.save("final_result_debug.jpg")
665
+ print("Final image composite completed.")
666
+
667
+ initial_result.value = final_result
668
+
669
+ return final_result
670
+
671
+ bg_sliders = [
672
+ bg_brightness,
673
+ bg_contrast,
674
+ bg_saturation,
675
+ bg_temperature,
676
+ bg_vibrance,
677
+ bg_color_mixer_blues,
678
+ bg_shadows,
679
+ ]
680
+
681
+ for slider in bg_sliders:
682
+ slider.change(
683
+ fn=on_adjust,
684
+ inputs=[
685
+ image_rgb_state,
686
+ background_output,
687
+ mask_state,
688
+ bg_brightness,
689
+ bg_contrast,
690
+ bg_saturation,
691
+ bg_temperature,
692
+ bg_vibrance,
693
+ bg_color_mixer_blues,
694
+ bg_shadows,
695
+ ],
696
+ outputs=final_output,
697
+ )
698
+
699
+ reset_button.click(
700
+ fn=reset_sliders,
701
+ inputs=[final_output],
702
+ outputs=[
703
+ filter_radio,
704
+ bg_brightness,
705
+ bg_contrast,
706
+ bg_saturation,
707
+ bg_temperature,
708
+ bg_vibrance,
709
+ bg_color_mixer_blues,
710
+ bg_shadows,
711
+ final_output,
712
+ ],
713
+ )
714
+
715
+ download_button.click(
716
+ fn=download_all,
717
+ inputs=[
718
+ input_image,
719
+ background_output,
720
+ final_output
721
+ ],
722
+ outputs=download_output,
723
+ )
724
+
725
+ return demo
726
+
727
+ if __name__ == "__main__":
728
+ logger.info("์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘")
729
+ demo = create_interface()
730
+ demo.queue()
731
+ demo.launch(server_name='0.0.0.0')