Kims12 commited on
Commit
993c58c
ยท
verified ยท
1 Parent(s): e3f9d48

Update app.py

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