ssboost commited on
Commit
265c64d
ยท
verified ยท
1 Parent(s): 01228d5

Update src/app.py

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