Kims12 commited on
Commit
f9fa24e
ยท
verified ยท
1 Parent(s): 2a5429b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +349 -33
app.py CHANGED
@@ -1,5 +1,6 @@
1
  import os
2
  import tempfile
 
3
  from PIL import Image
4
  import gradio as gr
5
  import logging
@@ -16,6 +17,80 @@ load_dotenv()
16
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
17
  logger = logging.getLogger(__name__)
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  def save_binary_file(file_name, data):
20
  with open(file_name, "wb") as f:
21
  f.write(data)
@@ -27,13 +102,12 @@ def translate_prompt_to_english(prompt):
27
  prompt = prompt.replace("#1", "IMAGE_TAG_ONE")
28
 
29
  try:
30
- api_key = os.environ.get("GEMINI_API_KEY")
31
- if not api_key:
32
  logger.error("Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
33
  prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
34
  return prompt
35
 
36
- client = genai.Client(api_key=api_key)
37
  translation_prompt = f"""
38
  Translate the following Korean text to English:
39
 
@@ -87,11 +161,10 @@ def preprocess_prompt(prompt, image1):
87
 
88
  def generate_with_images(prompt, images, variation_index=0):
89
  try:
90
- api_key = os.environ.get("GEMINI_API_KEY")
91
- if not api_key:
92
  return None, "API ๏ฟฝ๏ฟฝ๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
93
 
94
- client = genai.Client(api_key=api_key)
95
  logger.info(f"Gemini API ์š”์ฒญ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: {prompt}, ๋ณ€ํ˜• ์ธ๋ฑ์Šค: {variation_index}")
96
 
97
  variation_suffixes = [
@@ -225,35 +298,278 @@ def generate_multiple_images(image1, prompt, progress=gr.Progress()):
225
 
226
  return results[0], results[1], results[2], results[3], combined_status, combined_prompts
227
 
228
- # UI ๊ตฌ์„ฑ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  with gr.Blocks() as demo:
230
- with gr.Column():
231
- with gr.Group():
232
- with gr.Column():
233
- with gr.Row():
234
- image1_input = gr.Image(type="pil", label="์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", image_mode="RGB")
235
-
236
- prompt_input = gr.Textbox(
237
- lines=3,
238
- placeholder="ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”. '#1'์œผ๋กœ ์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.",
239
- label="ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ"
240
- )
241
-
242
- with gr.Row():
243
- submit_single_btn = gr.Button('์ด๋ฏธ์ง€ ์ƒ์„ฑ (1์žฅ)')
244
- submit_btn = gr.Button('์ด๋ฏธ์ง€ ์ƒ์„ฑ (4์žฅ)')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
- with gr.Column():
247
- with gr.Row():
248
- with gr.Column():
249
- output_image1 = gr.Image(label="์ด๋ฏธ์ง€ #1", type="filepath")
250
- output_image3 = gr.Image(label="์ด๋ฏธ์ง€ #3", type="filepath")
251
- with gr.Column():
252
- output_image2 = gr.Image(label="์ด๋ฏธ์ง€ #2", type="filepath")
253
- output_image4 = gr.Image(label="์ด๋ฏธ์ง€ #4", type="filepath")
254
-
255
- output_text = gr.Textbox(label="๊ฒฐ๊ณผ ์ •๋ณด", lines=2)
256
- prompt_display = gr.Textbox(label="์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ (์˜์–ด)", lines=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
 
258
  # ๋‹จ์ผ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
259
  submit_single_btn.click(
 
1
  import os
2
  import tempfile
3
+ import json
4
  from PIL import Image
5
  import gradio as gr
6
  import logging
 
17
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
18
  logger = logging.getLogger(__name__)
19
 
20
+ # Gemini API ํ‚ค ์„ค์ •
21
+ GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
22
+ genai.configure(api_key=GEMINI_API_KEY)
23
+
24
+ # ๋ฐฐ๊ฒฝ JSON ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • - ์ƒ๋Œ€ ๊ฒฝ๋กœ ์‚ฌ์šฉ
25
+ BACKGROUNDS_DIR = "./background"
26
+
27
+ # ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ
28
+ if not os.path.exists(BACKGROUNDS_DIR):
29
+ os.makedirs(BACKGROUNDS_DIR)
30
+ logger.info(f"๋ฐฐ๊ฒฝ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค: {BACKGROUNDS_DIR}")
31
+ else:
32
+ logger.info(f"๋ฐฐ๊ฒฝ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค: {BACKGROUNDS_DIR}")
33
+
34
+ # ๊ธฐ๋ณธ ๋ฐฐ๊ฒฝ ๋ฐ์ดํ„ฐ
35
+ SIMPLE_BACKGROUNDS = {"ํ™”์ดํŠธ ๋ฐฐ๊ฒฝ": "white background", "๋ธ”๋ž™ ๋ฐฐ๊ฒฝ": "black background", "๊ทธ๋ผ๋ฐ์ด์…˜ ๋ฐฐ๊ฒฝ": "gradient background"}
36
+ STUDIO_BACKGROUNDS = {"์ œํ’ˆ ์‚ฌ์ง„ ์ŠคํŠœ๋””์˜ค": "product photography studio", "๋ฏธ๋‹ˆ๋ฉ€ ์ŠคํŠœ๋””์˜ค": "minimal studio"}
37
+ NATURE_BACKGROUNDS = {"์—ด๋Œ€ ํ•ด๋ณ€": "tropical beach", "์ˆฒ์†": "forest", "์‚ฐ์•… ์ง€๋Œ€": "mountain landscape"}
38
+ INDOOR_BACKGROUNDS = {"๋ชจ๋˜ ๋ฆฌ๋น™๋ฃธ": "modern living room", "์„ธ๋ จ๋œ ์‚ฌ๋ฌด์‹ค": "elegant office", "๋Ÿญ์…”๋ฆฌ ํ˜ธํ…”": "luxury hotel"}
39
+ ABSTRACT_BACKGROUNDS = {"๋„ค์˜จ ์กฐ๋ช…": "neon lights", "์ถ”์ƒ์  ๊ทธ๋ผ๋ฐ์ด์…˜": "abstract gradient", "์šฐ์ฃผ ๋ฐฐ๊ฒฝ": "space background"}
40
+
41
+ # JSON ํŒŒ์ผ ๋กœ๋“œ ํ•จ์ˆ˜
42
+ def load_background_json(filename):
43
+ file_path = os.path.join(BACKGROUNDS_DIR, filename)
44
+ try:
45
+ with open(file_path, 'r', encoding='utf-8') as f:
46
+ data = json.load(f)
47
+ logger.info(f"{filename} ํŒŒ์ผ์„ ์„ฑ๊ณต์ ์œผ๋กœ ๋กœ๋“œํ–ˆ์Šต๋‹ˆ๋‹ค. {len(data)} ํ•ญ๋ชฉ ํฌํ•จ.")
48
+ return data
49
+ except FileNotFoundError:
50
+ logger.warning(f"๊ฒฝ๊ณ : {filename} ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.")
51
+ # ๊ธฐ๋ณธ๊ฐ’ ์ƒ์„ฑ - ํŒŒ์ผ์ด ์—†๋Š” ๊ฒฝ์šฐ ์ƒ์„ฑ
52
+ try:
53
+ with open(file_path, 'w', encoding='utf-8') as f:
54
+ if "simple" in filename:
55
+ json.dump(SIMPLE_BACKGROUNDS, f, ensure_ascii=False, indent=2)
56
+ elif "studio" in filename:
57
+ json.dump(STUDIO_BACKGROUNDS, f, ensure_ascii=False, indent=2)
58
+ elif "nature" in filename:
59
+ json.dump(NATURE_BACKGROUNDS, f, ensure_ascii=False, indent=2)
60
+ elif "indoor" in filename:
61
+ json.dump(INDOOR_BACKGROUNDS, f, ensure_ascii=False, indent=2)
62
+ elif "abstract" in filename:
63
+ json.dump(ABSTRACT_BACKGROUNDS, f, ensure_ascii=False, indent=2)
64
+ logger.info(f"{filename} ํŒŒ์ผ์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.")
65
+ except Exception as e:
66
+ logger.error(f"ํŒŒ์ผ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
67
+
68
+ # ๊ธฐ๋ณธ๊ฐ’ ๋ฐ˜ํ™˜
69
+ if "simple" in filename:
70
+ return SIMPLE_BACKGROUNDS
71
+ elif "studio" in filename:
72
+ return STUDIO_BACKGROUNDS
73
+ elif "nature" in filename:
74
+ return NATURE_BACKGROUNDS
75
+ elif "indoor" in filename:
76
+ return INDOOR_BACKGROUNDS
77
+ elif "abstract" in filename:
78
+ return ABSTRACT_BACKGROUNDS
79
+ return {}
80
+ except json.JSONDecodeError:
81
+ logger.warning(f"๊ฒฝ๊ณ : {filename} ํŒŒ์ผ์˜ JSON ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.")
82
+ return {}
83
+ except Exception as e:
84
+ logger.warning(f"๊ฒฝ๊ณ : {filename} ํŒŒ์ผ ๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}. ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.")
85
+ return {}
86
+
87
+ # ๋ฐฐ๊ฒฝ ๋ฐ์ดํ„ฐ ๋กœ๋“œ
88
+ SIMPLE_BACKGROUNDS = load_background_json("simple_backgrounds.json")
89
+ STUDIO_BACKGROUNDS = load_background_json("studio_backgrounds.json")
90
+ NATURE_BACKGROUNDS = load_background_json("nature_backgrounds.json")
91
+ INDOOR_BACKGROUNDS = load_background_json("indoor_backgrounds.json")
92
+ ABSTRACT_BACKGROUNDS = load_background_json("abstract_backgrounds.json")
93
+
94
  def save_binary_file(file_name, data):
95
  with open(file_name, "wb") as f:
96
  f.write(data)
 
102
  prompt = prompt.replace("#1", "IMAGE_TAG_ONE")
103
 
104
  try:
105
+ if not GEMINI_API_KEY:
 
106
  logger.error("Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
107
  prompt = prompt.replace("IMAGE_TAG_ONE", "#1")
108
  return prompt
109
 
110
+ client = genai.Client(api_key=GEMINI_API_KEY)
111
  translation_prompt = f"""
112
  Translate the following Korean text to English:
113
 
 
161
 
162
  def generate_with_images(prompt, images, variation_index=0):
163
  try:
164
+ if not GEMINI_API_KEY:
 
165
  return None, "API ๏ฟฝ๏ฟฝ๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
166
 
167
+ client = genai.Client(api_key=GEMINI_API_KEY)
168
  logger.info(f"Gemini API ์š”์ฒญ ์‹œ์ž‘ - ํ”„๋กฌํ”„ํŠธ: {prompt}, ๋ณ€ํ˜• ์ธ๋ฑ์Šค: {variation_index}")
169
 
170
  variation_suffixes = [
 
298
 
299
  return results[0], results[1], results[2], results[3], combined_status, combined_prompts
300
 
301
+ def generate_system_instruction():
302
+ return """๋‹น์‹ ์€ ์ƒํ’ˆ ์ด๋ฏธ์ง€์˜ ๋ฐฐ๊ฒฝ์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ๊ณ ํ’ˆ์งˆ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
303
+ ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ƒํ’ˆ๋ช…, ๋ฐฐ๊ฒฝ ์œ ํ˜•, ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ์„ ๋ฐ”ํƒ•์œผ๋กœ ๋ฏธ๋“œ์ €๋‹ˆ(Midjourney)์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”
304
+ ์ƒ์„ธํ•˜๊ณ  ์ „๋ฌธ์ ์ธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์˜์–ด๋กœ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
305
+ ๋‹ค์Œ ๊ฐ€์ด๋“œ๋ผ์ธ์„ ๋ฐ˜๋“œ์‹œ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค:
306
+ 1. ์ƒํ’ˆ์„ "#1"๋กœ ์ง€์ •ํ•˜์—ฌ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. (์˜ˆ: "skincare tube (#1)")
307
+ 2. *** ๋งค์šฐ ์ค‘์š”: ์ƒํ’ˆ์˜ ์›๋ž˜ ํŠน์„ฑ(๋””์ž์ธ, ์ƒ‰์ƒ, ํ˜•ํƒœ, ๋กœ๊ณ , ํŒจํ‚ค์ง€ ๋“ฑ)์€ ์–ด๋–ค ์ƒํ™ฉ์—์„œ๋„ ์ ˆ๋Œ€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ***
308
+ 3. *** ์ƒํ’ˆ์˜ ๋ณธ์งˆ์  ํŠน์„ฑ์€ ์œ ์ง€ํ•˜๋˜, ์ž์—ฐ์Šค๋Ÿฌ์šด ํ™˜๊ฒฝ ํ†ตํ•ฉ์„ ์œ„ํ•œ ์กฐ๋ช…๊ณผ ๊ทธ๋ฆผ์ž๋Š” ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค: ***
309
+ - ์ƒํ’ˆ ์ž์ฒด์˜ ์ƒ‰์ƒ, ๋””์ž์ธ, ํ˜•ํƒœ, ํ…์Šค์ฒ˜๋Š” ์ ˆ๋Œ€ ์ˆ˜์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
310
+ - ํ™˜๊ฒฝ๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์–ด์šธ๋ฆฌ๋Š” ๊ทธ๋ฆผ์ž, ์ฃผ๋ณ€ ์กฐ๋ช… ํšจ๊ณผ๋Š” ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.
311
+ - ์ƒํ’ˆ์— ๋ฌผ๋ฐฉ์šธ, ์‘์ถ•, ๊ธˆ, ์€๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€ ์š”์†Œ๋‚˜ ๋ฌผ๋ฆฌ์  ํšจ๊ณผ๋Š” ์ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
312
+ - ํ™˜๊ฒฝ์— ์–ด์šธ๋ฆฌ๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด ๋น› ๋ฐ˜์‚ฌ, ์ฃผ๋ณ€ ์กฐ๋ช…, ๊ทธ๋ฆผ์ž๋Š” ์‚ฌ์‹ค์  ํ†ตํ•ฉ๊ฐ์„ ์œ„ํ•ด ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
313
+ 4. ์ด๋ฏธ์ง€ ๋น„์œจ์€ ์ •ํ™•ํžˆ 1:1(์ •์‚ฌ๊ฐํ˜•) ํ˜•์‹์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กฌํ”„ํŠธ์— "square format", "1:1 ratio" ๋˜๋Š” "aspect ratio 1:1"์„ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
314
+ 5. ์ƒํ’ˆ์€ ๋ฐ˜๋“œ์‹œ ์ •์‚ฌ๊ฐํ˜• ๊ตฌ๋„์˜ ์ •์ค‘์•™์— ๋ฐฐ์น˜๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
315
+ 6. ์ƒํ’ˆ์„ ์ด๋ฏธ์ง€์˜ ์ฃผ์š” ์ดˆ์ ์œผ๋กœ ๋ถ€๊ฐ์‹œํ‚ค๊ณ , ์ƒํ’ˆ์˜ ๋น„์œจ์ด ์ „์ฒด ์ด๋ฏธ์ง€์—์„œ ํฌ๊ฒŒ ์ฐจ์ง€ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
316
+ 7. ์ƒํ’ˆ ์ด๋ฏธ์ง€ ์ปท์•„์›ƒ(#1)์˜ ๊ธฐ๋ณธ ํ˜•ํƒœ์™€ ์ƒ‰์ƒ์€ ์œ ์ง€ํ•˜๋ฉด์„œ, ์„ ํƒํ•œ ํ™˜๊ฒฝ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ํ†ตํ•ฉ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
317
+ 8. ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ์ƒ์—…์  ์ด๋ฏธ์ง€๋ฅผ ์œ„ํ•œ ๋‹ค์Œ ํ™˜๊ฒฝ ์š”์†Œ๋“ค์„ ํฌํ•จํ•˜์„ธ์š”:
318
+ - ์ƒํ’ˆ๊ณผ ์–ด์šธ๋ฆฌ๋Š” ์ฃผ๋ณ€ ํ™˜๊ฒฝ/๋ฐฐ๊ฒฝ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ™”์žฅํ’ˆ ์ฃผ๋ณ€์— ๊ฝƒ์ด๋‚˜ ํ—ˆ๋ธŒ, ์Œ๋ฃŒ ์ œํ’ˆ ์˜†์— ๊ณผ์ผ, ์ „์ž์ œํ’ˆ ๊ทผ์ฒ˜์— ํ˜„๋Œ€์  ์†Œํ’ˆ ๋“ฑ.
319
+ - ํ™˜๊ฒฝ์˜ ์กฐ๋ช… ํšจ๊ณผ(๋ฆผ ๋ผ์ดํŠธ, ๋ฐฑ๋ผ์ดํŠธ, ์†Œํ”„ํŠธ๋ฐ•์Šค ๋“ฑ)๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
320
+ - ์ƒํ’ˆ์ด ํ™˜๊ฒฝ์— ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์กด์žฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋„๋ก ์ ์ ˆํ•œ ๊ทธ๋ฆผ์ž์™€ ๋น› ํ‘œํ˜„์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
321
+ - ์ƒํ’ˆ์˜ ์šฉ๋„๋‚˜ ์žฅ์ ์„ ๊ฐ„์ ‘์ ์œผ๋กœ ์•”์‹œํ•˜๋Š” ๋ฐฐ๊ฒฝ ์š”์†Œ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
322
+ - ํ”„๋กœํŽ˜์…”๋„ํ•œ ์ƒ์—… ์‚ฌ์ง„ ํšจ๊ณผ(์„ ํƒ์  ํ”ผ์‚ฌ๊ณ„ ์‹ฌ๋„, ์†Œํ”„ํŠธ ํฌ์ปค์Šค, ์ŠคํŠœ๋””์˜ค ์กฐ๋ช… ๋“ฑ)๋ฅผ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
323
+ 9. ํ”„๋กฌํ”„ํŠธ์— ๋‹ค์Œ ์š”์†Œ๋“ค์„ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จํ•˜์„ธ์š”:
324
+ - "highly detailed commercial photography"
325
+ - "award-winning product photography"
326
+ - "professional advertising imagery"
327
+ - "studio quality"
328
+ - "magazine advertisement quality"
329
+ 10. ๋ฐฐ๊ฒฝ ํ™˜๊ฒฝ ์š”์†Œ๋ฅผ ์ƒํ’ˆ ์นดํ…Œ๊ณ ๋ฆฌ์— ๋งž๊ฒŒ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค:
330
+ - ์Šคํ‚จ์ผ€์–ด ์ œํ’ˆ: ๊นจ๋—ํ•œ ์š•์‹ค ์„ ๋ฐ˜, ์šฐ์•„ํ•œ ํ™”์žฅ๋Œ€, ์ŠคํŒŒ ๊ฐ™์€ ํ™˜๊ฒฝ ๋“ฑ
331
+ - ์Œ๋ฃŒ ์ œํ’ˆ: ์„ธ๋ จ๋œ ํ…Œ์ด๋ธ”, ํŒŒํ‹ฐ ํ™˜๊ฒฝ, ์•ผ์™ธ ํ”ผํฌ๋‹‰ ์žฅ๋ฉด ๋“ฑ
332
+ - ์ „์ž ์ œํ’ˆ: ์„ธ๋ จ๋œ ์ž‘์—… ๊ณต๊ฐ„, ํ˜„๋Œ€์ ์ธ ๊ฑฐ์‹ค, ๋ฏธ๋‹ˆ๋ฉ€ํ•œ ์ฑ…์ƒ ๋“ฑ
333
+ - ํŒจ์…˜/์˜๋ฅ˜: ์„ธ๋ จ๋œ ์‡ผ๋ฃธ, ๋„์‹œ ๊ฑฐ๋ฆฌ, ์—˜๋ ˆ๊ฐ•์Šคํ•œ ๋ผ์ดํ”„์Šคํƒ€์ผ ํ™˜๊ฒฝ ๋“ฑ
334
+ - ์‹ํ’ˆ ์ œํ’ˆ: ๊น”๋”ํ•œ ์ฃผ๋ฐฉ, ์‹ํƒ, ์š”๋ฆฌ ํ™˜๊ฒฝ ๋“ฑ
335
+ 11. ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ๊ตฌ์ฒด์ ์ธ ๋ฐฐ๊ฒฝ๊ณผ ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ์„ ์ •ํ™•ํžˆ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.
336
+ 12. ํ”„๋กฌํ”„ํŠธ๋Š” ๋ฏธ๋“œ์ €๋‹ˆ AI์— ์ตœ์ ํ™”๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
337
+ 13. ํ”„๋กฌํ”„ํŠธ ๋์— "--ar 1:1 --s 750 --q 2" ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฏธ๋“œ์ €๋‹ˆ์—์„œ ๊ณ ํ’ˆ์งˆ ์ •์‚ฌ๊ฐํ˜• ๋น„์œจ์„ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.
338
+ ์ถœ๋ ฅ ํ˜•์‹์€ ์˜์–ด๋กœ ๋œ ๋‹จ์ผ ๋‹จ๋ฝ์˜ ์ƒ์„ธํ•œ ํ”„๋กฌํ”„ํŠธ์—ฌ์•ผ ํ•˜๋ฉฐ, ๋์— ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
339
+ """
340
+
341
+ def generate_prompt_with_gemini(product_name, background_info, additional_info=""):
342
+ if not GEMINI_API_KEY:
343
+ return "Gemini API ํ‚ค๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ GEMINI_API_KEY๋ฅผ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ ์ฝ”๋“œ์— ์ง์ ‘ ์ž…๋ ฅํ•˜์„ธ์š”."
344
+ try:
345
+ prompt_request = f"""
346
+ ์ƒํ’ˆ๋ช…: {product_name}
347
+ ๋ฐฐ๊ฒฝ ์œ ํ˜•: {background_info.get('english', 'studio')}
348
+ ๋ฐฐ๊ฒฝ ์นดํ…Œ๊ณ ๋ฆฌ: {background_info.get('category', '')}
349
+ ๋ฐฐ๊ฒฝ ์ด๋ฆ„: {background_info.get('name', '')}
350
+ ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ: {additional_info}
351
+ ์ค‘์š” ์š”๊ตฌ์‚ฌํ•ญ:
352
+ 1. ์ƒํ’ˆ์ด ํฌ๊ฒŒ ๋ถ€๊ฐ๋˜๊ณ  ์ด๋ฏธ์ง€์—์„œ ์ค‘์‹ฌ์ ์ธ ์œ„์น˜๋ฅผ ์ฐจ์ง€ํ•˜๋„๋ก ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์„ธ์š”.
353
+ 2. ์ด๋ฏธ์ง€๋Š” ์ •ํ™•ํžˆ 1:1 ๋น„์œจ(์ •์‚ฌ๊ฐํ˜•)์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
354
+ 3. ์ƒํ’ˆ์€ ์ •์‚ฌ๊ฐํ˜• ํ”„๋ ˆ์ž„์˜ ์ •์ค‘์•™์— ์œ„์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
355
+ 4. ์ƒํ’ˆ์˜ ๋””์ž์ธ, ์ƒ‰์ƒ, ํ˜•ํƒœ, ๋กœ๊ณ  ๋“ฑ ๋ณธ์งˆ์  ํŠน์„ฑ์€ ์ ˆ๋Œ€ ์ˆ˜์ •ํ•˜์ง€ ๋งˆ์„ธ์š”.
356
+ 5. ํ™˜๊ฒฝ๊ณผ์˜ ์ž์—ฐ์Šค๋Ÿฌ์šด ํ†ตํ•ฉ์„ ์œ„ํ•œ ์กฐ๋ช… ํšจ๊ณผ์™€ ๊ทธ๋ฆผ์ž๋Š” ํฌํ•จํ•ด์ฃผ์„ธ์š”.
357
+ 6. ์ƒํ’ˆ์„ ๋” ๋‹๋ณด์ด๊ฒŒ ํ•˜๋Š” ๋ฐฐ๊ฒฝ ํ™˜๊ฒฝ์„ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”.
358
+ 7. ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ์ƒ์—… ๊ด‘๊ณ  ํ’ˆ์งˆ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋˜๋„๋ก ํ™˜๊ฒฝ ์„ค๋ช…์„ ํ•ด์ฃผ์„ธ์š”.
359
+ 8. ํ”„๋กฌํ”„ํŠธ ๋์— ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ "--ar 1:1 --s 750 --q 2"๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.
360
+ ํ•œ๊ตญ์–ด ์ž…๋ ฅ ๋‚ด์šฉ์„ ์˜์–ด๋กœ ์ ์ ˆํžˆ ๋ฒˆ์—ญํ•˜์—ฌ ๋ฐ˜์˜ํ•ด์ฃผ์„ธ์š”.
361
+ """
362
+ model = genai.GenerativeModel(
363
+ 'gemini-2.0-flash',
364
+ system_instruction=generate_system_instruction()
365
+ )
366
+ response = model.generate_content(
367
+ prompt_request,
368
+ generation_config=genai.types.GenerationConfig(
369
+ temperature=0.7,
370
+ top_p=0.95,
371
+ top_k=64,
372
+ max_output_tokens=1024,
373
+ )
374
+ )
375
+ response_text = response.text.strip()
376
+ if "--ar 1:1" not in response_text:
377
+ response_text = response_text.rstrip(".") + ". --ar 1:1 --s 750 --q 2"
378
+
379
+ # ๋ฏธ๋“œ์ €๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ ์ œ๊ฑฐ (Gemini API์™€๋Š” ๋‹ฌ๋ฆฌ ๋ถˆํ•„์š”ํ•˜๋ฏ€๋กœ)
380
+ response_text = response_text.replace(" --ar 1:1 --s 750 --q 2", "")
381
+
382
+ return response_text
383
+ except Exception as e:
384
+ return f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
385
+
386
+ # ์„ ํƒ๋œ ๋ฐฐ๊ฒฝ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
387
+ def get_selected_background_info(bg_type, simple, studio, nature, indoor, abstract):
388
+ if bg_type == "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ":
389
+ return {
390
+ "category": "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ",
391
+ "name": simple,
392
+ "english": SIMPLE_BACKGROUNDS.get(simple, "white background")
393
+ }
394
+ elif bg_type == "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ":
395
+ return {
396
+ "category": "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ",
397
+ "name": studio,
398
+ "english": STUDIO_BACKGROUNDS.get(studio, "product photography studio")
399
+ }
400
+ elif bg_type == "์ž์—ฐ ํ™˜๊ฒฝ":
401
+ return {
402
+ "category": "์ž์—ฐ ํ™˜๊ฒฝ",
403
+ "name": nature,
404
+ "english": NATURE_BACKGROUNDS.get(nature, "natural environment")
405
+ }
406
+ elif bg_type == "์‹ค๋‚ด ํ™˜๊ฒฝ":
407
+ return {
408
+ "category": "์‹ค๋‚ด ํ™˜๊ฒฝ",
409
+ "name": indoor,
410
+ "english": INDOOR_BACKGROUNDS.get(indoor, "indoor environment")
411
+ }
412
+ elif bg_type == "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ":
413
+ return {
414
+ "category": "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ",
415
+ "name": abstract,
416
+ "english": ABSTRACT_BACKGROUNDS.get(abstract, "abstract background")
417
+ }
418
+ else:
419
+ return {
420
+ "category": "๊ธฐ๋ณธ ๋ฐฐ๊ฒฝ",
421
+ "name": "ํ™”์ดํŠธ ๋ฐฐ๊ฒฝ",
422
+ "english": "white background"
423
+ }
424
+
425
+ # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ํ•จ์ˆ˜
426
+ def create_prompt(image, bg_type, simple, studio, nature, indoor, abstract, product_text, additional_text):
427
+ if image is None:
428
+ return "์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•ด์ฃผ์„ธ์š”."
429
+
430
+ product_text = product_text.strip() or "์ œํ’ˆ"
431
+
432
+ # ๋ฐฐ๊ฒฝ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
433
+ background_info = get_selected_background_info(bg_type, simple, studio, nature, indoor, abstract)
434
+
435
+ try:
436
+ prompt = generate_prompt_with_gemini(product_text, background_info, additional_text)
437
+ return prompt
438
+ except Exception as e:
439
+ error_msg = f"ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
440
+ return error_msg
441
+
442
+ with gr.Blocks() as demo: ๋ถ€๋ถ„๋ถ€ํ„ฐ ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค:
443
+ python๋ณต์‚ฌ# UI ๊ตฌ์„ฑ
444
  with gr.Blocks() as demo:
445
+ with gr.Row():
446
+ with gr.Column():
447
+ # ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์„น์…˜
448
+ gr.Markdown("## ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ")
449
+ with gr.Row():
450
+ image1_input = gr.Image(type="pil", label="์ด๋ฏธ์ง€ ์—…๋กœ๋“œ", image_mode="RGB")
451
+
452
+ # ์ œํ’ˆ๋ช… ์ž…๋ ฅ ์„น์…˜
453
+ gr.Markdown("## ์ œํ’ˆ ์ •๋ณด")
454
+ product_name = gr.Textbox(label="์ œํ’ˆ๋ช… (ํ•œ๊ตญ์–ด ์ž…๋ ฅ)", placeholder="์˜ˆ: ์Šคํ‚จ์ผ€์–ด ํŠœ๋ธŒ, ํ…€๋ธ”๋Ÿฌ ๋“ฑ")
455
+
456
+ # ๋ฐฐ๊ฒฝ ์œ ํ˜• ์„น์…˜
457
+ gr.Markdown("## ๏ฟฝ๏ฟฝ๊ฒฝ ์„ค์ •")
458
+ background_type = gr.Radio(
459
+ choices=["์‹ฌํ”Œ ๋ฐฐ๊ฒฝ", "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ", "์ž์—ฐ ํ™˜๊ฒฝ", "์‹ค๋‚ด ํ™˜๊ฒฝ", "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ"],
460
+ label="๋ฐฐ๊ฒฝ ์œ ํ˜•",
461
+ value="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ"
462
+ )
463
+
464
+ # ๊ฐ ๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋งž๋Š” ๋“œ๋กญ๋‹ค์šด ์ปดํฌ๋„ŒํŠธ๋“ค
465
+ simple_dropdown = gr.Dropdown(
466
+ choices=list(SIMPLE_BACKGROUNDS.keys()),
467
+ value=list(SIMPLE_BACKGROUNDS.keys())[0] if SIMPLE_BACKGROUNDS else None,
468
+ label="์‹ฌํ”Œ ๋ฐฐ๊ฒฝ ์„ ํƒ",
469
+ visible=True,
470
+ interactive=True
471
+ )
472
+
473
+ studio_dropdown = gr.Dropdown(
474
+ choices=list(STUDIO_BACKGROUNDS.keys()),
475
+ value=list(STUDIO_BACKGROUNDS.keys())[0] if STUDIO_BACKGROUNDS else None,
476
+ label="์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ ์„ ํƒ",
477
+ visible=False,
478
+ interactive=True
479
+ )
480
+
481
+ nature_dropdown = gr.Dropdown(
482
+ choices=list(NATURE_BACKGROUNDS.keys()),
483
+ value=list(NATURE_BACKGROUNDS.keys())[0] if NATURE_BACKGROUNDS else None,
484
+ label="์ž์—ฐ ํ™˜๊ฒฝ ์„ ํƒ",
485
+ visible=False,
486
+ interactive=True
487
+ )
488
+
489
+ indoor_dropdown = gr.Dropdown(
490
+ choices=list(INDOOR_BACKGROUNDS.keys()),
491
+ value=list(INDOOR_BACKGROUNDS.keys())[0] if INDOOR_BACKGROUNDS else None,
492
+ label="์‹ค๋‚ด ํ™˜๊ฒฝ ์„ ํƒ",
493
+ visible=False,
494
+ interactive=True
495
+ )
496
+
497
+ abstract_dropdown = gr.Dropdown(
498
+ choices=list(ABSTRACT_BACKGROUNDS.keys()),
499
+ value=list(ABSTRACT_BACKGROUNDS.keys())[0] if ABSTRACT_BACKGROUNDS else None,
500
+ label="์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ ์„ ํƒ",
501
+ visible=False,
502
+ interactive=True
503
+ )
504
+
505
+ # ์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ
506
+ additional_info = gr.Textbox(
507
+ label="์ถ”๊ฐ€ ์š”์ฒญ์‚ฌํ•ญ (์„ ํƒ์‚ฌํ•ญ)",
508
+ placeholder="์˜ˆ: ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ๋А๋‚Œ, ๋ฐ์€ ์กฐ๋ช…, ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ณด์กฐ์ ์ธ ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š” ๋“ฑ",
509
+ lines=2
510
+ )
511
+
512
+ # ํ”„๋กฌํ”„ํŠธ ์ž…๋ ฅ & ์ƒ์„ฑ ์„น์…˜
513
+ gr.Markdown("## ํ”„๋กฌํ”„ํŠธ ์„ค์ •")
514
+
515
+ generate_prompt_btn = gr.Button("ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ")
516
+
517
+ prompt_input = gr.Textbox(
518
+ lines=3,
519
+ placeholder="์—ฌ๊ธฐ์— ํ”„๋กฌํ”„ํŠธ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ˆ˜๋™์œผ๋กœ ์ˆ˜์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. '#1'์œผ๋กœ ์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.",
520
+ label="์ƒ์„ฑ๋œ ํ”„๋กฌํ”„ํŠธ"
521
+ )
522
 
523
+ with gr.Row():
524
+ submit_single_btn = gr.Button('์ด๋ฏธ์ง€ ์ƒ์„ฑ (1์žฅ)')
525
+ submit_btn = gr.Button('์ด๋ฏธ์ง€ ์ƒ์„ฑ (4์žฅ)')
526
+
527
+ with gr.Column():
528
+ gr.Markdown("## ์ƒ์„ฑ๋œ ์ด๋ฏธ์ง€")
529
+ with gr.Row():
530
+ with gr.Column():
531
+ output_image1 = gr.Image(label="์ด๋ฏธ์ง€ #1", type="filepath")
532
+ output_image3 = gr.Image(label="์ด๋ฏธ์ง€ #3", type="filepath")
533
+ with gr.Column():
534
+ output_image2 = gr.Image(label="์ด๋ฏธ์ง€ #2", type="filepath")
535
+ output_image4 = gr.Image(label="์ด๋ฏธ์ง€ #4", type="filepath")
536
+
537
+ output_text = gr.Textbox(label="๊ฒฐ๊ณผ ์ •๋ณด", lines=2)
538
+ prompt_display = gr.Textbox(label="์‚ฌ์šฉ๋œ ํ”„๋กฌํ”„ํŠธ (์˜์–ด)", lines=2)
539
+
540
+ # ๋ฐฐ๊ฒฝ ์œ ํ˜•์— ๋”ฐ๋ผ ๋“œ๋กญ๋‹ค์šด ํ‘œ์‹œ ์—…๋ฐ์ดํŠธ
541
+ def update_dropdowns(bg_type):
542
+ return {
543
+ simple_dropdown: gr.update(visible=(bg_type == "์‹ฌํ”Œ ๋ฐฐ๊ฒฝ")),
544
+ studio_dropdown: gr.update(visible=(bg_type == "์ŠคํŠœ๋””์˜ค ๋ฐฐ๊ฒฝ")),
545
+ nature_dropdown: gr.update(visible=(bg_type == "์ž์—ฐ ํ™˜๊ฒฝ")),
546
+ indoor_dropdown: gr.update(visible=(bg_type == "์‹ค๋‚ด ํ™˜๊ฒฝ")),
547
+ abstract_dropdown: gr.update(visible=(bg_type == "์ถ”์ƒ/ํŠน์ˆ˜ ๋ฐฐ๊ฒฝ"))
548
+ }
549
+
550
+ # ๋ฐฐ๊ฒฝ ์œ ํ˜• ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
551
+ background_type.change(
552
+ fn=update_dropdowns,
553
+ inputs=[background_type],
554
+ outputs=[simple_dropdown, studio_dropdown, nature_dropdown, indoor_dropdown, abstract_dropdown]
555
+ )
556
+
557
+ # ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์ด๋ฒคํŠธ
558
+ generate_prompt_btn.click(
559
+ fn=create_prompt,
560
+ inputs=[
561
+ image1_input,
562
+ background_type,
563
+ simple_dropdown,
564
+ studio_dropdown,
565
+ nature_dropdown,
566
+ indoor_dropdown,
567
+ abstract_dropdown,
568
+ product_name,
569
+ additional_info
570
+ ],
571
+ outputs=[prompt_input]
572
+ )
573
 
574
  # ๋‹จ์ผ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
575
  submit_single_btn.click(