ssboost commited on
Commit
8b8ac8e
ยท
verified ยท
1 Parent(s): f5eb2ec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +168 -107
app.py CHANGED
@@ -7,79 +7,109 @@ from typing import List, Tuple, Optional, Any
7
  import gradio as gr
8
  from gradio_client import Client, handle_file
9
  from dotenv import load_dotenv
 
10
 
11
  # .env ํŒŒ์ผ ๋กœ๋“œ
12
  load_dotenv()
13
 
14
  # ๋กœ๊น… ์„ค์ • (API ์—”๋“œํฌ์ธํŠธ ์ •๋ณด๋Š” ๋กœ๊ทธ์— ๋‚จ๊ธฐ์ง€ ์•Š์Œ)
15
- logging.basicConfig(
16
- level=logging.INFO,
17
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
18
- handlers=[
19
- logging.FileHandler("app.log"),
20
- logging.StreamHandler(sys.stdout)
21
- ]
22
- )
 
 
 
 
 
 
 
 
 
23
  logger = logging.getLogger("image-enhancer-control-tower")
 
 
 
24
 
25
  class GradioClientController:
26
  """ํ—ˆ๊น…ํŽ˜์ด์Šค ๊ทธ๋ผ๋””์˜ค API ํด๋ผ์ด์–ธํŠธ ์ปจํŠธ๋กค๋Ÿฌ"""
27
 
28
  def __init__(self):
29
  self.client = None
 
30
  self._initialize_client()
31
 
32
  def _initialize_client(self):
33
  """ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” (์—”๋“œํฌ์ธํŠธ ์ •๋ณด๋Š” ๋กœ๊ทธ์— ๋‚จ๊ธฐ์ง€ ์•Š์Œ)"""
34
  try:
35
- api_endpoint = os.environ.get("API_ENDPOINT")
36
- if not api_endpoint:
37
  logger.error("API_ENDPOINT ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
38
  raise ValueError("API_ENDPOINT ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.")
39
 
40
- self.client = Client(api_endpoint)
41
- logger.info("API ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ดˆ๊ธฐํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
42
-
 
 
 
 
 
 
 
 
 
 
 
43
  except Exception as e:
44
- logger.error(f"ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์‹คํŒจ: {e}")
45
  self.client = None
46
 
 
 
 
 
 
 
 
47
  def update_dropdowns(self, bg_type: str) -> Tuple:
48
  """๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋”ฐ๋ฅธ ๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ"""
49
  try:
50
- if not self.client:
51
- logger.error("ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
52
  return tuple([gr.update() for _ in range(7)])
53
 
54
  result = self.client.predict(
55
- bg_type=bg_type,
56
  api_name="/update_dropdowns"
57
  )
58
 
59
  logger.info(f"๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ: {bg_type}")
60
 
61
  # ๊ฒฐ๊ณผ๋ฅผ Gradio ์—…๋ฐ์ดํŠธ ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
62
- updates = []
63
- for i, choices in enumerate(result):
64
- if i == 0: # ์‹ฌํ”Œ ๋ฐฐ๊ฒฝ
65
- updates.append(gr.update(visible=(bg_type == "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ"), choices=choices, value=choices[0] if choices else None))
66
- elif i == 1: # ์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ
67
- updates.append(gr.update(visible=(bg_type == "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ"), choices=choices, value=choices[0] if choices else None))
68
- elif i == 2: # ์ž์—ฐ ํ™˜๊ฒฝ
69
- updates.append(gr.update(visible=(bg_type == "์ž์—ฐ ํ™˜๊ฒฝ"), choices=choices, value=choices[0] if choices else None))
70
- elif i == 3: # ์‹ค๋‚ด ํ™˜๊ฒฝ
71
- updates.append(gr.update(visible=(bg_type == "์‹ค๋‚ด ํ™˜๏ฟฝ๏ฟฝ๏ฟฝ"), choices=choices, value=choices[0] if choices else None))
72
- elif i == 4: # ํŠน์ˆ˜๋ฐฐ๊ฒฝ
73
- updates.append(gr.update(visible=(bg_type == "ํŠน์ˆ˜๋ฐฐ๊ฒฝ"), choices=choices, value=choices[0] if choices else None))
74
- elif i == 5: # ์ฃผ์–ผ๋ฆฌ
75
- updates.append(gr.update(visible=(bg_type == "์ฃผ์–ผ๋ฆฌ"), choices=choices, value=choices[0] if choices else None))
76
- elif i == 6: # ํŠน์ˆ˜ํšจ๊ณผ
77
- updates.append(gr.update(visible=(bg_type == "ํŠน์ˆ˜ํšจ๊ณผ"), choices=choices, value=choices[0] if choices else None))
78
-
79
- return tuple(updates)
80
 
81
  except Exception as e:
82
- logger.error(f"๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ ์˜ค๋ฅ˜: {e}")
83
  return tuple([gr.update() for _ in range(7)])
84
 
85
  def generate_prompt_only(self, password: str, bg_type: str, simple: str, studio: str,
@@ -87,30 +117,29 @@ class GradioClientController:
87
  special_effects: str, request_text: str, aspect_ratio: str) -> str:
88
  """ํ”„๋กฌํ”„ํŠธ๋งŒ ์ƒ์„ฑ"""
89
  try:
90
- if not self.client:
91
- logger.error("ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
92
- return "ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์˜ค๋ฅ˜"
93
 
94
  result = self.client.predict(
95
- password=password,
96
- bg_type=bg_type,
97
- simple=simple,
98
- studio=studio,
99
- nature=nature,
100
- indoor=indoor,
101
- special=special,
102
- jewelry=jewelry,
103
- special_effects=special_effects,
104
- request_text=request_text,
105
- aspect_ratio=aspect_ratio,
106
  api_name="/generate_prompt_with_password_check"
107
  )
108
 
109
  logger.info("ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์™„๋ฃŒ")
110
- return result
111
 
112
  except Exception as e:
113
- logger.error(f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์˜ค๋ฅ˜: {e}")
114
  return f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์˜ค๋ฅ˜: {str(e)}"
115
 
116
  def process_image(self, password: str, image, bg_type: str, simple: str, studio: str,
@@ -118,58 +147,66 @@ class GradioClientController:
118
  request_text: str, quality_level: str, aspect_ratio: str,
119
  output_format: str, enable_enhancement: bool) -> Tuple:
120
  """์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ (ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ )"""
 
121
  try:
122
- if not self.client:
123
- logger.error("ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
124
- return ([], None, [], None, "", "", "ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์˜ค๋ฅ˜")
 
 
 
125
 
126
  # ์ด๋ฏธ์ง€๋ฅผ ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ
127
- temp_path = None
128
- if image is not None:
129
- temp_path = tempfile.mktemp(suffix='.png')
130
- image.save(temp_path)
 
 
 
131
 
132
  # API ํ˜ธ์ถœ
 
133
  result = self.client.predict(
134
- password=password,
135
- param_1=handle_file(temp_path) if temp_path else None,
136
- param_2=bg_type,
137
- param_3=simple,
138
- param_4=studio,
139
- param_5=nature,
140
- param_6=indoor,
141
- param_7=special,
142
- param_8=jewelry,
143
- param_9=special_effects,
144
- param_10=request_text,
145
- param_11=quality_level,
146
- param_12=aspect_ratio,
147
- param_13=output_format,
148
- param_14=enable_enhancement,
149
  api_name="/check_password"
150
  )
151
 
152
- # ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
153
- if temp_path and os.path.exists(temp_path):
154
- try:
155
- os.remove(temp_path)
156
- except:
157
- pass
158
 
159
- logger.info("์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์™„๋ฃŒ")
160
-
161
- # ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜: (original_output, original_download, enhanced_output, enhanced_download, prompt_output, info, error)
162
- return result
 
 
163
 
164
  except Exception as e:
165
- logger.error(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์˜ค๋ฅ˜: {e}")
 
 
 
166
  # ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
167
- if 'temp_path' in locals() and temp_path and os.path.exists(temp_path):
168
  try:
169
  os.remove(temp_path)
170
- except:
171
- pass
172
- return ([], None, [], None, "", "", f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์˜ค๋ฅ˜: {str(e)}")
173
 
174
  # ์ „์—ญ ํด๋ผ์ด์–ธํŠธ ์ปจํŠธ๋กค๋Ÿฌ ์ธ์Šคํ„ด์Šค
175
  controller = GradioClientController()
@@ -179,10 +216,17 @@ def create_gradio_interface():
179
  try:
180
  logger.info("Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ์‹œ์ž‘")
181
 
182
- # ๋ฐฐ๊ฒฝ ์œ ํ˜• ์„ ํƒ์ง€ (ํ•˜๋“œ์ฝ”๋”ฉ)
183
  background_types = ["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "ํŠน์ˆ˜๋ฐฐ๊ฒฝ", "์ฃผ์–ผ๋ฆฌ", "ํŠน์ˆ˜ํšจ๊ณผ"]
184
 
185
- with gr.Blocks(title="AI ์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ ") as app:
 
 
 
 
 
 
 
186
  gr.Markdown("# AI ์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„  ๋„๊ตฌ")
187
 
188
  # ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํ•„๋“œ
@@ -256,14 +300,6 @@ def create_gradio_interface():
256
  visible=False,
257
  interactive=True
258
  )
259
-
260
- # ๋“œ๋กญ๋‹ค์šด ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ
261
- background_type.change(
262
- fn=controller.update_dropdowns,
263
- inputs=[background_type],
264
- outputs=[simple_dropdown, studio_dropdown, nature_dropdown,
265
- indoor_dropdown, special_dropdown, jewelry_dropdown, special_effects_dropdown]
266
- )
267
 
268
  # ์š”์ฒญ์‚ฌํ•ญ ์ž…๋ ฅ
269
  request_text = gr.Textbox(
@@ -277,7 +313,7 @@ def create_gradio_interface():
277
  label="ํ’ˆ์งˆ ๋ ˆ๋ฒจ",
278
  choices=["gpt", "flux"],
279
  value="flux",
280
- info="GPT: GPT ๋ชจ๋ธ (๊ณ ํ’ˆ์งˆ), ์ผ๋ฐ˜: Flux ๋ชจ๋ธ (๋น ๋ฅธ ์ฒ˜๋ฆฌ + ๊ธฐ๋ณธ ํ™”์งˆ๊ฐœ์„ )"
281
  )
282
 
283
  aspect_ratio = gr.Dropdown(
@@ -300,10 +336,10 @@ def create_gradio_interface():
300
  )
301
 
302
  # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ
303
- generate_prompt_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ๋งŒ ์ƒ์„ฑ")
304
 
305
  # ํŽธ์ง‘ ๋ฒ„ํŠผ
306
- edit_btn = gr.Button("์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ ")
307
 
308
  with gr.Column():
309
  with gr.Row():
@@ -322,6 +358,14 @@ def create_gradio_interface():
322
  info = gr.Textbox(label="์ฒ˜๋ฆฌ ์ •๋ณด", interactive=False)
323
  error = gr.Textbox(label="์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€", interactive=False, visible=True)
324
 
 
 
 
 
 
 
 
 
325
  # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
326
  generate_prompt_btn.click(
327
  fn=controller.generate_prompt_only,
@@ -352,7 +396,7 @@ def create_gradio_interface():
352
  ]
353
  )
354
 
355
- # ์ดˆ๊ธฐ ๋“œ๋กญ๋‹ค์šด ๋กœ๋“œ
356
  app.load(
357
  fn=controller.update_dropdowns,
358
  inputs=[background_type],
@@ -364,7 +408,7 @@ def create_gradio_interface():
364
  return app
365
 
366
  except Exception as e:
367
- logger.error(f"Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ์˜ค๋ฅ˜: {e}")
368
  logger.error(traceback.format_exc())
369
  raise
370
 
@@ -377,10 +421,27 @@ if __name__ == "__main__":
377
  os.makedirs("imgs", exist_ok=True)
378
  logger.info("์ด๋ฏธ์ง€ ๋””๋ ‰ํ† ๋ฆฌ ์ค€๋น„ ์™„๋ฃŒ")
379
 
 
 
 
 
 
 
 
380
  app = create_gradio_interface()
381
  logger.info("Gradio ์•ฑ ์‹œ์ž‘")
382
- app.launch(share=True)
 
 
 
 
 
 
383
 
 
 
384
  except Exception as e:
385
- logger.error(f"์•ฑ ์‹คํ–‰ ์˜ค๋ฅ˜: {e}")
386
- logger.error(traceback.format_exc())
 
 
 
7
  import gradio as gr
8
  from gradio_client import Client, handle_file
9
  from dotenv import load_dotenv
10
+ import time
11
 
12
  # .env ํŒŒ์ผ ๋กœ๋“œ
13
  load_dotenv()
14
 
15
  # ๋กœ๊น… ์„ค์ • (API ์—”๋“œํฌ์ธํŠธ ์ •๋ณด๋Š” ๋กœ๊ทธ์— ๋‚จ๊ธฐ์ง€ ์•Š์Œ)
16
+ class SafeFormatter(logging.Formatter):
17
+ """API ์—”๋“œํฌ์ธํŠธ ์ •๋ณด๋ฅผ ๋กœ๊ทธ์—์„œ ์ œ๊ฑฐํ•˜๋Š” ์•ˆ์ „ํ•œ ํฌ๋งคํ„ฐ"""
18
+ def format(self, record):
19
+ # API_ENDPOINT ๊ด€๋ จ ์ •๋ณด ํ•„ํ„ฐ๋ง
20
+ msg = super().format(record)
21
+ # ๋ฏผ๊ฐํ•œ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ ๊ฒฝ์šฐ ๋งˆ์Šคํ‚น
22
+ if "API_ENDPOINT" in msg or "happydoggg" in msg or "49493h" in msg:
23
+ return msg.replace(os.environ.get("API_ENDPOINT", ""), "[API_ENDPOINT_HIDDEN]")
24
+ return msg
25
+
26
+ # ๋กœ๊ทธ ํ•ธ๋“ค๋Ÿฌ ์„ค์ •
27
+ file_handler = logging.FileHandler("app.log")
28
+ console_handler = logging.StreamHandler(sys.stdout)
29
+ formatter = SafeFormatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
30
+ file_handler.setFormatter(formatter)
31
+ console_handler.setFormatter(formatter)
32
+
33
  logger = logging.getLogger("image-enhancer-control-tower")
34
+ logger.setLevel(logging.INFO)
35
+ logger.addHandler(file_handler)
36
+ logger.addHandler(console_handler)
37
 
38
  class GradioClientController:
39
  """ํ—ˆ๊น…ํŽ˜์ด์Šค ๊ทธ๋ผ๋””์˜ค API ํด๋ผ์ด์–ธํŠธ ์ปจํŠธ๋กค๋Ÿฌ"""
40
 
41
  def __init__(self):
42
  self.client = None
43
+ self.api_endpoint = None
44
  self._initialize_client()
45
 
46
  def _initialize_client(self):
47
  """ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” (์—”๋“œํฌ์ธํŠธ ์ •๋ณด๋Š” ๋กœ๊ทธ์— ๋‚จ๊ธฐ์ง€ ์•Š์Œ)"""
48
  try:
49
+ self.api_endpoint = os.environ.get("API_ENDPOINT")
50
+ if not self.api_endpoint:
51
  logger.error("API_ENDPOINT ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
52
  raise ValueError("API_ENDPOINT ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.")
53
 
54
+ # ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์‹œ๋„ (์žฌ์‹œ๋„ ๋กœ์ง ํฌํ•จ)
55
+ max_retries = 3
56
+ for attempt in range(max_retries):
57
+ try:
58
+ self.client = Client(self.api_endpoint)
59
+ logger.info("API ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ดˆ๊ธฐํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
60
+ return
61
+ except Exception as e:
62
+ if attempt < max_retries - 1:
63
+ logger.warning(f"ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์žฌ์‹œ๋„ {attempt + 1}/{max_retries}")
64
+ time.sleep(2)
65
+ else:
66
+ raise e
67
+
68
  except Exception as e:
69
+ logger.error(f"ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์‹คํŒจ: {str(e)}")
70
  self.client = None
71
 
72
+ def _ensure_client(self) -> bool:
73
+ """ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์ƒํƒœ ํ™•์ธ ๋ฐ ์žฌ์—ฐ๊ฒฐ"""
74
+ if self.client is None:
75
+ logger.info("ํด๋ผ์ด์–ธํŠธ ์žฌ์—ฐ๊ฒฐ ์‹œ๋„")
76
+ self._initialize_client()
77
+ return self.client is not None
78
+
79
  def update_dropdowns(self, bg_type: str) -> Tuple:
80
  """๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋”ฐ๋ฅธ ๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ"""
81
  try:
82
+ if not self._ensure_client():
83
+ logger.error("ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์‹คํŒจ")
84
  return tuple([gr.update() for _ in range(7)])
85
 
86
  result = self.client.predict(
87
+ bg_type,
88
  api_name="/update_dropdowns"
89
  )
90
 
91
  logger.info(f"๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ: {bg_type}")
92
 
93
  # ๊ฒฐ๊ณผ๋ฅผ Gradio ์—…๋ฐ์ดํŠธ ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
94
+ if isinstance(result, (list, tuple)) and len(result) >= 7:
95
+ updates = []
96
+ visibility_map = ["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "ํŠน์ˆ˜๋ฐฐ๊ฒฝ", "์ฃผ์–ผ๋ฆฌ", "ํŠน์ˆ˜ํšจ๊ณผ"]
97
+
98
+ for i, choices in enumerate(result[:7]):
99
+ is_visible = (bg_type == visibility_map[i])
100
+ updates.append(gr.update(
101
+ visible=is_visible,
102
+ choices=choices if choices else [],
103
+ value=choices[0] if choices and len(choices) > 0 else None
104
+ ))
105
+
106
+ return tuple(updates)
107
+ else:
108
+ logger.warning("API์—์„œ ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅธ ํ˜•์‹์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค.")
109
+ return tuple([gr.update() for _ in range(7)])
 
 
110
 
111
  except Exception as e:
112
+ logger.error(f"๋“œ๋กญ๋‹ค์šด ์—…๋ฐ์ดํŠธ ์˜ค๋ฅ˜: {str(e)}")
113
  return tuple([gr.update() for _ in range(7)])
114
 
115
  def generate_prompt_only(self, password: str, bg_type: str, simple: str, studio: str,
 
117
  special_effects: str, request_text: str, aspect_ratio: str) -> str:
118
  """ํ”„๋กฌํ”„ํŠธ๋งŒ ์ƒ์„ฑ"""
119
  try:
120
+ if not self._ensure_client():
121
+ return "ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”."
 
122
 
123
  result = self.client.predict(
124
+ password,
125
+ bg_type,
126
+ simple or "",
127
+ studio or "",
128
+ nature or "",
129
+ indoor or "",
130
+ special or "",
131
+ jewelry or "",
132
+ special_effects or "",
133
+ request_text or "",
134
+ aspect_ratio,
135
  api_name="/generate_prompt_with_password_check"
136
  )
137
 
138
  logger.info("ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์™„๋ฃŒ")
139
+ return result if result else "ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค."
140
 
141
  except Exception as e:
142
+ logger.error(f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์˜ค๋ฅ˜: {str(e)}")
143
  return f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์˜ค๋ฅ˜: {str(e)}"
144
 
145
  def process_image(self, password: str, image, bg_type: str, simple: str, studio: str,
 
147
  request_text: str, quality_level: str, aspect_ratio: str,
148
  output_format: str, enable_enhancement: bool) -> Tuple:
149
  """์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ (ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ )"""
150
+ temp_path = None
151
  try:
152
+ if not self._ensure_client():
153
+ return ([], None, [], None, "", "", "ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.")
154
+
155
+ # ์ด๋ฏธ์ง€ ๊ฒ€์ฆ
156
+ if image is None:
157
+ return ([], None, [], None, "", "", "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”.")
158
 
159
  # ์ด๋ฏธ์ง€๋ฅผ ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ
160
+ temp_path = tempfile.mktemp(suffix='.png')
161
+ try:
162
+ image.save(temp_path, format='PNG')
163
+ logger.info(f"์ด๋ฏธ์ง€๋ฅผ ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ: {os.path.basename(temp_path)}")
164
+ except Exception as e:
165
+ logger.error(f"์ด๋ฏธ์ง€ ์ €์žฅ ์‹คํŒจ: {str(e)}")
166
+ return ([], None, [], None, "", "", "์ด๋ฏธ์ง€ ์ €์žฅ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ด๋ฏธ์ง€๋ฅผ ์‹œ๋„ํ•ด๋ณด์„ธ์š”.")
167
 
168
  # API ํ˜ธ์ถœ
169
+ logger.info("์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ API ํ˜ธ์ถœ ์‹œ์ž‘")
170
  result = self.client.predict(
171
+ password,
172
+ handle_file(temp_path),
173
+ bg_type,
174
+ simple or "",
175
+ studio or "",
176
+ nature or "",
177
+ indoor or "",
178
+ special or "",
179
+ jewelry or "",
180
+ special_effects or "",
181
+ request_text or "",
182
+ quality_level,
183
+ aspect_ratio,
184
+ output_format,
185
+ enable_enhancement,
186
  api_name="/check_password"
187
  )
188
 
189
+ logger.info("์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ API ํ˜ธ์ถœ ์™„๋ฃŒ")
 
 
 
 
 
190
 
191
+ # ๊ฒฐ๊ณผ ๊ฒ€์ฆ ๋ฐ ๋ฐ˜ํ™˜
192
+ if isinstance(result, (list, tuple)) and len(result) >= 7:
193
+ return result
194
+ else:
195
+ logger.warning("API์—์„œ ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅธ ํ˜•์‹์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค.")
196
+ return ([], None, [], None, "", "", "API์—์„œ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ์‘๋‹ต์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.")
197
 
198
  except Exception as e:
199
+ logger.error(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์˜ค๋ฅ˜: {str(e)}")
200
+ return ([], None, [], None, "", "", f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}")
201
+
202
+ finally:
203
  # ์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ
204
+ if temp_path and os.path.exists(temp_path):
205
  try:
206
  os.remove(temp_path)
207
+ logger.info("์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ ์™„๋ฃŒ")
208
+ except Exception as e:
209
+ logger.warning(f"์ž„์‹œ ํŒŒ์ผ ์ •๋ฆฌ ์‹คํŒจ: {str(e)}")
210
 
211
  # ์ „์—ญ ํด๋ผ์ด์–ธํŠธ ์ปจํŠธ๋กค๋Ÿฌ ์ธ์Šคํ„ด์Šค
212
  controller = GradioClientController()
 
216
  try:
217
  logger.info("Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ์‹œ์ž‘")
218
 
219
+ # ๋ฐฐ๊ฒฝ ์œ ํ˜• ์„ ํƒ์ง€
220
  background_types = ["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "ํŠน์ˆ˜๋ฐฐ๊ฒฝ", "์ฃผ์–ผ๋ฆฌ", "ํŠน์ˆ˜ํšจ๊ณผ"]
221
 
222
+ # ์ปค์Šคํ…€ CSS ์ถ”๊ฐ€ (์›๋ณธ๊ณผ ๋™์ผํ•œ ์Šคํƒ€์ผ ์œ ์ง€)
223
+ css = """
224
+ .gradio-container {
225
+ max-width: 1200px !important;
226
+ }
227
+ """
228
+
229
+ with gr.Blocks(title="AI ์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ ", css=css, theme=gr.themes.Soft()) as app:
230
  gr.Markdown("# AI ์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„  ๋„๊ตฌ")
231
 
232
  # ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํ•„๋“œ
 
300
  visible=False,
301
  interactive=True
302
  )
 
 
 
 
 
 
 
 
303
 
304
  # ์š”์ฒญ์‚ฌํ•ญ ์ž…๋ ฅ
305
  request_text = gr.Textbox(
 
313
  label="ํ’ˆ์งˆ ๋ ˆ๋ฒจ",
314
  choices=["gpt", "flux"],
315
  value="flux",
316
+ info="GPT: GPT ๋ชจ๋ธ (๊ณ ํ’ˆ์งˆ), Flux: Flux ๋ชจ๋ธ (๋น ๋ฅธ ์ฒ˜๋ฆฌ + ๊ธฐ๋ณธ ํ™”์งˆ๊ฐœ์„ )"
317
  )
318
 
319
  aspect_ratio = gr.Dropdown(
 
336
  )
337
 
338
  # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ
339
+ generate_prompt_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ๋งŒ ์ƒ์„ฑ", variant="secondary")
340
 
341
  # ํŽธ์ง‘ ๋ฒ„ํŠผ
342
+ edit_btn = gr.Button("์ด๋ฏธ์ง€ ํŽธ์ง‘ ๋ฐ ํ™”์งˆ ๊ฐœ์„ ", variant="primary")
343
 
344
  with gr.Column():
345
  with gr.Row():
 
358
  info = gr.Textbox(label="์ฒ˜๋ฆฌ ์ •๋ณด", interactive=False)
359
  error = gr.Textbox(label="์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€", interactive=False, visible=True)
360
 
361
+ # ๋“œ๋กญ๋‹ค์šด ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ
362
+ background_type.change(
363
+ fn=controller.update_dropdowns,
364
+ inputs=[background_type],
365
+ outputs=[simple_dropdown, studio_dropdown, nature_dropdown,
366
+ indoor_dropdown, special_dropdown, jewelry_dropdown, special_effects_dropdown]
367
+ )
368
+
369
  # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
370
  generate_prompt_btn.click(
371
  fn=controller.generate_prompt_only,
 
396
  ]
397
  )
398
 
399
+ # ์•ฑ ๋กœ๋“œ ์‹œ ์ดˆ๊ธฐ ๋“œ๋กญ๋‹ค์šด ์„ค์ •
400
  app.load(
401
  fn=controller.update_dropdowns,
402
  inputs=[background_type],
 
408
  return app
409
 
410
  except Exception as e:
411
+ logger.error(f"Gradio ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ ์˜ค๋ฅ˜: {str(e)}")
412
  logger.error(traceback.format_exc())
413
  raise
414
 
 
421
  os.makedirs("imgs", exist_ok=True)
422
  logger.info("์ด๋ฏธ์ง€ ๋””๋ ‰ํ† ๋ฆฌ ์ค€๋น„ ์™„๋ฃŒ")
423
 
424
+ # API ์—”๋“œํฌ์ธํŠธ ํ™•์ธ
425
+ if not os.environ.get("API_ENDPOINT"):
426
+ logger.error("API_ENDPOINT ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
427
+ print("\nโŒ ์˜ค๋ฅ˜: API_ENDPOINT ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
428
+ print("ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ .env ํŒŒ์ผ์— API_ENDPOINT๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.")
429
+ sys.exit(1)
430
+
431
  app = create_gradio_interface()
432
  logger.info("Gradio ์•ฑ ์‹œ์ž‘")
433
+ app.launch(
434
+ share=True,
435
+ server_name="0.0.0.0",
436
+ server_port=7860,
437
+ show_error=True,
438
+ quiet=False
439
+ )
440
 
441
+ except KeyboardInterrupt:
442
+ logger.info("์‚ฌ์šฉ์ž์— ์˜ํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ค‘๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
443
  except Exception as e:
444
+ logger.error(f"์•ฑ ์‹คํ–‰ ์˜ค๋ฅ˜: {str(e)}")
445
+ logger.error(traceback.format_exc())
446
+ print(f"\nโŒ ์‹ฌ๊ฐํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}")
447
+ print("์ž์„ธํ•œ ๋‚ด์šฉ์€ app.log ํŒŒ์ผ์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.")