Kims12 commited on
Commit
6cd8947
ยท
verified ยท
1 Parent(s): 9f8f9fc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +513 -15
app.py CHANGED
@@ -1,15 +1,513 @@
1
- google-genai==1.5.0
2
- google-generativeai==0.3.1
3
- gradio==5.21.0
4
- pydantic==2.10.6
5
- pillow==10.2.0
6
- python-dotenv
7
- basicsr==1.4.2
8
- facexlib==0.3.0
9
- gfpgan==1.3.8
10
- opencv-python==4.9.0.80
11
- realesrgan==0.3.0
12
- torch==2.3.0
13
- torchvision==0.18.0
14
- numpy==1.26.4
15
- tqdm==4.66.2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tempfile
3
+ from PIL import Image
4
+ import gradio as gr
5
+ import logging
6
+ import re
7
+ import time
8
+
9
+ from google import genai
10
+ from google.genai import types
11
+ from dotenv import load_dotenv
12
+ load_dotenv()
13
+
14
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
15
+ logger = logging.getLogger(__name__)
16
+
17
+ def save_binary_file(file_name, data):
18
+ with open(file_name, "wb") as f:
19
+ f.write(data)
20
+
21
+ def translate_prompt_to_english(prompt):
22
+ """
23
+ ์ž…๋ ฅ๋œ ํ”„๋กฌํ”„ํŠธ์— ํ•œ๊ธ€์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉด Geminiโ€‘2.0โ€‘flash ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜์–ด๋กœ ๋ฒˆ์—ญํ•ฉ๋‹ˆ๋‹ค.
24
+ ํ•œ๊ธ€์ด ์—†์œผ๋ฉด ์›๋ณธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
25
+ ์ค‘์š”: #1, #2, #3 ํƒœ๊ทธ๋Š” ๋ฒˆ์—ญ ์ „ํ›„์— ๋ฐ˜๋“œ์‹œ ๋ณด์กด๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
26
+ """
27
+ if not re.search("[๊ฐ€-ํžฃ]", prompt):
28
+ return prompt
29
+
30
+ prompt = prompt.replace("#1", "IMAGE_TAG_ONE")
31
+ prompt = prompt.replace("#2", "IMAGE_TAG_TWO")
32
+ prompt = prompt.replace("#3", "IMAGE_TAG_THREE")
33
+
34
+ try:
35
+ api_key = os.environ.get("GEMINI_API_KEY")
36
+ if not api_key:
37
+ logger.error("Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
38
+ prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
39
+ prompt = prompt.replace("IMAGE_TAG_TWO", "#2")
40
+ prompt = prompt.replace("IMAGE_TAG_THREE", "#3")
41
+ return prompt
42
+
43
+ client = genai.Client(api_key=api_key)
44
+ translation_prompt = f"""
45
+ Translate the following Korean text to English:
46
+
47
+ {prompt}
48
+
49
+ IMPORTANT: The tokens IMAGE_TAG_ONE, IMAGE_TAG_TWO, and IMAGE_TAG_THREE are special tags
50
+ and must be preserved exactly as is in your translation. Do not translate these tokens.
51
+ """
52
+
53
+ logger.info(f"Translation prompt: {translation_prompt}")
54
+ response = client.models.generate_content(
55
+ model="gemini-2.0-flash",
56
+ contents=[translation_prompt],
57
+ config=types.GenerateContentConfig(
58
+ response_modalities=['Text'],
59
+ temperature=0.2,
60
+ top_p=0.95,
61
+ top_k=40,
62
+ max_output_tokens=512
63
+ )
64
+ )
65
+
66
+ translated_text = ""
67
+ for part in response.candidates[0].content.parts:
68
+ if hasattr(part, 'text') and part.text:
69
+ translated_text += part.text
70
+
71
+ if translated_text.strip():
72
+ translated_text = translated_text.replace("IMAGE_TAG_ONE", "#1")
73
+ translated_text = translated_text.replace("IMAGE_TAG_TWO", "#2")
74
+ translated_text = translated_text.replace("IMAGE_TAG_THREE", "#3")
75
+ logger.info(f"Translated text: {translated_text.strip()}")
76
+ return translated_text.strip()
77
+ else:
78
+ logger.warning("๋ฒˆ์—ญ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์›๋ณธ ํ”„๋กฌํ”„ํŠธ ์‚ฌ์šฉ")
79
+ prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
80
+ prompt = prompt.replace("IMAGE_TAG_TWO", "#2")
81
+ prompt = prompt.replace("IMAGE_TAG_THREE", "#3")
82
+ return prompt
83
+ except Exception as e:
84
+ logger.exception("๋ฒˆ์—ญ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
85
+ prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
86
+ prompt = prompt.replace("IMAGE_TAG_TWO", "#2")
87
+ prompt = prompt.replace("IMAGE_TAG_THREE", "#3")
88
+ return prompt
89
+
90
+ def preprocess_prompt(prompt, image1, image2, image3):
91
+ """
92
+ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ธฐ๋Šฅ ๋ช…๋ น์„ ํ•ด์„
93
+ """
94
+ has_img1 = image1 is not None
95
+ has_img2 = image2 is not None
96
+ has_img3 = image3 is not None
97
+
98
+ if "#1" in prompt and not has_img1:
99
+ prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
100
+ else:
101
+ prompt = prompt.replace("#1", "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
102
+
103
+ if "#2" in prompt and not has_img2:
104
+ prompt = prompt.replace("#2", "๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
105
+ else:
106
+ prompt = prompt.replace("#2", "๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
107
+
108
+ if "#3" in prompt and not has_img3:
109
+ prompt = prompt.replace("#3", "์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(์—†์Œ)")
110
+ else:
111
+ prompt = prompt.replace("#3", "์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€")
112
+
113
+ if "1. ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ" in prompt:
114
+ desc_match = re.search(r'#1์„ "(.*?)"์œผ๋กœ ๋ฐ”๊ฟ”๋ผ', prompt)
115
+ if desc_match:
116
+ description = desc_match.group(1)
117
+ prompt = f"์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ {description}์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”. ์›๋ณธ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ๋‚ด์šฉ์€ ์œ ์ง€ํ•˜๋˜ ์ƒˆ๋กœ์šด ์Šคํƒ€์ผ๊ณผ ๋ถ„์œ„๊ธฐ๋กœ ์žฌํ•ด์„ํ•ด์ฃผ์„ธ์š”."
118
+ else:
119
+ prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ์ฐฝ์˜์ ์œผ๋กœ ๋ณ€ํ˜•ํ•ด์ฃผ์„ธ์š”. ๋” ์ƒ์ƒํ•˜๊ณ  ์˜ˆ์ˆ ์ ์ธ ๋ฒ„์ „์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
120
+
121
+ elif "2. ๊ธ€์ž์ง€์šฐ๊ธฐ" in prompt:
122
+ text_match = re.search(r'#1์—์„œ "(.*?)"๋ฅผ ์ง€์›Œ๋ผ', prompt)
123
+ if text_match:
124
+ text_to_remove = text_match.group(1)
125
+ prompt = f"์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์—์„œ '{text_to_remove}' ํ…์ŠคํŠธ๋ฅผ ์ฐพ์•„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ œ๊ฑฐํ•ด์ฃผ์„ธ์š”. ํ…์ŠคํŠธ๊ฐ€ ์žˆ๋˜ ๋ถ€๋ถ„์„ ๋ฐฐ๊ฒฝ๊ณผ ์กฐํ™”๋กญ๊ฒŒ ์ฑ„์›Œ์ฃผ์„ธ์š”."
126
+ else:
127
+ prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์—์„œ ๋ชจ๋“  ํ…์ŠคํŠธ๋ฅผ ์ฐพ์•„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ œ๊ฑฐํ•ด์ฃผ์„ธ์š”. ๊น”๋”ํ•œ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”."
128
+
129
+ elif "4. ์˜ท๋ฐ”๊พธ๊ธฐ" in prompt:
130
+ prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์ธ๋ฌผ ์˜์ƒ์„ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์˜์ƒ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”. ์˜์ƒ์˜ ์Šคํƒ€์ผ๊ณผ ์ƒ‰์ƒ์€ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ๋”ฐ๋ฅด๋˜, ์‹ ์ฒด ๋น„์œจ๊ณผ ํฌ์ฆˆ๋Š” ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ์œ ์ง€ํ•ด์ฃผ์„ธ์š”."
131
+
132
+ elif "5. ๋ฐฐ๊ฒฝ๋ฐ”๊พธ๊ธฐ" in prompt:
133
+ prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์„ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์„ธ์š”. ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ํ”ผ์‚ฌ์ฒด๋Š” ์œ ์ง€ํ•˜๊ณ , ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ๊ณผ ์กฐํ™”๋กญ๊ฒŒ ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”."
134
+
135
+ elif "6. ์ด๋ฏธ์ง€ ํ•ฉ์„ฑ(์ƒํ’ˆํฌํ•จ)" in prompt:
136
+ prompt = "์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์™€ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€(๋˜๋Š” ์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€)๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”. ๋ชจ๋“  ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ์š”์†Œ๋ฅผ ํฌํ•จํ•˜๊ณ , ํŠนํžˆ ์ƒํ’ˆ์ด ๋‹๋ณด์ด๋„๋ก ์กฐํ™”๋กญ๊ฒŒ ํ†ตํ•ฉํ•ด์ฃผ์„ธ์š”."
137
+
138
+ prompt += " ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”. ์ด๋ฏธ์ง€์— ํ…์ŠคํŠธ๋‚˜ ๊ธ€์ž๋ฅผ ํฌํ•จํ•˜์ง€ ๋งˆ์„ธ์š”."
139
+ return prompt
140
+
141
+ def generate_with_images(prompt, images, variation_index=0):
142
+ """
143
+ API ํ˜ธ์ถœ์„ ํ†ตํ•ด ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
144
+ variation_index๋กœ ๋‹ค์–‘ํ•œ ๋ณ€ํ™”๋ฅผ ์ค๋‹ˆ๋‹ค.
145
+ """
146
+ try:
147
+ api_key = os.environ.get("GEMINI_API_KEY")
148
+ if not api_key:
149
+ return None, "API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
150
+
151
+ client = genai.Client(api_key=api_key)
152
+ logger.info(f"Gemini API ์š”์ฒญ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: {prompt}, ๋ณ€ํ˜• ์ธ๋ฑ์Šค: {variation_index}")
153
+
154
+ variation_suffixes = [
155
+ " Create this as the first variation. Do not add any text, watermarks, or labels to the image.",
156
+ " Create this as the second variation with more vivid colors. Do not add any text, watermarks, or labels to the image.",
157
+ " Create this as the third variation with a more creative style. Do not add any text, watermarks, or labels to the image.",
158
+ " Create this as the fourth variation with enhanced details. Do not add any text, watermarks, or labels to the image."
159
+ ]
160
+
161
+ if variation_index < len(variation_suffixes):
162
+ prompt = prompt + variation_suffixes[variation_index]
163
+ else:
164
+ prompt = prompt + " Do not add any text, watermarks, or labels to the image."
165
+
166
+ contents = [prompt]
167
+ for idx, img in enumerate(images, 1):
168
+ if img is not None:
169
+ contents.append(img)
170
+ logger.info(f"์ด๋ฏธ์ง€ #{idx} ์ถ”๊ฐ€๋จ")
171
+
172
+ response = client.models.generate_content(
173
+ model="gemini-2.0-flash-exp-image-generation",
174
+ contents=contents,
175
+ config=types.GenerateContentConfig(
176
+ response_modalities=['Text', 'Image'],
177
+ temperature=1,
178
+ top_p=0.95,
179
+ top_k=40,
180
+ max_output_tokens=8192
181
+ )
182
+ )
183
+
184
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
185
+ temp_path = tmp.name
186
+ result_text = ""
187
+ image_found = False
188
+ for part in response.candidates[0].content.parts:
189
+ if hasattr(part, 'text') and part.text:
190
+ result_text += part.text
191
+ logger.info(f"์‘๋‹ต ํ…์ŠคํŠธ: {part.text}")
192
+ elif hasattr(part, 'inline_data') and part.inline_data:
193
+ save_binary_file(temp_path, part.inline_data.data)
194
+ image_found = True
195
+ logger.info("์‘๋‹ต์—์„œ ์ด๋ฏธ์ง€ ์ถ”์ถœ ์„ฑ๊ณต")
196
+ if not image_found:
197
+ return None, f"API์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์‘๋‹ต ํ…์ŠคํŠธ: {result_text}"
198
+ result_img = Image.open(temp_path)
199
+ if result_img.mode == "RGBA":
200
+ result_img = result_img.convert("RGB")
201
+ return result_img, f"์ด๋ฏธ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. {result_text}"
202
+ except Exception as e:
203
+ logger.exception("์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
204
+ return None, f"์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
205
+
206
+ def process_images_with_prompt(image1, image2, image3, prompt, variation_index=0, max_retries=3):
207
+ """
208
+ 3๊ฐœ์˜ ์ด๋ฏธ์ง€์™€ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ตœ์ข… ์˜์–ด ํ”„๋กฌํ”„ํŠธ(final_prompt)๋ฅผ ์ƒ์„ฑํ•œ ํ›„,
209
+ API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์ตœ๋Œ€ max_retries ํšŸ์ˆ˜๋งŒํผ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.
210
+ """
211
+ retry_count = 0
212
+ last_error = None
213
+
214
+ while retry_count < max_retries:
215
+ try:
216
+ images = [image1, image2, image3]
217
+ valid_images = [img for img in images if img is not None]
218
+ if not valid_images:
219
+ return None, "์ ์–ด๋„ ํ•˜๋‚˜์˜ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.", ""
220
+
221
+ if prompt and prompt.strip():
222
+ processed_prompt = preprocess_prompt(prompt, image1, image2, image3)
223
+ if re.search("[๊ฐ€-ํžฃ]", processed_prompt):
224
+ final_prompt = translate_prompt_to_english(processed_prompt)
225
+ else:
226
+ final_prompt = processed_prompt
227
+ else:
228
+ if len(valid_images) == 1:
229
+ final_prompt = "Please creatively transform this image into a more vivid and artistic version. Do not include any text or watermarks in the generated image."
230
+ logger.info("Default prompt generated for single image")
231
+ elif len(valid_images) == 2:
232
+ final_prompt = "Please seamlessly composite these two images, integrating their key elements harmoniously into a single image. Do not include any text or watermarks in the generated image."
233
+ logger.info("Default prompt generated for two images")
234
+ else:
235
+ final_prompt = "Please creatively composite these three images, combining their main elements into a cohesive and natural scene. Do not include any text or watermarks in the generated image."
236
+ logger.info("Default prompt generated for three images")
237
+
238
+ result_img, status = generate_with_images(final_prompt, valid_images, variation_index)
239
+ if result_img is not None:
240
+ return result_img, status, final_prompt
241
+ else:
242
+ last_error = status
243
+ retry_count += 1
244
+ logger.warning(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์‹คํŒจ, ์žฌ์‹œ๋„ {retry_count}/{max_retries}: {status}")
245
+ time.sleep(1)
246
+ except Exception as e:
247
+ last_error = str(e)
248
+ retry_count += 1
249
+ logger.exception(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ์žฌ์‹œ๋„ {retry_count}/{max_retries}:")
250
+ time.sleep(1)
251
+
252
+ return None, f"์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜({max_retries}ํšŒ) ์ดˆ๊ณผ ํ›„ ์‹คํŒจ: {last_error}", prompt
253
+
254
+ def generate_multiple_images(image1, image2, image3, prompt, progress=gr.Progress()):
255
+ """
256
+ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ด๋ฏธ์ง€๋ฅผ ์ฐจ๋ก€๋Œ€๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
257
+ """
258
+ results = []
259
+ statuses = []
260
+ prompts = []
261
+
262
+ num_images = 4
263
+ max_retries = 3
264
+
265
+ progress(0, desc="์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค€๋น„ ์ค‘...")
266
+
267
+ for i in range(num_images):
268
+ progress((i / num_images), desc=f"{i+1}/{num_images} ์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘...")
269
+ result_img, status, final_prompt = process_images_with_prompt(image1, image2, image3, prompt, i, max_retries)
270
+
271
+ if result_img is not None:
272
+ results.append(result_img)
273
+ statuses.append(f"์ด๋ฏธ์ง€ #{i+1}: {status}")
274
+ prompts.append(f"์ด๋ฏธ์ง€ #{i+1}: {final_prompt}")
275
+ else:
276
+ results.append(None)
277
+ statuses.append(f"์ด๋ฏธ์ง€ #{i+1} ์ƒ์„ฑ ์‹คํŒจ: {status}")
278
+ prompts.append(f"์ด๋ฏธ์ง€ #{i+1}: {final_prompt}")
279
+
280
+ time.sleep(1)
281
+
282
+ progress(1.0, desc="์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ!")
283
+
284
+ while len(results) < 4:
285
+ results.append(None)
286
+
287
+ combined_status = "\n".join(statuses)
288
+ combined_prompts = "\n".join(prompts)
289
+
290
+ return results[0], results[1], results[2], results[3], combined_status, combined_prompts
291
+
292
+ # =====================================================================
293
+ # ์•„๋ž˜๋Š” GFPGAN ์ฐธ์กฐ์ฝ”๋“œ๋ฅผ ํƒญ์œผ๋กœ ์ถ”๊ฐ€ํ•œ ๋ถ€๋ถ„ (๊ธฐ๋Šฅ ๊ตฌํ˜„ ๋ฐ UI ๊ฐœ์„ )
294
+ # ๊ธฐ์กด GFPGAN ๊ด€๋ จ ์ฝ”๋“œ์—์„œ version๊ณผ Rescaling factor ๊ด€๋ จ UI๋Š” ์ œ๊ฑฐํ•˜๊ณ ,
295
+ # GFPGANv1.4๋ฅผ ๊ณ ์ •์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
296
+ # =====================================================================
297
+
298
+ import sys
299
+ from torchvision.transforms import functional
300
+ sys.modules["torchvision.transforms.functional_tensor"] = functional
301
+
302
+ from basicsr.archs.srvgg_arch import SRVGGNetCompact
303
+ from gfpgan.utils import GFPGANer
304
+ from realesrgan.utils import RealESRGANer
305
+
306
+ import torch
307
+ import cv2
308
+
309
+ # ํ•„์š”ํ•œ ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ (์ด๋ฏธ ์—†์œผ๋ฉด ๋‹ค์šด๋กœ๋“œ)
310
+ if not os.path.exists('realesr-general-x4v3.pth'):
311
+ os.system("wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth -P .")
312
+ if not os.path.exists('GFPGANv1.4.pth'):
313
+ os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth -P .")
314
+ if not os.path.exists('RestoreFormer.pth'):
315
+ os.system("wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.4/RestoreFormer.pth -P .")
316
+
317
+ model = SRVGGNetCompact(num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=32, upscale=4, act_type='prelu')
318
+ model_path = 'realesr-general-x4v3.pth'
319
+ half = True if torch.cuda.is_available() else False
320
+ upsampler = RealESRGANer(scale=4, model_path=model_path, model=model, tile=0, tile_pad=10, pre_pad=0, half=half)
321
+
322
+ def upscaler(img, version, scale):
323
+ try:
324
+ img = cv2.imread(img, cv2.IMREAD_UNCHANGED)
325
+ if len(img.shape) == 3 and img.shape[2] == 4:
326
+ img_mode = 'RGBA'
327
+ elif len(img.shape) == 2:
328
+ img_mode = None
329
+ img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
330
+ else:
331
+ img_mode = None
332
+
333
+ h, w = img.shape[0:2]
334
+ if h < 300:
335
+ img = cv2.resize(img, (w * 2, h * 2), interpolation=cv2.INTER_LANCZOS4)
336
+
337
+ face_enhancer = GFPGANer(
338
+ model_path=f'{version}.pth',
339
+ upscale=2,
340
+ arch='RestoreFormer' if version=='RestoreFormer' else 'clean',
341
+ channel_multiplier=2,
342
+ bg_upsampler=upsampler
343
+ )
344
+
345
+ try:
346
+ _, _, output = face_enhancer.enhance(img, has_aligned=False, only_center_face=False, paste_back=True)
347
+ except RuntimeError as error:
348
+ print('์˜ค๋ฅ˜ ๋ฐœ์ƒ:', error)
349
+
350
+ try:
351
+ if scale != 2:
352
+ interpolation = cv2.INTER_AREA if scale < 2 else cv2.INTER_LANCZOS4
353
+ h, w = img.shape[0:2]
354
+ output = cv2.resize(output, (int(w * scale / 2), int(h * scale / 2)), interpolation=interpolation)
355
+ except Exception as error:
356
+ print('์ž˜๋ชป๋œ ์Šค์ผ€์ผ ์ž…๋ ฅ:', error)
357
+
358
+ output = cv2.cvtColor(output, cv2.COLOR_BGR2RGB)
359
+ return output
360
+ except Exception as error:
361
+ print('์ „์ฒด ์˜ˆ์™ธ ๋ฐœ์ƒ:', error)
362
+ return None
363
+
364
+ # GFPGAN ์—…์Šค์ผ€์ผ๋Ÿฌ ํ•จ์ˆ˜ (๋ฒ„์ „๊ณผ ์Šค์ผ€์ผ์€ ๊ณ ์ •)
365
+ def upscaler_korean(img):
366
+ return upscaler(img, "GFPGANv1.4", 2)
367
+
368
+ # =====================================================================
369
+ # Gradio Blocks๋กœ ํƒญ UI ๊ตฌ์„ฑ (Gradio 5.21 ๊ธฐ์ค€)
370
+ # =====================================================================
371
+
372
+ with gr.Blocks() as demo:
373
+ with gr.Tabs():
374
+ with gr.TabItem("์ด์ปค๋จธ์Šค ์ด๋ฏธ์ง€ ์ƒ์„ฑ๊ธฐ"):
375
+ gr.HTML(
376
+ """
377
+ <div style="text-align: center; margin-bottom: 1rem;">
378
+ <h1>์ด์ปค๋จธ์Šค์šฉ ์ด๋ฏธ์ง€ ์ƒ์„ฑ๊ธฐ</h1>
379
+ <p>์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ  ์˜ˆ์ œ๋ฅผ ์ฐธ๊ฐ€ํ•˜์—ฌ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ˆ˜์ •ํ•œ ํ›„ "์ด๋ฏธ์ง€ ์ƒ์„ฑ" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ฐจ๋ก€๋กœ 4์žฅ์˜ ์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.</p>
380
+ </div>
381
+ """
382
+ )
383
+
384
+ with gr.Row():
385
+ with gr.Column(scale=1):
386
+ with gr.Row():
387
+ image1_input = gr.Image(type="pil", label="#1", image_mode="RGB", height=300, width=200)
388
+ image2_input = gr.Image(type="pil", label="#2", image_mode="RGB", height=300, width=200)
389
+ image3_input = gr.Image(type="pil", label="#3", image_mode="RGB", height=300, width=200)
390
+ prompt_input = gr.Textbox(
391
+ lines=3,
392
+ placeholder="ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ๋น„์›Œ๋‘๋ฉด ์ž๋™ ํ•ฉ์„ฑ๋ฉ๋‹ˆ๋‹ค.",
393
+ label="ํ”„๋กฌํ”„ํŠธ (์„ ํƒ ์‚ฌํ•ญ)"
394
+ )
395
+ with gr.Row():
396
+ image_change_btn1 = gr.Button("์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ-1")
397
+ image_change_btn2 = gr.Button("์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ-2")
398
+ text_remove_btn = gr.Button("๊ธ€์ž ์ง€์šฐ๊ธฐ")
399
+ text_change_btn = gr.Button("๊ธ€์ž ๋ณ€๊ฒฝํ•˜๊ธฐ")
400
+ clothes_change_btn1 = gr.Button("๊ฐ€์ƒ ์ƒํ’ˆ์ฐฉ์šฉ-1")
401
+ clothes_change_btn2 = gr.Button("๊ฐ€์ƒ ์ƒํ’ˆ์ฐฉ์šฉ-2")
402
+ holding_product_btn = gr.Button("์ƒํ’ˆ๋“ค๊ณ  ์žˆ๊ธฐ")
403
+ background_change_btn = gr.Button("๋ฐฐ๊ฒฝ ๋ฐ”๊พธ๊ธฐ")
404
+ composite_product_btn = gr.Button("๋ถ€๋ถ„ ์ง€์šฐ๊ธฐ")
405
+ submit_btn = gr.Button("์ด๋ฏธ์ง€ ์ƒ์„ฑ (4์žฅ)", variant="primary")
406
+
407
+ gr.Markdown(
408
+ """
409
+ ### ์‚ฌ์šฉ ๋ฐฉ๋ฒ•:
410
+
411
+ 1. **์ž๋™ ํ•ฉ์„ฑ**: ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ  ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋น„์›Œ๋‘๋ฉด ์ž๋™์œผ๋กœ ํ•ฉ์„ฑ๋ฉ๋‹ˆ๋‹ค.
412
+ 2. **์ด๋ฏธ์ง€ ์ฐธ์กฐ**: #1, #2, #3์œผ๋กœ ๊ฐ ์ด๋ฏธ์ง€๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
413
+ 3. **์„ ํƒ ์˜ต์…˜**: ์œ„์˜ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ๋ž€์— ํ•œ๊ตญ์–ด ๋ฌธ๊ตฌ๋กœ ์ž…๋ ฅํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
414
+ 4. **๋‹ค์–‘ํ•œ ์ด๋ฏธ์ง€**: "์ด๋ฏธ์ง€ ์ƒ์„ฑ" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์ฐจ๋ก€๋กœ 4์žฅ์˜ ์ด๋ฏธ์ง€๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
415
+ 5. **์˜ˆ์ œ ์„ ํƒ**: ๋‹ค์–‘ํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ๋ฏธ๋ฆฌ ํ…Œ์ŠคํŠธํ•ด๋ณด์„ธ์š”.
416
+
417
+ > **ํŒ**: ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
418
+ """
419
+ )
420
+
421
+ gr.Markdown("## ์˜ˆ์ œ ์ด๋ฏธ์ง€")
422
+ examples = [
423
+ ["down/๋ชจ๋ธ.jpg", None, None, "(#1์˜ ์—ฌ์„ฑ)์ด ์‚ด์ง ๋’ค๋กœ ๋Œ์•„๋ณด๋Š” ๋ชจ์Šต์œผ๋กœ ์ตœ๋Œ€ํ•œ ์ด์ „ seed๋ฅผ ์œ ์ง€ํ•œํ…Œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณ€๊ฒฝํ•˜๋ผ."],
424
+ ["down/์ƒ์–ด๋ ˆ๊ณ ๋ชจํ˜•.png", None, None, "(#1 ๋ ˆ๋ชจ๋ชจํ˜•)์—์„œ ์ฒญ์ƒ‰์ƒ์–ด๋ ˆ๊ณ ๋งŒ ๊ฒ€์€์ƒ‰ ๊ณ ๋ž˜๋ ˆ๊ณ ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์€ seed๋ฅผ ๋ณ€๊ฒฝ์„ ํ•˜์ง€๋งˆ๋ผ."],
425
+ ["down/์ค‘๊ตญ์–ด.png", None, None, "(#1 ์ด๋ฏธ์ง€)์— ์žˆ๋Š” ์ค‘๊ตญ์–ด๋ฅผ ๋ชจ๋‘ ์ œ๊ฑฐํ•˜๋ผ."],
426
+ ["down/ํ…์ŠคํŠธ.webp", None, None, '(#1์˜ ํ…์ŠคํŠธ)๋ฅผ ์Šคํƒ€์ผ์„ ์œ ์ง€ํ•œ์ฒด ํ…์ŠคํŠธ๋งŒ "Hello"๋กœ ๋ฐ”๊ฟ”๋ผ'],
427
+ ["down/๋ชจ๋ธ.jpg", "down/์„ ๊ธ€๋ผ์Šค.png", "down/์ฒญ๋ฐ”์ง€.png", "(#1์˜ ์—ฌ์„ฑ๋ชจ๋ธ)์ด ์‹ ์ฒด ๋น„์œจ๊ณผ ํฌ์ฆˆ๋Š” ์œ ์น˜ํ•œ ์ฒด (#2์˜ ์„ ๊ธ€๋ผ์Šค)์™€ (#3์˜ ์ฒญ๋ฐ”์ง€)๋ฅผ ์ง์ ‘ ๋ชจ๋ธ์ด ์ฐฉ์šฉํ•œ๊ฒƒ ์ฒ˜๋Ÿผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋ผ."],
428
+ ["down/๋ชจ๋ธ.jpg", "down/์„ ๊ธ€๋ผ์Šค.png", "down/์นดํŽ˜์ „๊ฒฝ.png", "(#1์˜ ์—ฌ์„ฑ๋ชจ๋ธ)์ด ์‹ ์ฒด ๋น„์œจ๊ณผ ํฌ์ฆˆ๋Š” ์œ ์น˜ํ•œ ์ฒด (#2์˜ ์„ ๊ธ€๋ผ์Šค)๋ฅผ ์ง์ ‘ ๋ชจ๋ธ์ด ์ฐฉ์šฉํ•œ ๊ฒƒ์ฒ˜๋Ÿผ (#3์˜ ์žฅ์†Œ)์—์„œ ์˜์ž์— ์•‰์•„ ์žˆ๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋ผ."],
429
+ ["down/๋ชจ๋ธ.jpg", "down/์™€์ธ์ž”.png", None, "(#1์˜ ์—ฌ์„ฑ๋ชจ๋ธ)์ด ์‹ ์ฒด ๋น„์œจ๊ณผ ํฌ์ฆˆ๋Š” ์œ ์น˜ํ•œ ์ฒด (#2์˜ ์™€์ธ์ž”)์„ ์—ฌ์„ฑ๋ชจ๋ธ์ด ํ™๋ณดํ•  ์™€์ธ์ž”์„ ๋‹๋ณด์ด๊ฒŒ ๋“ค๊ณ  ์žˆ๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ชจ์Šต์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋ผ."],
430
+ ["down/๋ชจ๋ธ.jpg", "down/์นดํŽ˜์ „๊ฒฝ.png", None, "(#1์˜ ์—ฌ์„ฑ๋ชจ๋ธ)์ด (#2 ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ)์„ ์ฃผ์š” ํ”ผ์‚ฌ์ฒด๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜์—ฌ ์ด๋ฏธ์ง€์˜ ๋ถ„์œ„๊ธฐ๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์–ด์šฐ๋Ÿฌ์ง€๋„๋ก ์ƒ์„ฑํ•˜๋ผ."],
431
+ ["down/์ƒ์–ด๋ ˆ๊ณ ๋ชจํ˜•.png", None, None, "(#1์˜ ๋ ˆ๊ณ ๋ชจํ˜•)์—์„œ ์ฒญ์ƒ‰์ƒ์–ด๋ ˆ๊ณ ๋ฅผ ์ œ๊ฑฐํ•œ ํ›„, ๊ทธ ์ž๋ฆฌ๋ฅผ ์ฃผ๋ณ€ ๋ฐฐ๊ฒฝ๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์–ด์šฐ๋Ÿฌ์ง€๋„๋ก ์ฑ„์›Œ์ฃผ์„ธ์š”. ๋‹จ, ์ด๋ฏธ์ง€์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„์˜ ์ฃผ์š” ์š”์†Œ๋Š” ๋™์ผํ•˜๊ฒŒ ์œ ์ง€ํ•ด ํ•ด์•ผํ•œ๋‹ค."]
432
+ ]
433
+
434
+ gr.Examples(
435
+ examples=examples,
436
+ inputs=[image1_input, image2_input, image3_input, prompt_input],
437
+ elem_id="examples-grid"
438
+ )
439
+
440
+ with gr.Column(scale=1):
441
+ with gr.Row():
442
+ with gr.Column():
443
+ output_image1 = gr.Image(label="์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€ #1", height=600, width=450)
444
+ output_image3 = gr.Image(label="์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€ #3", height=600, width=450)
445
+ with gr.Column():
446
+ output_image2 = gr.Image(label="์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€ #2", height=600, width=450)
447
+ output_image4 = gr.Image(label="์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€ #4", height=600, width=450)
448
+
449
+ output_text = gr.Textbox(label="์ƒํƒœ ๋ฉ”์‹œ์ง€", lines=4)
450
+ prompt_display = gr.Textbox(label="์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ (์˜์–ด)", visible=True, lines=4)
451
+
452
+ image_change_btn1.click(
453
+ fn=lambda: "(#1์˜ ์—ฌ์„ฑ)์ด ์‚ด์ง ๋’ค๋กœ ๋Œ์•„๋ณด๋Š” ๋ชจ์Šต์œผ๋กœ ์ตœ๋Œ€ํ•œ ์ด์ „ seed๋ฅผ ์œ ์ง€ํ•œํ…Œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณ€๊ฒฝํ•˜๋ผ.",
454
+ inputs=[],
455
+ outputs=prompt_input
456
+ )
457
+ image_change_btn2.click(
458
+ fn=lambda: "(#1 ๋ ˆ๋ชจ๋ชจํ˜•)์—์„œ ์ฒญ์ƒ‰์ƒ์–ด๋ ˆ๊ณ ๋งŒ ๊ฒ€์€์ƒ‰ ๊ณ ๋ž˜๋ ˆ๊ณ ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์€ seed๋ฅผ ๋ณ€๊ฒฝ์„ ํ•˜์ง€๋งˆ๋ผ.",
459
+ inputs=[],
460
+ outputs=prompt_input
461
+ )
462
+ text_remove_btn.click(
463
+ fn=lambda: "(#1 ์ด๋ฏธ์ง€)์— ์žˆ๋Š” ์ค‘๊ตญ์–ด๋ฅผ ๋ชจ๋‘ ์ œ๊ฑฐํ•˜๋ผ.",
464
+ inputs=[],
465
+ outputs=prompt_input
466
+ )
467
+ text_change_btn.click(
468
+ fn=lambda: '(#1์˜ ํ…์ŠคํŠธ)๋ฅผ ์Šคํƒ€์ผ์„ ์œ ์ง€ํ•œ์ฒด ํ…์ŠคํŠธ๋งŒ "Hello"๋กœ ๋ฐ”๊ฟ”๋ผ',
469
+ inputs=[],
470
+ outputs=prompt_input
471
+ )
472
+ clothes_change_btn1.click(
473
+ fn=lambda: "(#1์˜ ์—ฌ์„ฑ๋ชจ๊ฒ”)์ด ์‹ ์ฒด ๋น„์œจ๊ณผ ํฌ์ฆˆ๋Š” ์œ ์น˜ํ•œ ์ฒด (#2์˜ ์„ ๊ธ€๋ผ์Šค)์™€ (#3์˜ ์ฒญ๋ฐ”์ง€)๋ฅผ ์ง์ ‘ ๋ชจ๋ธ์ด ์ฐฉ์šฉํ•œ๊ฒƒ ์ฒ˜๋Ÿผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋ผ.",
474
+ inputs=[],
475
+ outputs=prompt_input
476
+ )
477
+ clothes_change_btn2.click(
478
+ fn=lambda: "(#1์˜ ์—ฌ์„ฑ๋ชจ๋ธ)์ด ์‹ ์ฒด ๋น„์œจ๊ณผ ํฌ์ฆˆ๋Š” ์œ ์น˜ํ•œ ์ฒด (#2์˜ ์„ ๊ธ€๋ผ์Šค)๋ฅผ ์ง์ ‘ ๋ชจ๋ธ์ด ์ฐฉ์šฉํ•œ ๊ฒƒ์ฒ˜๋Ÿผ (#3์˜ ์žฅ์†Œ)์—์„œ ์˜์ž์— ์•‰์•„ ์žˆ๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋ผ.",
479
+ inputs=[],
480
+ outputs=prompt_input
481
+ )
482
+ holding_product_btn.click(
483
+ fn=lambda: "(#1์˜ ์—ฌ์„ฑ๋ชจ๋ธ)์ด ์‹ ์ฒด ๋น„์œจ๊ณผ ํฌ์ฆˆ๋Š” ์œ ์น˜ํ•œ ์ฒด (#2์˜ ์™€์ธ์ž”)์„ ์—ฌ์„ฑ๋ชจ๋ธ์ด ํ™๋ณดํ•  ์™€์ธ์ž”์„ ๋‹๋ณด์ด๊ฒŒ ๋“ค๊ณ  ์žˆ๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ชจ์Šต์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋ผ.",
484
+ inputs=[],
485
+ outputs=prompt_input
486
+ )
487
+ background_change_btn.click(
488
+ fn=lambda: "(#1์˜ ์—ฌ์„ฑ๋ชจ๋ธ)์ด (#2 ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ)์„ ์ฃผ์š” ํ”ผ์‚ฌ์ฒด๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜์—ฌ ๋‘ ์ด๋ฏธ์ง€์˜ ๋ถ„์œ„๊ธฐ๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์–ด์šฐ๋Ÿฌ์ง€๋„๋ก ์ƒ์„ฑํ•˜๋ผ.",
489
+ inputs=[],
490
+ outputs=prompt_input
491
+ )
492
+ composite_product_btn.click(
493
+ fn=lambda: "(#1์˜ ๋ ˆ๊ณ ๋ชจํ˜•)์—์„œ ์ฒญ์ƒ‰์ƒ์–ด๋ ˆ๊ณ ๋ฅผ ์ œ๊ฑฐํ•œ ํ›„, ๊ทธ ์ž๋ฆฌ๋ฅผ ์ฃผ๋ณ€ ๋ฐฐ๊ฒฝ๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์–ด์šฐ๋Ÿฌ์ง€๋„๋ก ์ฑ„์›Œ์ฃผ์„ธ์š”. ๋‹จ, ์ด๋ฏธ์ง€์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„์˜ ์ฃผ์š” ์š”์†Œ๋Š” ๋™์ผํ•˜๊ฒŒ ์œ ์ง€ํ•ด ํ•ด์•ผํ•œ๋‹ค.",
494
+ inputs=[],
495
+ outputs=prompt_input
496
+ )
497
+ submit_btn.click(
498
+ fn=generate_multiple_images,
499
+ inputs=[image1_input, image2_input, image3_input, prompt_input],
500
+ outputs=[output_image1, output_image2, output_image3, output_image4, output_text, prompt_display],
501
+ )
502
+
503
+ with gr.TabItem("GFPGAN ์—…์Šค์ผ€์ผ๋Ÿฌ"):
504
+ gr.Markdown("<h1 style='text-align: center;'>GFPGAN ์—…์Šค์ผ€์ผ๋Ÿฌ ๋ฐ ๋ณต์›</h1>")
505
+ gr.Markdown("์ž…๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๋ฉด GFPGANv1.4 ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์–ผ๊ตด ๋ณต์› ๋ฐ ์—…์Šค์ผ€์ผ๋ง์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.")
506
+ with gr.Row():
507
+ gfpgan_input = gr.Image(type="filepath", label="์ž…๋ ฅ ์ด๋ฏธ์ง€", image_mode="RGB")
508
+ gfpgan_output = gr.Image(type="numpy", label="์ถœ๋ ฅ ์ด๋ฏธ์ง€")
509
+ gfpgan_btn = gr.Button("์—…์Šค์ผ€์ผ ๋ฐ ๋ณต์›")
510
+ gfpgan_btn.click(fn=upscaler_korean, inputs=gfpgan_input, outputs=gfpgan_output)
511
+
512
+ demo.queue()
513
+ demo.launch()