ssboost commited on
Commit
c37b4d7
ยท
verified ยท
1 Parent(s): 0226e26

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +606 -1
app.py CHANGED
@@ -1,2 +1,607 @@
 
 
 
 
 
 
 
 
1
  import os
2
- exec(os.environ.get('APP'))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import replicate
3
+ from PIL import Image
4
+ from google import genai
5
+ from google.genai import types
6
+ import io
7
+ import base64
8
+ import tempfile
9
  import os
10
+ import uuid
11
+ import requests
12
+ from io import BytesIO
13
+ import time
14
+ import json
15
+ import datetime
16
+
17
+ # ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ API ํ† ํฐ๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ฐ€์ ธ์˜ค๊ธฐ
18
+ REPLICATE_API_TOKEN = os.getenv("REPLICATE_API_TOKEN")
19
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
20
+ PASSWORD = os.getenv("APP_PASSWORD", "1089") # ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •
21
+
22
+ # API ํ‚ค ๊ฒ€์ฆ
23
+ def validate_api_keys():
24
+ """API ํ‚ค๋“ค์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ํ™•์ธ"""
25
+ missing_keys = []
26
+
27
+ if not REPLICATE_API_TOKEN:
28
+ missing_keys.append("REPLICATE_API_TOKEN")
29
+
30
+ if not GEMINI_API_KEY:
31
+ missing_keys.append("GEMINI_API_KEY")
32
+
33
+ if missing_keys:
34
+ error_msg = f"๋‹ค์Œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค: {', '.join(missing_keys)}"
35
+ raise ValueError(error_msg)
36
+
37
+ return True
38
+
39
+ def log_message(message, log_list=None):
40
+ """๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ํƒ€์ž„์Šคํƒฌํ”„์™€ ํ•จ๊ป˜ ๊ธฐ๋ก"""
41
+ timestamp = datetime.datetime.now().strftime("%H:%M:%S")
42
+ formatted_message = f"[{timestamp}] {message}"
43
+ print(formatted_message) # ์ฝ˜์†”์—๋„ ์ถœ๋ ฅ
44
+ if log_list is not None:
45
+ log_list.append(formatted_message)
46
+ return formatted_message
47
+
48
+ def translate_to_english(korean_prompt, log_list):
49
+ """ํ•œ๊ตญ์–ด ํ”„๋กฌํ”„ํŠธ๋ฅผ FLUX ์ด๋ฏธ์ง€ ์ƒ์„ฑ์— ์ตœ์ ํ™”๋œ ์˜์–ด๋กœ ๋ฒˆ์—ญ"""
50
+ log_message("=== ๋ฒˆ์—ญ ํ”„๋กœ์„ธ์Šค ์‹œ์ž‘ ===", log_list)
51
+ log_message(f"์ž…๋ ฅ๋œ ํ•œ๊ตญ์–ด ํ”„๋กฌํ”„ํŠธ: '{korean_prompt}'", log_list)
52
+
53
+ try:
54
+ log_message("Gemini API ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์‹œ์ž‘...", log_list)
55
+ client = genai.Client(api_key=GEMINI_API_KEY)
56
+ log_message("Gemini API ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ", log_list)
57
+
58
+ system_instruction = """You are a professional prompt translator for FLUX image generation models.
59
+ Translate Korean image editing prompts to optimized English prompts that work best with FLUX models.
60
+ Keep the translation:
61
+ - Clear and specific
62
+ - Descriptive but concise
63
+ - Focused on visual elements
64
+ - Suitable for AI image generation
65
+
66
+ Only return the translated English prompt, nothing else."""
67
+
68
+ log_message("๋ฒˆ์—ญ ์š”์ฒญ ์ค€๋น„ ์™„๋ฃŒ", log_list)
69
+ log_message("Gemini API ํ˜ธ์ถœ ์‹œ์ž‘...", log_list)
70
+
71
+ start_time = time.time()
72
+ response = client.models.generate_content(
73
+ model="gemini-2.0-flash",
74
+ config=types.GenerateContentConfig(
75
+ system_instruction=system_instruction,
76
+ temperature=0.3
77
+ ),
78
+ contents=[f"Translate this Korean prompt to English for FLUX image editing: {korean_prompt}"]
79
+ )
80
+ end_time = time.time()
81
+
82
+ log_message(f"Gemini API ์‘๋‹ต ์ˆ˜์‹  ์™„๋ฃŒ (์†Œ์š”์‹œ๊ฐ„: {end_time - start_time:.2f}์ดˆ)", log_list)
83
+
84
+ translated_text = response.text.strip()
85
+ log_message(f"๋ฒˆ์—ญ ๊ฒฐ๊ณผ: '{translated_text}'", log_list)
86
+ log_message("=== ๋ฒˆ์—ญ ํ”„๋กœ์„ธ์Šค ์™„๋ฃŒ ===", log_list)
87
+
88
+ return translated_text
89
+
90
+ except Exception as e:
91
+ error_msg = f"๋ฒˆ์—ญ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
92
+ log_message(error_msg, log_list)
93
+ log_message("์›๋ณธ ํ•œ๊ตญ์–ด ํ”„๋กฌํ”„ํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค", log_list)
94
+ log_message("=== ๋ฒˆ์—ญ ํ”„๋กœ์„ธ์Šค ์‹คํŒจ ===", log_list)
95
+ return korean_prompt
96
+
97
+ def upscale_image(image_path, output_format, english_prompt, log_list):
98
+ """Clarity Upscaler๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€ ์—…์Šค์ผ€์ผ๋ง (๋ชจ๋“  ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ณ ์ •)"""
99
+ log_message("=== ํ™”์งˆ ๊ฐœ์„ (์—…์Šค์ผ€์ผ๋ง) ํ”„๋กœ์„ธ์Šค ์‹œ์ž‘ ===", log_list)
100
+ log_message(f"์ž…๋ ฅ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ: {image_path}", log_list)
101
+ log_message(f"์ถœ๋ ฅ ํฌ๋งท: {output_format}", log_list)
102
+ log_message(f"์‚ฌ์šฉํ•  ํ”„๋กฌํ”„ํŠธ: '{english_prompt}'", log_list)
103
+
104
+ try:
105
+ # ํŒŒ์ผ ์กด์žฌ ํ™•์ธ
106
+ if not os.path.exists(image_path):
107
+ error_msg = f"์ž…๋ ฅ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค: {image_path}"
108
+ log_message(error_msg, log_list)
109
+ return None
110
+
111
+ # ํŒŒ์ผ ํฌ๊ธฐ ํ™•์ธ
112
+ file_size = os.path.getsize(image_path)
113
+ log_message(f"์ž…๋ ฅ ํŒŒ์ผ ํฌ๊ธฐ: {file_size} bytes ({file_size/1024/1024:.2f} MB)", log_list)
114
+
115
+ log_message("Replicate API ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์‹œ์ž‘...", log_list)
116
+ client = replicate.Client(api_token=REPLICATE_API_TOKEN)
117
+ log_message("Replicate API ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ", log_list)
118
+
119
+ log_message("์ด๋ฏธ์ง€ ํŒŒ์ผ ์ฝ๊ธฐ ์‹œ์ž‘...", log_list)
120
+ with open(image_path, "rb") as file:
121
+ log_message("์ด๋ฏธ์ง€ ํŒŒ์ผ ์ฝ๊ธฐ ์™„๋ฃŒ", log_list)
122
+
123
+ # ์—…์Šค์ผ€์ผ ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •
124
+ input_data = {
125
+ "image": file,
126
+ "scale_factor": 2, # ๊ณ ์ •: 2๋ฐฐ ํ™•๋Œ€
127
+ "resemblance": 0.8, # ๊ณ ์ •: ๋†’์€ ์›๋ณธ ์œ ์‚ฌ๋„
128
+ "creativity": 0.2, # ๊ณ ์ •: ๋‚ฎ์€ ์ฐฝ์˜์„ฑ
129
+ "output_format": output_format.lower(),
130
+ "prompt": english_prompt,
131
+ "negative_prompt": "(worst quality, low quality, normal quality:2)"
132
+ }
133
+
134
+ log_message("์—…์Šค์ผ€์ผ ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •:", log_list)
135
+ log_message(f" - scale_factor: 2", log_list)
136
+ log_message(f" - resemblance: 0.8", log_list)
137
+ log_message(f" - creativity: 0.2", log_list)
138
+ log_message(f" - output_format: {output_format.lower()}", log_list)
139
+ log_message(f" - negative_prompt: (worst quality, low quality, normal quality:2)", log_list)
140
+
141
+ log_message("Clarity Upscaler API ํ˜ธ์ถœ ์‹œ์ž‘...", log_list)
142
+ log_message("๋ชจ๋ธ: philz1337x/clarity-upscaler", log_list)
143
+
144
+ start_time = time.time()
145
+ try:
146
+ output = client.run(
147
+ "philz1337x/clarity-upscaler:dfad41707589d68ecdccd1dfa600d55a208f9310748e44bfe35b4a6291453d5e",
148
+ input=input_data
149
+ )
150
+ end_time = time.time()
151
+ log_message(f"Clarity Upscaler API ์‘๋‹ต ์ˆ˜์‹  ์™„๋ฃŒ (์†Œ์š”์‹œ๊ฐ„: {end_time - start_time:.2f}์ดˆ)", log_list)
152
+
153
+ except Exception as api_error:
154
+ error_msg = f"Clarity Upscaler API ํ˜ธ์ถœ ์‹คํŒจ: {str(api_error)}"
155
+ log_message(error_msg, log_list)
156
+ log_message("=== ํ™”์งˆ ๊ฐœ์„  ํ”„๋กœ์„ธ์Šค ์‹คํŒจ ===", log_list)
157
+ return None
158
+
159
+ # API ์‘๋‹ต ๊ฒ€์ฆ
160
+ log_message(f"API ์‘๋‹ต ํƒ€์ž…: {type(output)}", log_list)
161
+ log_message(f"API ์‘๋‹ต ๋‚ด์šฉ: {output}", log_list)
162
+
163
+ # ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ
164
+ if output and isinstance(output, list) and len(output) > 0:
165
+ result_url = output[0]
166
+ log_message(f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ URL: {result_url}", log_list)
167
+ log_message("๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์‹œ์ž‘...", log_list)
168
+
169
+ try:
170
+ download_start = time.time()
171
+ response = requests.get(result_url, timeout=30)
172
+ download_end = time.time()
173
+
174
+ log_message(f"๋‹ค์šด๋กœ๋“œ ์‘๋‹ต ์ƒํƒœ: {response.status_code}", log_list)
175
+ log_message(f"๋‹ค์šด๋กœ๋“œ ์†Œ์š”์‹œ๊ฐ„: {download_end - download_start:.2f}์ดˆ", log_list)
176
+ log_message(f"๋‹ค์šด๋กœ๋“œ๋œ ๋ฐ์ดํ„ฐ ํฌ๊ธฐ: {len(response.content)} bytes ({len(response.content)/1024/1024:.2f} MB)", log_list)
177
+
178
+ if response.status_code == 200:
179
+ log_message("์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ PIL Image๋กœ ๋ณ€ํ™˜ ์ค‘...", log_list)
180
+ result_image = Image.open(BytesIO(response.content))
181
+ log_message(f"๋ณ€ํ™˜๋œ ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {result_image.size}", log_list)
182
+ log_message(f"๋ณ€ํ™˜๋œ ์ด๋ฏธ์ง€ ๋ชจ๋“œ: {result_image.mode}", log_list)
183
+
184
+ # ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ
185
+ ext = output_format.lower()
186
+ upscaled_filename = f"upscaled_temp_{uuid.uuid4()}.{ext}"
187
+ log_message(f"์—…์Šค์ผ€์ผ๋œ ์ด๋ฏธ์ง€ ์ €์žฅ ํŒŒ์ผ๋ช…: {upscaled_filename}", log_list)
188
+
189
+ # RGBA ๋ชจ๋“œ ์ฒ˜๋ฆฌ
190
+ if ext == 'jpg' and result_image.mode == 'RGBA':
191
+ log_message("RGBA ๋ชจ๋“œ๋ฅผ RGB๋กœ ๋ณ€ํ™˜ ์ค‘ (JPG ์ €์žฅ์„ ์œ„ํ•ด)...", log_list)
192
+ result_image = result_image.convert('RGB')
193
+
194
+ # ์ด๋ฏธ์ง€ ์ €์žฅ
195
+ save_start = time.time()
196
+ if ext == 'jpg':
197
+ result_image.save(upscaled_filename, format='JPEG', quality=95)
198
+ else:
199
+ result_image.save(upscaled_filename, format='PNG')
200
+ save_end = time.time()
201
+
202
+ log_message(f"์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ (์†Œ์š”์‹œ๊ฐ„: {save_end - save_start:.2f}์ดˆ)", log_list)
203
+
204
+ # ์ €์žฅ๋œ ํŒŒ์ผ ํฌ๊ธฐ ํ™•์ธ
205
+ saved_size = os.path.getsize(upscaled_filename)
206
+ log_message(f"์ €์žฅ๋œ ํŒŒ์ผ ํฌ๊ธฐ: {saved_size} bytes ({saved_size/1024/1024:.2f} MB)", log_list)
207
+
208
+ log_message("=== ํ™”์งˆ ๊ฐœ์„  ํ”„๋กœ์„ธ์Šค ์™„๋ฃŒ ===", log_list)
209
+ return upscaled_filename
210
+ else:
211
+ error_msg = f"์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ - HTTP ์ƒํƒœ: {response.status_code}"
212
+ log_message(error_msg, log_list)
213
+ log_message("=== ๏ฟฝ๏ฟฝ๏ฟฝ์งˆ ๊ฐœ์„  ํ”„๋กœ์„ธ์Šค ์‹คํŒจ ===", log_list)
214
+ return None
215
+
216
+ except requests.exceptions.Timeout:
217
+ log_message("์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ํƒ€์ž„์•„์›ƒ (30์ดˆ)", log_list)
218
+ log_message("=== ํ™”์งˆ ๊ฐœ์„  ํ”„๋กœ์„ธ์Šค ์‹คํŒจ ===", log_list)
219
+ return None
220
+ except Exception as download_error:
221
+ error_msg = f"์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜: {str(download_error)}"
222
+ log_message(error_msg, log_list)
223
+ log_message("=== ํ™”์งˆ ๊ฐœ์„  ํ”„๋กœ์„ธ์Šค ์‹คํŒจ ===", log_list)
224
+ return None
225
+ else:
226
+ log_message("API ์‘๋‹ต์ด ๋น„์–ด์žˆ๊ฑฐ๋‚˜ ์˜ˆ์ƒ ํ˜•์‹๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค", log_list)
227
+ if output:
228
+ log_message(f"์‹ค์ œ ์‘๋‹ต: {json.dumps(output, indent=2) if isinstance(output, dict) else str(output)}", log_list)
229
+ log_message("=== ํ™”์งˆ ๊ฐœ์„  ํ”„๋กœ์„ธ์Šค ์‹คํŒจ ===", log_list)
230
+ return None
231
+
232
+ except Exception as e:
233
+ error_msg = f"์—…์Šค์ผ€์ผ๋ง ํ”„๋กœ์„ธ์Šค ์ค‘ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜: {str(e)}"
234
+ log_message(error_msg, log_list)
235
+ log_message("=== ํ™”์งˆ ๊ฐœ์„  ํ”„๋กœ์„ธ์Šค ์‹คํŒจ ===", log_list)
236
+ return None
237
+
238
+ def edit_image(input_image, password, korean_prompt, output_format, aspect_ratio, upscale_option, current_images, current_downloads):
239
+ log_list = []
240
+ log_message("=" * 60, log_list)
241
+ log_message("์ƒˆ๋กœ์šด ์ด๋ฏธ์ง€ ํŽธ์ง‘ ์ž‘์—… ์‹œ์ž‘", log_list)
242
+ log_message("=" * 60, log_list)
243
+
244
+ # API ํ‚ค ๊ฒ€์ฆ
245
+ try:
246
+ validate_api_keys()
247
+ log_message("API ํ‚ค ๊ฒ€์ฆ ์™„๋ฃŒ", log_list)
248
+ except ValueError as e:
249
+ error_msg = str(e)
250
+ log_message(f"API ํ‚ค ๊ฒ€์ฆ ์‹คํŒจ: {error_msg}", log_list)
251
+ return None, None, "\n".join(log_list) + f"\n์˜ค๋ฅ˜: {error_msg}", current_images, current_downloads
252
+
253
+ # ์ž…๋ ฅ ๊ฒ€์ฆ
254
+ log_message("=== ์ž…๋ ฅ ๊ฒ€์ฆ ๋‹จ๊ณ„ ===", log_list)
255
+
256
+ if not password:
257
+ error_msg = "๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”."
258
+ log_message(f"๊ฒ€์ฆ ์‹คํŒจ: {error_msg}", log_list)
259
+ return None, None, "\n".join(log_list) + f"\n์˜ค๋ฅ˜: {error_msg}", current_images, current_downloads
260
+
261
+ if password != PASSWORD:
262
+ error_msg = "๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค."
263
+ log_message(f"๊ฒ€์ฆ ์‹คํŒจ: {error_msg}", log_list)
264
+ return None, None, "\n".join(log_list) + f"\n์˜ค๋ฅ˜: {error_msg}", current_images, current_downloads
265
+
266
+ log_message("๋น„๋ฐ€๋ฒˆํ˜ธ ๊ฒ€์ฆ ํ†ต๊ณผ", log_list)
267
+
268
+ if input_image is None:
269
+ error_msg = "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜์„ธ์š”."
270
+ log_message(f"๊ฒ€์ฆ ์‹คํŒจ: {error_msg}", log_list)
271
+ return None, None, "\n".join(log_list) + f"\n์˜ค๋ฅ˜: {error_msg}", current_images, current_downloads
272
+
273
+ log_message(f"์ž…๋ ฅ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ: {input_image}", log_list)
274
+
275
+ if not korean_prompt.strip():
276
+ error_msg = "ํŽธ์ง‘ ์ง€์‹œ์‚ฌํ•ญ์„ ์ž…๋ ฅํ•˜์„ธ์š”."
277
+ log_message(f"๊ฒ€์ฆ ์‹คํŒจ: {error_msg}", log_list)
278
+ return None, None, "\n".join(log_list) + f"\n์˜ค๋ฅ˜: {error_msg}", current_images, current_downloads
279
+
280
+ log_message(f"ํŽธ์ง‘ ์ง€์‹œ์‚ฌํ•ญ: '{korean_prompt.strip()}'", log_list)
281
+ log_message(f"์ถœ๋ ฅ ํฌ๋งท: {output_format}", log_list)
282
+ log_message(f"ํ™”๋ฉด ๋น„์œจ: {aspect_ratio}", log_list)
283
+ log_message(f"ํ™”์งˆ ๊ฐœ์„  ์˜ต์…˜: {upscale_option}", log_list)
284
+ log_message("๋ชจ๋“  ์ž…๋ ฅ ๊ฒ€์ฆ ํ†ต๊ณผ", log_list)
285
+
286
+ try:
287
+ # Replicate ํด๋ผ์ด์–ธํŠธ ์„ค์ •
288
+ log_message("=== Replicate ์„ค์ • ๋‹จ๊ณ„ ===", log_list)
289
+ log_message("Replicate ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์‹œ์ž‘...", log_list)
290
+ client = replicate.Client(api_token=REPLICATE_API_TOKEN)
291
+ log_message("Replicate ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ", log_list)
292
+
293
+ # ํ•œ๊ตญ์–ด ํ”„๋กฌํ”„ํŠธ๋ฅผ ์˜์–ด๋กœ ๋ฒˆ์—ญ
294
+ english_prompt = translate_to_english(korean_prompt, log_list)
295
+
296
+ # ์ž…๋ ฅ ์ด๋ฏธ์ง€ ์ •๋ณด ํ™•์ธ
297
+ log_message("=== ์ž…๋ ฅ ์ด๋ฏธ์ง€ ๋ถ„์„ ===", log_list)
298
+ try:
299
+ with Image.open(input_image) as img:
300
+ log_message(f"์ด๋ฏธ์ง€ ํฌ๊ธฐ: {img.size}", log_list)
301
+ log_message(f"์ด๋ฏธ์ง€ ๋ชจ๋“œ: {img.mode}", log_list)
302
+ log_message(f"์ด๋ฏธ์ง€ ํฌ๋งท: {img.format}", log_list)
303
+ except Exception as img_error:
304
+ log_message(f"์ด๋ฏธ์ง€ ์ •๋ณด ์ฝ๊ธฐ ์˜ค๋ฅ˜: {str(img_error)}", log_list)
305
+
306
+ # ํŒŒ์ผ ํฌ๊ธฐ ํ™•์ธ
307
+ file_size = os.path.getsize(input_image)
308
+ log_message(f"์ž…๋ ฅ ํŒŒ์ผ ํฌ๊ธฐ: {file_size} bytes ({file_size/1024/1024:.2f} MB)", log_list)
309
+
310
+ # FLUX ์ด๋ฏธ์ง€ ํŽธ์ง‘ ์‹œ์ž‘
311
+ log_message("=== FLUX ์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋‹จ๊ณ„ ===", log_list)
312
+ log_message("์ด๋ฏธ์ง€ ํŒŒ์ผ ์ฝ๊ธฐ ์‹œ์ž‘...", log_list)
313
+
314
+ with open(input_image, "rb") as file:
315
+ input_file = file
316
+ log_message("ํŒŒ์ผ ์ฝ๊ธฐ ์™„๏ฟฝ๏ฟฝ", log_list)
317
+
318
+ # Replicate API ํ˜ธ์ถœ ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •
319
+ input_data = {
320
+ "prompt": english_prompt,
321
+ "input_image": input_file,
322
+ "output_format": output_format.lower(),
323
+ "aspect_ratio": aspect_ratio
324
+ }
325
+
326
+ log_message("FLUX API ํ˜ธ์ถœ ํŒŒ๋ผ๋ฏธํ„ฐ:", log_list)
327
+ log_message(f" - ํ”„๋กฌํ”„ํŠธ: '{english_prompt}'", log_list)
328
+ log_message(f" - ์ถœ๋ ฅ ํฌ๋งท: {output_format.lower()}", log_list)
329
+ log_message(f" - ํ™”๋ฉด ๋น„์œจ: {aspect_ratio}", log_list)
330
+
331
+ log_message("FLUX ๋ชจ๋ธ API ํ˜ธ์ถœ ์‹œ์ž‘...", log_list)
332
+ log_message("๋ชจ๋ธ: black-forest-labs/flux-kontext-pro", log_list)
333
+
334
+ flux_start_time = time.time()
335
+ try:
336
+ output = client.run(
337
+ "black-forest-labs/flux-kontext-pro",
338
+ input=input_data
339
+ )
340
+ flux_end_time = time.time()
341
+ log_message(f"FLUX API ์‘๋‹ต ์ˆ˜์‹  ์™„๋ฃŒ (์†Œ์š”์‹œ๊ฐ„: {flux_end_time - flux_start_time:.2f}์ดˆ)", log_list)
342
+
343
+ except Exception as flux_error:
344
+ error_msg = f"FLUX API ํ˜ธ์ถœ ์‹คํŒจ: {str(flux_error)}"
345
+ log_message(error_msg, log_list)
346
+ return None, None, "\n".join(log_list) + f"\n์˜ค๋ฅ˜: {error_msg}", current_images, current_downloads
347
+
348
+ log_message(f"FLUX API ์‘๋‹ต ํƒ€์ž…: {type(output)}", log_list)
349
+
350
+ # ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ
351
+ log_message("=== ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ๋‹จ๊ณ„ ===", log_list)
352
+ temp_filename = f"temp_output_{uuid.uuid4()}.{output_format.lower()}"
353
+ log_message(f"์ž„์‹œ ํŒŒ์ผ๋ช…: {temp_filename}", log_list)
354
+
355
+ try:
356
+ log_message("๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ์ €์žฅ ์‹œ์ž‘...", log_list)
357
+ with open(temp_filename, "wb") as file:
358
+ file.write(output.read())
359
+
360
+ # ์ €์žฅ๋œ ํŒŒ์ผ ํฌ๊ธฐ ํ™•์ธ
361
+ saved_size = os.path.getsize(temp_filename)
362
+ log_message(f"FLUX ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ", log_list)
363
+ log_message(f"์ €์žฅ๋œ ํŒŒ์ผ ํฌ๊ธฐ: {saved_size} bytes ({saved_size/1024/1024:.2f} MB)", log_list)
364
+
365
+ except Exception as save_error:
366
+ error_msg = f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ์ €์žฅ ์‹คํŒจ: {str(save_error)}"
367
+ log_message(error_msg, log_list)
368
+ return None, None, "\n".join(log_list) + f"\n์˜ค๋ฅ˜: {error_msg}", current_images, current_downloads
369
+
370
+ # ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ๋กœ๋“œ
371
+ try:
372
+ log_message("๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋ฅผ PIL Image๋กœ ๋กœ๋“œ ์ค‘...", log_list)
373
+ result_image = Image.open(temp_filename)
374
+ log_message(f"๋กœ๋“œ๋œ ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {result_image.size}", log_list)
375
+ log_message(f"๋กœ๋“œ๋œ ์ด๋ฏธ์ง€ ๋ชจ๋“œ: {result_image.mode}", log_list)
376
+
377
+ except Exception as load_error:
378
+ error_msg = f"๊ฒฐ๊ณผ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {str(load_error)}"
379
+ log_message(error_msg, log_list)
380
+ return None, None, "\n".join(log_list) + f"\n์˜ค๋ฅ˜: {error_msg}", current_images, current_downloads
381
+
382
+ # ์—…์Šค์ผ€์ผ๋ง ์ ์šฉ (์„ ํƒ์‚ฌํ•ญ)
383
+ final_image = result_image
384
+ if upscale_option == "์ ์šฉ":
385
+ upscaled_path = upscale_image(temp_filename, output_format, english_prompt, log_list)
386
+
387
+ if upscaled_path:
388
+ try:
389
+ log_message("์—…์Šค์ผ€์ผ๋œ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์ค‘...", log_list)
390
+ final_image = Image.open(upscaled_path)
391
+ log_message(f"์ตœ์ข… ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {final_image.size}", log_list)
392
+ log_message("ํ™”์งˆ ๊ฐœ์„ ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค", log_list)
393
+
394
+ # ์—…์Šค์ผ€์ผ ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
395
+ try:
396
+ os.remove(upscaled_path)
397
+ log_message("์—…์Šค์ผ€์ผ ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ ์™„๋ฃŒ", log_list)
398
+ except:
399
+ pass
400
+
401
+ except Exception as upscale_load_error:
402
+ log_message(f"์—…์Šค์ผ€์ผ๋œ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {str(upscale_load_error)}", log_list)
403
+ log_message("์›๋ณธ FLUX ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค", log_list)
404
+ else:
405
+ log_message("ํ™”์งˆ ๊ฐœ์„  ์‹คํŒจ - ์›๋ณธ FLUX ๊ฒฐ๊ณผ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค", log_list)
406
+ else:
407
+ log_message("ํ™”์งˆ ๊ฐœ์„  ์˜ต์…˜์ด ์„ ํƒ๋˜์ง€ ์•Š์Œ - ์›๋ณธ FLUX ๊ฒฐ๊ณผ ์‚ฌ์šฉ", log_list)
408
+
409
+ # ์ž๋™ ์ €์žฅ ์ฒ˜๋ฆฌ
410
+ log_message("=== ๊ฒฐ๊ณผ ์ €์žฅ ๋‹จ๊ณ„ ===", log_list)
411
+
412
+ if current_images is None:
413
+ current_images = []
414
+ if current_downloads is None:
415
+ current_downloads = []
416
+
417
+ # ๊ฐค๋Ÿฌ๋ฆฌ์šฉ ์ž„์‹œ ํŒŒ์ผ ์ƒ์„ฑ
418
+ gallery_temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.png')
419
+ final_image.save(gallery_temp_file.name, 'png')
420
+ current_images.append(gallery_temp_file.name)
421
+ log_message(f"๊ฐค๋Ÿฌ๋ฆฌ์šฉ ์ด๋ฏธ์ง€ ์ €์žฅ: {gallery_temp_file.name}", log_list)
422
+
423
+ # ๋‹ค์šด๋กœ๋“œ์šฉ ํŒŒ์ผ ์ƒ์„ฑ
424
+ download_filename = f"edited_image_{len(current_downloads) + 1}.{output_format.lower()}"
425
+ final_image.save(download_filename)
426
+ current_downloads.append(download_filename)
427
+ log_message(f"๋‹ค์šด๋กœ๋“œ์šฉ ์ด๋ฏธ์ง€ ์ €์žฅ: {download_filename}", log_list)
428
+
429
+ # ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
430
+ try:
431
+ os.remove(temp_filename)
432
+ log_message("FLUX ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ ์™„๋ฃŒ", log_list)
433
+ except:
434
+ pass
435
+
436
+ log_message("=" * 60, log_list)
437
+ log_message("์ด๋ฏธ์ง€ ํŽธ์ง‘ ์ž‘์—… ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ!", log_list)
438
+ log_message("=" * 60, log_list)
439
+
440
+ return final_image, current_downloads, "\n".join(log_list), current_images, current_downloads
441
+
442
+ except Exception as e:
443
+ error_msg = f"์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
444
+ log_message(error_msg, log_list)
445
+ log_message("=" * 60, log_list)
446
+ log_message("์ด๋ฏธ์ง€ ํŽธ์ง‘ ์ž‘์—… ์‹คํŒจ", log_list)
447
+ log_message("=" * 60, log_list)
448
+ return None, current_downloads, "\n".join(log_list), current_images, current_downloads
449
+
450
+ def save_output_as_input(output_image, current_images, current_downloads):
451
+ """์ถœ๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ์ž…๋ ฅ์œผ๋กœ ์ €์žฅ"""
452
+ log_list = []
453
+ log_message("=== ์ถœ๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ์ž…๋ ฅ์œผ๋กœ ์ €์žฅ ์‹œ์ž‘ ===", log_list)
454
+
455
+ if output_image is None:
456
+ log_message("์ €์žฅํ•  ์ถœ๋ ฅ ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค", log_list)
457
+ return None, current_images, current_downloads
458
+
459
+ try:
460
+ log_message(f"์ถœ๋ ฅ ์ด๋ฏธ์ง€ ํƒ€์ž…: {type(output_image)}", log_list)
461
+
462
+ # numpy array๋ฅผ PIL Image๋กœ ๋ณ€ํ™˜
463
+ if hasattr(output_image, 'shape'): # numpy array์ธ ๊ฒฝ์šฐ
464
+ log_message("numpy array๋ฅผ PIL Image๋กœ ๋ณ€ํ™˜ ์ค‘...", log_list)
465
+ output_image = Image.fromarray(output_image)
466
+
467
+ log_message(f"๋ณ€ํ™˜๋œ ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {output_image.size}", log_list)
468
+ log_message(f"๋ณ€ํ™˜๋œ ์ด๋ฏธ์ง€ ๋ชจ๋“œ: {output_image.mode}", log_list)
469
+
470
+ # ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ (์ž…๋ ฅ์šฉ)
471
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.png')
472
+ output_image.save(temp_file.name, 'png')
473
+
474
+ file_size = os.path.getsize(temp_file.name)
475
+ log_message(f"์ž…๋ ฅ์šฉ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {temp_file.name}", log_list)
476
+ log_message(f"์ €์žฅ๋œ ํŒŒ์ผ ํฌ๊ธฐ: {file_size} bytes ({file_size/1024/1024:.2f} MB)", log_list)
477
+ log_message("=== ์ €์žฅ ํ”„๋กœ์„ธ์Šค ์™„๋ฃŒ ===", log_list)
478
+
479
+ print("\n".join(log_list)) # ์ฝ˜์†”์— ๋กœ๊ทธ ์ถœ๋ ฅ
480
+ return temp_file.name, current_images, current_downloads
481
+
482
+ except Exception as e:
483
+ error_msg = f"์ด๋ฏธ์ง€ ์ €์žฅ ์ค‘ ์˜ค๋ฅ˜: {str(e)}"
484
+ log_message(error_msg, log_list)
485
+ log_message("=== ์ €์žฅ ํ”„๋กœ์„ธ์Šค ์‹คํŒจ ===", log_list)
486
+ print("\n".join(log_list)) # ์ฝ˜์†”์— ๋กœ๊ทธ ์ถœ๋ ฅ
487
+ return None, current_images, current_downloads
488
+
489
+ # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ API ํ‚ค ํ™•์ธ
490
+ try:
491
+ validate_api_keys()
492
+ print("โœ… ๋ชจ๋“  API ํ‚ค๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
493
+ except ValueError as e:
494
+ print(f"โŒ {e}")
495
+ print("\n๐Ÿ”ง ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • ๋ฐฉ๋ฒ•:")
496
+ print("Hugging Face Spaces์—์„œ:")
497
+ print("1. Settings > Repository secrets ๋กœ ์ด๋™")
498
+ print("2. ๋‹ค์Œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋“ค์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”:")
499
+ print(" - REPLICATE_API_TOKEN: Replicate API ํ† ํฐ")
500
+ print(" - GEMINI_API_KEY: Google Gemini API ํ‚ค")
501
+ print(" - APP_PASSWORD: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋น„๋ฐ€๋ฒˆํ˜ธ (์„ ํƒ์‚ฌํ•ญ)")
502
+
503
+ # Gradio ์ธํ„ฐํŽ˜์ด์Šค
504
+ with gr.Blocks(title="์ด๋ฏธ์ง€ ํŽธ์ง‘๊ธฐ (๋ณด์•ˆ ๊ฐ•ํ™” ๋ฒ„์ „)") as demo:
505
+ # ์ƒํƒœ ๋ณ€์ˆ˜๋“ค
506
+ saved_images = gr.State([])
507
+ saved_downloads = gr.State([])
508
+
509
+ gr.Markdown("# ๐ŸŽจ AI ์ด๋ฏธ์ง€ ํŽธ์ง‘๊ธฐ (๋ณด์•ˆ ๊ฐ•ํ™” ๋ฒ„์ „)")
510
+ with gr.Row():
511
+ with gr.Column():
512
+ input_image = gr.Image(type="filepath", label="๐Ÿ“ค ์ž…๋ ฅ ์ด๋ฏธ์ง€")
513
+ password = gr.Textbox(
514
+ label="๐Ÿ” ๋น„๋ฐ€๋ฒˆํ˜ธ",
515
+ type="password",
516
+ placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”"
517
+ )
518
+ korean_prompt = gr.Textbox(
519
+ label="โœ๏ธ ํŽธ์ง‘ ์ง€์‹œ์‚ฌํ•ญ (ํ•œ๊ตญ์–ด)",
520
+ placeholder="์˜ˆ: ์ด ์‚ฌ๋žŒ์„ ๋งŒํ™” ์บ๋ฆญํ„ฐ๋กœ ๋ฐ”๊ฟ”์ค˜",
521
+ lines=3
522
+ )
523
+
524
+ with gr.Row():
525
+ output_format = gr.Radio(
526
+ choices=["jpg", "png"],
527
+ value="jpg",
528
+ label="๐Ÿ“ ์ถœ๋ ฅ ํฌ๋งท"
529
+ )
530
+ aspect_ratio = gr.Dropdown(
531
+ choices=["match_input_image", "1:1", "3:2", "2:3"],
532
+ value="match_input_image",
533
+ label="๐Ÿ“ ํ™”๋ฉด ๋น„์œจ"
534
+ )
535
+
536
+ upscale_option = gr.Radio(
537
+ choices=["์—†์Œ", "์ ์šฉ"],
538
+ value="์—†์Œ",
539
+ label="๐Ÿ” ํ™”์งˆ ๊ฐœ์„  (2๋ฐฐ ํ™•๋Œ€)"
540
+ )
541
+
542
+ edit_btn = gr.Button("๐Ÿš€ ์ด๋ฏธ์ง€ ํŽธ์ง‘", variant="primary", size="lg")
543
+
544
+ with gr.Column():
545
+ output_image = gr.Image(label="โœจ ํŽธ์ง‘๋œ ์ด๋ฏธ์ง€")
546
+ log_output = gr.Textbox(
547
+ label="๐Ÿ“‹ ์ƒ์„ธ ๋กœ๊ทธ",
548
+ lines=15,
549
+ max_lines=20,
550
+ show_copy_button=True
551
+ )
552
+ download_files = gr.File(label="๐Ÿ’พ ๋‹ค์šด๋กœ๋“œ", file_count="multiple")
553
+
554
+ save_btn = gr.Button("๐Ÿ”„ ์ถœ๋ ฅ ์ด๋ฏธ์ง€๋ฅผ ์ž…๋ ฅ์œผ๋กœ ์ €์žฅ", variant="secondary")
555
+
556
+ # ์ €์žฅ๋œ ์ด๋ฏธ์ง€๋“ค์„ ํ‘œ์‹œํ•˜๋Š” ๊ฐค๋Ÿฌ๋ฆฌ
557
+ with gr.Row():
558
+ output_gallery = gr.Gallery(
559
+ label="๐Ÿ“ธ ํŽธ์ง‘ ๊ธฐ๋ก",
560
+ show_label=True,
561
+ elem_id="gallery",
562
+ columns=3,
563
+ rows=2,
564
+ height="auto"
565
+ )
566
+
567
+
568
+ # ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
569
+ edit_btn.click(
570
+ fn=edit_image,
571
+ inputs=[input_image, password, korean_prompt, output_format, aspect_ratio, upscale_option, saved_images, saved_downloads],
572
+ outputs=[output_image, download_files, log_output, saved_images, saved_downloads]
573
+ )
574
+
575
+ save_btn.click(
576
+ fn=save_output_as_input,
577
+ inputs=[output_image, saved_images, saved_downloads],
578
+ outputs=[input_image, saved_images, saved_downloads]
579
+ )
580
+
581
+ # ๊ฐค๋Ÿฌ๋ฆฌ ์—…๋ฐ์ดํŠธ
582
+ saved_images.change(
583
+ fn=lambda images: images if images else [],
584
+ inputs=[saved_images],
585
+ outputs=[output_gallery]
586
+ )
587
+
588
+ if __name__ == "__main__":
589
+ print("๐Ÿš€ ์ด๋ฏธ์ง€ ํŽธ์ง‘ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์ค‘...")
590
+ print("๐Ÿ” ๋ณด์•ˆ ๊ฐ•ํ™” ๋ฒ„์ „ - ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์‚ฌ์šฉ")
591
+ print("๐Ÿ“Š ์ƒ์„ธ ๋กœ๊ทธ ์‹œ์Šคํ…œ์ด ํ™œ์„ฑํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
592
+ print("๐Ÿ” ๋ชจ๋“  API ํ˜ธ์ถœ๊ณผ ์ฒ˜๋ฆฌ ๊ณผ์ •์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค.")
593
+
594
+ # API ํ‚ค ์ƒํƒœ ํ™•์ธ
595
+ try:
596
+ validate_api_keys()
597
+ print("โœ… ๋ชจ๋“  API ํ‚ค๊ฐ€ ์„ค์ •๋˜์–ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.")
598
+ except ValueError as e:
599
+ print(f"โš ๏ธ ๊ฒฝ๊ณ : {e}")
600
+ print("์ผ๋ถ€ ๊ธฐ๋Šฅ์ด ์ œํ•œ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")
601
+
602
+ demo.launch(
603
+ server_name="0.0.0.0",
604
+ server_port=7860,
605
+ share=False,
606
+ debug=True
607
+ )