Kims12 commited on
Commit
bfd9212
ยท
verified ยท
1 Parent(s): c5884f7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +99 -171
app.py CHANGED
@@ -9,15 +9,12 @@ import base64
9
  import mimetypes
10
  import logging
11
 
12
- import google.generativeai as genai
13
- from google.generativeai import types
14
 
15
  # .env ํŒŒ์ผ์— ์ €์žฅ๋œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋กœ๋“œ (python-dotenv ์„ค์น˜ ํ•„์š”: pip install python-dotenv)
16
- try:
17
- from dotenv import load_dotenv
18
- load_dotenv()
19
- except ImportError:
20
- logger.warning("python-dotenv๊ฐ€ ์„ค์น˜๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ง์ ‘ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.")
21
 
22
  # ๋กœ๊น… ์„ค์ • (๋กœ๊ทธ ๋ ˆ๋ฒจ: DEBUG)
23
  logging.basicConfig(level=logging.DEBUG,
@@ -32,19 +29,8 @@ def save_binary_file(file_name, data):
32
  logger.debug(f"ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ: {file_name}")
33
 
34
 
35
- def generate(text, files_list, model="gemini-2.0-flash-exp-image-generation"):
36
- """
37
- ์—ฌ๋Ÿฌ ์ด๋ฏธ์ง€์™€ ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Gemini API๋กœ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜
38
-
39
- Args:
40
- text (str): ์ด๋ฏธ์ง€ ์ƒ์„ฑ์— ์‚ฌ์šฉํ•  ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ
41
- files_list (list): ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ ๋ฆฌ์ŠคํŠธ
42
- model (str): ์‚ฌ์šฉํ•  Gemini ๋ชจ๋ธ๋ช…
43
-
44
- Returns:
45
- str: ์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€์˜ ํŒŒ์ผ ๊ฒฝ๋กœ ๋˜๋Š” None (์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ)
46
- """
47
- logger.debug(f"generate ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ…์ŠคํŠธ: '{text}', ํŒŒ์ผ ์ˆ˜: {len(files_list)}, ๋ชจ๋ธ: '{model}'")
48
 
49
  try:
50
  # API ํ‚ค๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๋ถˆ๋Ÿฌ์˜ด
@@ -58,34 +44,50 @@ def generate(text, files_list, model="gemini-2.0-flash-exp-image-generation"):
58
  client = genai.Client(api_key=effective_api_key)
59
  logger.debug("Gemini ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ.")
60
 
61
- # ์—ฌ๋Ÿฌ ํŒŒ์ผ ์—…๋กœ๋“œ
62
  uploaded_files = []
63
- for file_path in files_list:
64
- if file_path and os.path.exists(file_path):
65
- uploaded_file = client.files.upload(file=file_path)
66
- uploaded_files.append(uploaded_file)
67
- logger.debug(f"ํŒŒ์ผ ์—…๋กœ๋“œ ์™„๋ฃŒ. URI: {uploaded_file.uri}, MIME ํƒ€์ž…: {uploaded_file.mime_type}")
68
- else:
69
- logger.warning(f"ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ None์ž…๋‹ˆ๋‹ค: {file_path}")
70
-
71
- if not uploaded_files:
72
- logger.error("์—…๋กœ๋“œํ•  ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค.")
73
- return None
74
-
75
- # ํŒŒํŠธ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ (๋ชจ๋“  ์ด๋ฏธ์ง€ + ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ)
76
  parts = []
77
- for uploaded_file in uploaded_files:
 
 
 
 
 
 
 
 
78
  parts.append(
79
  types.Part.from_uri(
80
- file_uri=uploaded_file.uri,
81
- mime_type=uploaded_file.mime_type,
82
  )
83
  )
84
-
85
- # ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ ์ถ”๊ฐ€
 
 
 
 
 
 
 
 
 
86
  parts.append(types.Part.from_text(text=text))
87
-
88
- # ์ปจํ…์ธ  ๊ฐ์ฒด ์ƒ์„ฑ
89
  contents = [
90
  types.Content(
91
  role="user",
@@ -133,7 +135,6 @@ def generate(text, files_list, model="gemini-2.0-flash-exp-image-generation"):
133
 
134
  logger.debug(f"Raw chunk: {chunk}")
135
 
136
- # ์—…๋กœ๋“œ๋œ ํŒŒ์ผ ์ •๋ณด ์ •๋ฆฌ
137
  del uploaded_files
138
  logger.debug("์—…๋กœ๋“œ๋œ ํŒŒ์ผ ์ •๋ณด ์‚ญ์ œ ์™„๋ฃŒ.")
139
  return temp_path
@@ -143,84 +144,43 @@ def generate(text, files_list, model="gemini-2.0-flash-exp-image-generation"):
143
  return None # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ None ๋ฐ˜ํ™˜
144
 
145
 
146
- def save_image_temp(image):
147
- """์ด๋ฏธ์ง€๋ฅผ ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜"""
148
- if image is None:
149
- return None
150
-
151
- with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
152
- temp_path = tmp.name
153
- if isinstance(image, Image.Image):
154
- if image.mode == "RGBA":
155
- # ์•ŒํŒŒ ์ฑ„๋„์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ
156
- image = image.convert("RGB")
157
- image.save(temp_path)
158
- else:
159
- logger.warning(f"์ง€์›๋˜์ง€ ์•Š๋Š” ์ด๋ฏธ์ง€ ํƒ€์ž…: {type(image)}")
160
- return None
161
-
162
- logger.debug(f"์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {temp_path}")
163
- return temp_path
164
-
165
-
166
- def process_with_background_and_style(main_image, background_image, style_image, prompt):
167
- """
168
- ์ฃผ ์ด๋ฏธ์ง€, ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€, ์Šคํƒ€์ผ ์ด๋ฏธ์ง€๋ฅผ ํ”„๋กฌํ”„ํŠธ์™€ ํ•จ๊ป˜ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜
169
-
170
- Args:
171
- main_image (PIL.Image): ์ฃผ ๋Œ€์ƒ ์ด๋ฏธ์ง€
172
- background_image (PIL.Image): ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€
173
- style_image (PIL.Image): ์Šคํƒ€์ผ ์ฐธ์กฐ ์ด๋ฏธ์ง€
174
- prompt (str): ์ด๋ฏธ์ง€ ํŽธ์ง‘ ํ”„๋กฌํ”„ํŠธ
175
-
176
- Returns:
177
- list: ์ฒ˜๋ฆฌ๋œ ์ด๋ฏธ์ง€ ๋ชฉ๋ก
178
- """
179
- logger.debug(f"process_with_background_and_style ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: '{prompt}'")
180
  try:
181
- # ๊ฐ ์ด๋ฏธ์ง€๋ฅผ ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ
182
- files_list = []
183
-
184
- # ์ฃผ ์ด๋ฏธ์ง€ ์ €์žฅ
185
- main_path = save_image_temp(main_image)
186
- if main_path:
187
- files_list.append(main_path)
188
-
189
- # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ €์žฅ (์žˆ๋Š” ๊ฒฝ์šฐ)
190
- if background_image is not None:
191
- bg_path = save_image_temp(background_image)
192
- if bg_path:
193
- files_list.append(bg_path)
194
-
195
- # ์Šคํƒ€์ผ ์ด๋ฏธ์ง€ ์ €์žฅ (์žˆ๋Š” ๊ฒฝ์šฐ)
196
- if style_image is not None:
197
- style_path = save_image_temp(style_image)
198
- if style_path:
199
- files_list.append(style_path)
200
-
201
- # ์ด๋ฏธ์ง€๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋Š” ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ
202
- if not files_list:
203
- logger.error("์ฒ˜๋ฆฌํ•  ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.")
204
- return []
205
-
206
- # ํ”„๋กฌํ”„ํŠธ ๋ณด๊ฐ• (๋ฐฐ๊ฒฝ ๋ฐ ์Šคํƒ€์ผ ๊ด€๋ จ ์ •๋ณด ์ถ”๊ฐ€)
207
- enhanced_prompt = prompt
208
- if background_image is not None and style_image is not None:
209
- enhanced_prompt = f"{prompt}. ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋Š” ์ฃผ ๋Œ€์ƒ ์ด๋ฏธ์ง€์ด๊ณ , ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋Š” ๋ฐฐ๊ฒฝ์œผ๋กœ ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”. ์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์Šคํƒ€์ผ์„ ์ ์šฉํ•ด์ฃผ์„ธ์š”."
210
- elif background_image is not None:
211
- enhanced_prompt = f"{prompt}. ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋Š” ์ฃผ ๋Œ€์ƒ ์ด๋ฏธ์ง€์ด๊ณ , ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋Š” ๋ฐฐ๊ฒฝ์œผ๋กœ ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”."
212
- elif style_image is not None:
213
- enhanced_prompt = f"{prompt}. ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋Š” ์ฃผ ๋Œ€์ƒ ์ด๋ฏธ์ง€์ด๊ณ , ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์Šคํƒ€์ผ์„ ์ ์šฉํ•ด์ฃผ์„ธ์š”."
214
-
215
- logger.debug(f"๋ณด๊ฐ•๋œ ํ”„๋กฌํ”„ํŠธ: {enhanced_prompt}")
216
  model = "gemini-2.0-flash-exp-image-generation"
217
 
218
- # Gemini API ํ˜ธ์ถœ
219
- result_path = generate(text=enhanced_prompt, files_list=files_list, model=model)
 
 
 
220
 
221
- if result_path:
222
- logger.debug(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ. ๊ฒฝ๋กœ: {result_path}")
223
- result_img = Image.open(result_path)
224
  if result_img.mode == "RGBA":
225
  result_img = result_img.convert("RGB")
226
  return [result_img]
@@ -229,7 +189,7 @@ def process_with_background_and_style(main_image, background_image, style_image,
229
  return [] # ์˜ค๋ฅ˜ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
230
 
231
  except Exception as e:
232
- logger.exception("process_with_background_and_style ํ•จ์ˆ˜์—์„œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
233
  return [] # ์˜ค๋ฅ˜ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
234
 
235
 
@@ -243,78 +203,46 @@ with gr.Blocks() as demo:
243
  </div>
244
  <div>
245
  <h1>Gemini๋ฅผ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ํŽธ์ง‘</h1>
246
- <p>๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€์™€ ์Šคํƒ€์ผ ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.</p>
247
  <p>Gemini API ํ‚ค๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜(GEMINI_API_KEY)๋กœ ์„ค์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.</p>
248
  </div>
249
  </div>
250
  """
251
  )
252
- gr.Markdown("์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ , ํŽธ์ง‘ํ•  ๋‚ด์šฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”. ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€์™€ ์Šคํƒ€์ผ ์ด๋ฏธ์ง€๋Š” ์„ ํƒ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.")
253
 
254
  with gr.Row():
255
  with gr.Column():
256
- # ์ž…๋ ฅ ์ปดํฌ๋„ŒํŠธ
257
- main_image_input = gr.Image(type="pil", label="์ฃผ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", image_mode="RGB")
258
- background_image_input = gr.Image(type="pil", label="๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ (์„ ํƒ์‚ฌํ•ญ)", image_mode="RGB")
259
- style_image_input = gr.Image(type="pil", label="์Šคํƒ€์ผ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ (์„ ํƒ์‚ฌํ•ญ)", image_mode="RGB")
260
-
261
  prompt_input = gr.Textbox(
262
- lines=3,
263
  placeholder="ํŽธ์ง‘ํ•  ๋‚ด์šฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”...",
264
  label="ํŽธ์ง‘ ํ”„๋กฌํ”„ํŠธ"
265
  )
266
-
267
- # ํ”„๋กฌํ”„ํŠธ ์˜ˆ์‹œ
268
- gr.Markdown("### ํ”„๋กฌํ”„ํŠธ ์˜ˆ์‹œ")
269
- gr.Markdown("- '์ฃผ ์ด๋ฏธ์ง€๋ฅผ ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์œ„์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฐฐ์น˜ํ•ด์ฃผ์„ธ์š”'")
270
- gr.Markdown("- '์ฃผ ์ด๋ฏธ์ง€๋ฅผ ์Šคํƒ€์ผ ์ด๋ฏธ์ง€์˜ ํ™”ํ’์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ์„ธ์š”'")
271
- gr.Markdown("- '์ฃผ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์„ ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋กœ ๋Œ€์ฒดํ•˜๊ณ , ์„ธ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์˜ ์ƒ‰๊ฐ์„ ์ ์šฉํ•ด์ฃผ์„ธ์š”'")
272
-
273
  submit_btn = gr.Button("์ด๋ฏธ์ง€ ํŽธ์ง‘ ์‹คํ–‰")
274
-
275
  with gr.Column():
276
- # ์ถœ๋ ฅ ์ปดํฌ๋„ŒํŠธ
277
  output_gallery = gr.Gallery(label="ํŽธ์ง‘ ๊ฒฐ๊ณผ")
278
- output_info = gr.Textbox(label="์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ์ •๋ณด", lines=2)
279
 
280
- # ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ ์—ฐ๊ฒฐ
281
  submit_btn.click(
282
- fn=process_with_background_and_style,
283
- inputs=[main_image_input, background_image_input, style_image_input, prompt_input],
284
- outputs=[output_gallery],
285
- ).then(
286
- lambda: "ํŽธ์ง‘์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”.",
287
- None,
288
- output_info
289
  )
290
 
291
- # ์˜ˆ์ œ ์ด๋ฏธ์ง€ ์ถ”๊ฐ€
292
- gr.Examples(
293
- examples=[
294
- ["example_main.jpg", "example_background.jpg", "example_style.jpg", "์ฃผ ์ด๋ฏธ์ง€์˜ ์ธ๋ฌผ์„ ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€์— ํ•ฉ์„ฑํ•˜๊ณ , ์Šคํƒ€์ผ ์ด๋ฏธ์ง€์˜ ํ™”ํ’์„ ์ ์šฉํ•ด์ฃผ์„ธ์š”"],
295
- ["example_main.jpg", None, "example_style.jpg", "์ด๋ฏธ์ง€๋ฅผ ์Šคํƒ€์ผ ์ด๋ฏธ์ง€์˜ ํ™”ํ’์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ์„ธ์š”"],
296
- ["example_main.jpg", "example_background.jpg", None, "์ฃผ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์„ ์ œ๊ฑฐํ•˜๊ณ  ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€ ์œ„์— ํ•ฉ์„ฑํ•ด์ฃผ์„ธ์š”"],
297
- ],
298
- inputs=[main_image_input, background_image_input, style_image_input, prompt_input],
299
- )
300
 
 
 
 
 
301
 
302
- # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰
303
- if __name__ == "__main__":
304
- # ์‹ค์ œ ์šด์˜์—์„œ๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ œ๊ฑฐ
305
- # ํ…Œ์ŠคํŠธ์šฉ ๋”๋ฏธ ์ด๋ฏธ์ง€ (์‹ค์ œ ์ด๋ฏธ์ง€๋กœ ๋Œ€์ฒด ๊ฐ€๋Šฅ)
306
- # dummy_image = Image.new("RGB", (100, 100), color="red")
307
- # dummy_bg = Image.new("RGB", (100, 100), color="blue")
308
- # dummy_style = Image.new("RGB", (100, 100), color="green")
309
- # dummy_prompt = "์ด๋ฏธ์ง€๋ฅผ ํ•ฉ์„ฑํ•ด์ค˜"
310
-
311
- # logger.info("process_with_background_and_style ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค...")
312
- # result = process_with_background_and_style(dummy_image, dummy_bg, dummy_style, dummy_prompt)
313
-
314
- # if result:
315
- # logger.info(f"์ง์ ‘ ํ˜ธ์ถœ ์„ฑ๊ณต. ๊ฒฐ๊ณผ: {result}")
316
- # else:
317
- # logger.error("์ง์ ‘ ํ˜ธ์ถœ ์‹คํŒจ.")
318
-
319
- # Gradio ์•ฑ ์‹คํ–‰
320
- demo.launch(share=True)
 
9
  import mimetypes
10
  import logging
11
 
12
+ from google import genai
13
+ from google.genai import types
14
 
15
  # .env ํŒŒ์ผ์— ์ €์žฅ๋œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋กœ๋“œ (python-dotenv ์„ค์น˜ ํ•„์š”: pip install python-dotenv)
16
+ from dotenv import load_dotenv
17
+ load_dotenv()
 
 
 
18
 
19
  # ๋กœ๊น… ์„ค์ • (๋กœ๊ทธ ๋ ˆ๋ฒจ: DEBUG)
20
  logging.basicConfig(level=logging.DEBUG,
 
29
  logger.debug(f"ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ: {file_name}")
30
 
31
 
32
+ def generate(text, file_name, background_file=None, style_file=None, model="gemini-2.0-flash-exp-image-generation"):
33
+ logger.debug(f"generate ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ…์ŠคํŠธ: '{text}', ํŒŒ์ผ๋ช…: '{file_name}', ๋ชจ๋ธ: '{model}'")
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  try:
36
  # API ํ‚ค๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜์—์„œ ๋ถˆ๋Ÿฌ์˜ด
 
44
  client = genai.Client(api_key=effective_api_key)
45
  logger.debug("Gemini ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ.")
46
 
47
+ # ์›๋ณธ, ๋ฐฐ๊ฒฝ, ์Šคํƒ€์ผ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ๊ฐ ์—…๋กœ๋“œ (์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ)
48
  uploaded_files = []
49
+ uploaded_files.append(client.files.upload(file=file_name))
50
+ logger.debug(f"์›๋ณธ ํŒŒ์ผ ์—…๋กœ๋“œ ์™„๋ฃŒ. URI: {uploaded_files[0].uri}, MIME ํƒ€์ž…: {uploaded_files[0].mime_type}")
51
+
52
+ if background_file is not None:
53
+ bg_file = client.files.upload(file=background_file)
54
+ uploaded_files.append(bg_file)
55
+ logger.debug(f"๋ฐฐ๊ฒฝ ํŒŒ์ผ ์—…๋กœ๋“œ ์™„๋ฃŒ. URI: {bg_file.uri}, MIME ํƒ€์ž…: {bg_file.mime_type}")
56
+ if style_file is not None:
57
+ style_uploaded = client.files.upload(file=style_file)
58
+ uploaded_files.append(style_uploaded)
59
+ logger.debug(f"์Šคํƒ€์ผ ํŒŒ์ผ ์—…๋กœ๋“œ ์™„๋ฃŒ. URI: {style_uploaded.uri}, MIME ํƒ€์ž…: {style_uploaded.mime_type}")
60
+
61
+ # ์ปจํ…์ธ  ๊ฐ์ฒด ์ƒ์„ฑ: ์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€๋“ค์„ ์ˆœ์„œ๋Œ€๋กœ(์›๋ณธ, ๋ฐฐ๊ฒฝ, ์Šคํƒ€์ผ) ์ถ”๊ฐ€ํ•˜๊ณ  ๋งˆ์ง€๋ง‰์— ํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ ์ถ”๊ฐ€
62
  parts = []
63
+ # ์›๋ณธ ์ด๋ฏธ์ง€ ํŒŒํŠธ
64
+ parts.append(
65
+ types.Part.from_uri(
66
+ file_uri=uploaded_files[0].uri,
67
+ mime_type=uploaded_files[0].mime_type,
68
+ )
69
+ )
70
+ # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ํŒŒํŠธ (์กด์žฌ ์‹œ)
71
+ if background_file is not None:
72
  parts.append(
73
  types.Part.from_uri(
74
+ file_uri=uploaded_files[1].uri,
75
+ mime_type=uploaded_files[1].mime_type,
76
  )
77
  )
78
+ # ์Šคํƒ€์ผ ์ด๋ฏธ์ง€ ํŒŒํŠธ (์กด์žฌ ์‹œ)
79
+ if style_file is not None:
80
+ # ๋ฐฐ๊ฒฝ์ด ์—†๋Š” ๊ฒฝ์šฐ uploaded_files[1]๊ฐ€ ์Šคํƒ€์ผ ์ด๋ฏธ์ง€๊ฐ€ ๋จ์— ์ฃผ์˜
81
+ style_index = 2 if background_file is not None else 1
82
+ parts.append(
83
+ types.Part.from_uri(
84
+ file_uri=uploaded_files[style_index].uri,
85
+ mime_type=uploaded_files[style_index].mime_type,
86
+ )
87
+ )
88
+ # ๋งˆ์ง€๋ง‰์œผ๋กœ ํ…์ŠคํŠธ ํŒŒํŠธ ์ถ”๊ฐ€
89
  parts.append(types.Part.from_text(text=text))
90
+
 
91
  contents = [
92
  types.Content(
93
  role="user",
 
135
 
136
  logger.debug(f"Raw chunk: {chunk}")
137
 
 
138
  del uploaded_files
139
  logger.debug("์—…๋กœ๋“œ๋œ ํŒŒ์ผ ์ •๋ณด ์‚ญ์ œ ์™„๋ฃŒ.")
140
  return temp_path
 
144
  return None # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ None ๋ฐ˜ํ™˜
145
 
146
 
147
+ def process_image_and_prompt(original_pil, prompt, background_pil=None, style_pil=None):
148
+ logger.debug(f"process_image_and_prompt ํ•จ์ˆ˜ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: '{prompt}'")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  try:
150
+ # ์›๋ณธ ์ด๋ฏธ์ง€ ์ €์žฅ
151
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
152
+ original_path = tmp.name
153
+ original_pil.save(original_path)
154
+ logger.debug(f"์›๋ณธ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {original_path}")
155
+
156
+ # ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ €์žฅ (์ œ๊ณต๋œ ๊ฒฝ์šฐ)
157
+ background_path = None
158
+ if background_pil is not None:
159
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_bg:
160
+ background_path = tmp_bg.name
161
+ background_pil.save(background_path)
162
+ logger.debug(f"๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {background_path}")
163
+
164
+ # ์Šคํƒ€์ผ ์ด๋ฏธ์ง€ ์ €์žฅ (์ œ๊ณต๋œ ๊ฒฝ์šฐ)
165
+ style_path = None
166
+ if style_pil is not None:
167
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_style:
168
+ style_path = tmp_style.name
169
+ style_pil.save(style_path)
170
+ logger.debug(f"์Šคํƒ€์ผ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ: {style_path}")
171
+
172
+ input_text = prompt
 
 
 
 
 
 
 
 
 
 
 
 
173
  model = "gemini-2.0-flash-exp-image-generation"
174
 
175
+ gemma_edited_image_path = generate(text=input_text,
176
+ file_name=original_path,
177
+ background_file=background_path,
178
+ style_file=style_path,
179
+ model=model)
180
 
181
+ if gemma_edited_image_path:
182
+ logger.debug(f"์ด๋ฏธ์ง€ ์ƒ์„ฑ ์™„๋ฃŒ. ๊ฒฝ๋กœ: {gemma_edited_image_path}")
183
+ result_img = Image.open(gemma_edited_image_path)
184
  if result_img.mode == "RGBA":
185
  result_img = result_img.convert("RGB")
186
  return [result_img]
 
189
  return [] # ์˜ค๋ฅ˜ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
190
 
191
  except Exception as e:
192
+ logger.exception("process_image_and_prompt ํ•จ์ˆ˜์—์„œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ:")
193
  return [] # ์˜ค๋ฅ˜ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜
194
 
195
 
 
203
  </div>
204
  <div>
205
  <h1>Gemini๋ฅผ ์ด์šฉํ•œ ์ด๋ฏธ์ง€ ํŽธ์ง‘</h1>
 
206
  <p>Gemini API ํ‚ค๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜(GEMINI_API_KEY)๋กœ ์„ค์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.</p>
207
  </div>
208
  </div>
209
  """
210
  )
211
+ gr.Markdown("์›๋ณธ, ๋ฐฐ๊ฒฝ, ์Šคํƒ€์ผ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ , ํŽธ์ง‘ํ•  ๋‚ด์šฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”.")
212
 
213
  with gr.Row():
214
  with gr.Column():
215
+ original_input = gr.Image(type="pil", label="์›๋ณธ ์ด๋ฏธ์ง€", image_mode="RGBA")
216
+ background_input = gr.Image(type="pil", label="๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€", image_mode="RGBA")
217
+ style_input = gr.Image(type="pil", label="์Šคํƒ€์ผ ์ด๋ฏธ์ง€", image_mode="RGBA")
 
 
218
  prompt_input = gr.Textbox(
219
+ lines=2,
220
  placeholder="ํŽธ์ง‘ํ•  ๋‚ด์šฉ์„ ์ž…๋ ฅํ•˜์„ธ์š”...",
221
  label="ํŽธ์ง‘ ํ”„๋กฌํ”„ํŠธ"
222
  )
 
 
 
 
 
 
 
223
  submit_btn = gr.Button("์ด๋ฏธ์ง€ ํŽธ์ง‘ ์‹คํ–‰")
 
224
  with gr.Column():
 
225
  output_gallery = gr.Gallery(label="ํŽธ์ง‘ ๊ฒฐ๊ณผ")
 
226
 
 
227
  submit_btn.click(
228
+ fn=process_image_and_prompt,
229
+ inputs=[original_input, prompt_input, background_input, style_input],
230
+ outputs=output_gallery,
 
 
 
 
231
  )
232
 
233
+ # --- ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ---
234
+ # ํ…Œ์ŠคํŠธ์šฉ ๋”๋ฏธ ์ด๋ฏธ์ง€ (์‹ค์ œ ์ด๋ฏธ์ง€๋กœ ๋Œ€์ฒด ๊ฐ€๋Šฅ)
235
+ dummy_original = Image.new("RGBA", (100, 100), color="red")
236
+ dummy_background = Image.new("RGBA", (100, 100), color="green")
237
+ dummy_style = Image.new("RGBA", (100, 100), color="blue")
238
+ dummy_prompt = "์ด๋ฏธ์ง€ ํŽธ์ง‘: ์›๋ณธ์€ ๋นจ๊ฐ•, ๋ฐฐ๊ฒฝ์€ ์ดˆ๋ก, ์Šคํƒ€์ผ์€ ํŒŒ๋ž‘"
239
+
240
+ logger.info("process_image_and_prompt ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•ฉ๏ฟฝ๏ฟฝ๋‹ค...")
241
+ result = process_image_and_prompt(dummy_original, dummy_prompt, dummy_background, dummy_style)
242
 
243
+ if result:
244
+ logger.info(f"์ง์ ‘ ํ˜ธ์ถœ ์„ฑ๊ณต. ๊ฒฐ๊ณผ: {result}")
245
+ else:
246
+ logger.error("์ง์ ‘ ํ˜ธ์ถœ ์‹คํŒจ.")
247
 
248
+ demo.launch(share=True)