Update app.py
Browse files
app.py
CHANGED
@@ -6,9 +6,7 @@ import logging
|
|
6 |
import re
|
7 |
import time
|
8 |
import json
|
9 |
-
|
10 |
-
from google import genai
|
11 |
-
from google.genai import types
|
12 |
from dotenv import load_dotenv
|
13 |
|
14 |
load_dotenv()
|
@@ -19,7 +17,6 @@ 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"
|
@@ -29,87 +26,37 @@ if not os.path.exists(BACKGROUNDS_DIR):
|
|
29 |
os.makedirs(BACKGROUNDS_DIR)
|
30 |
logger.info(f"λ°°κ²½ λλ ν 리λ₯Ό μμ±νμ΅λλ€: {BACKGROUNDS_DIR}")
|
31 |
|
32 |
-
#
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
logger.info(f"{filename} νμΌμ μ±κ³΅μ μΌλ‘ λ‘λνμ΅λλ€. {len(data)} νλͺ© ν¬ν¨.")
|
39 |
-
return data
|
40 |
-
except FileNotFoundError:
|
41 |
-
logger.warning(f"κ²½κ³ : {filename} νμΌμ μ°Ύμ μ μμ΅λλ€. κΈ°λ³Έκ°μ μ¬μ©ν©λλ€.")
|
42 |
-
return {}
|
43 |
-
except json.JSONDecodeError:
|
44 |
-
logger.warning(f"κ²½κ³ : {filename} νμΌμ JSON νμμ΄ μ¬λ°λ₯΄μ§ μμ΅λλ€. κΈ°λ³Έκ°μ μ¬μ©ν©λλ€.")
|
45 |
-
return {}
|
46 |
-
except Exception as e:
|
47 |
-
logger.warning(f"κ²½κ³ : {filename} νμΌ λ‘λ μ€ μ€λ₯ λ°μ: {str(e)}. κΈ°λ³Έκ°μ μ¬μ©ν©λλ€.")
|
48 |
-
return {}
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
NATURE_BACKGROUNDS = load_background_json("nature_backgrounds.json")
|
54 |
-
INDOOR_BACKGROUNDS = load_background_json("indoor_backgrounds.json")
|
55 |
-
ABSTRACT_BACKGROUNDS = load_background_json("abstract_backgrounds.json")
|
56 |
-
|
57 |
-
# λ°°κ²½μ΄ λ‘λλμ§ μμ κ²½μ° κΈ°λ³Έκ° μ€μ
|
58 |
-
if not SIMPLE_BACKGROUNDS:
|
59 |
-
SIMPLE_BACKGROUNDS = {"νμ΄νΈ λ°°κ²½": "white background"}
|
60 |
-
if not STUDIO_BACKGROUNDS:
|
61 |
-
STUDIO_BACKGROUNDS = {"μ ν μ¬μ§ μ€νλμ€": "product photography studio"}
|
62 |
-
if not NATURE_BACKGROUNDS:
|
63 |
-
NATURE_BACKGROUNDS = {"μ΄λ ν΄λ³": "tropical beach"}
|
64 |
-
if not INDOOR_BACKGROUNDS:
|
65 |
-
INDOOR_BACKGROUNDS = {"λͺ¨λ 리λΉλ£Έ": "modern living room"}
|
66 |
-
if not ABSTRACT_BACKGROUNDS:
|
67 |
-
ABSTRACT_BACKGROUNDS = {"λ€μ¨ μ‘°λͺ
": "neon lights"}
|
68 |
|
69 |
def generate_system_instruction():
|
70 |
return """λΉμ μ μν μ΄λ―Έμ§μ λ°°κ²½μ λ³κ²½νκΈ° μν κ³ νμ§ ν둬ννΈλ₯Ό μμ±νλ μ λ¬Έκ°μ
λλ€.
|
71 |
-
μ¬μ©μκ° μ 곡νλ μνλͺ
, λ°°κ²½ μ ν, μΆκ° μμ²μ¬νμ λ°νμΌλ‘
|
72 |
-
μμΈνκ³ μ λ¬Έμ μΈ ν둬ννΈλ₯Ό μμ΄λ‘ μμ±ν΄μ£ΌμΈμ.
|
73 |
λ€μ κ°μ΄λλΌμΈμ λ°λμ λ°λΌμΌ ν©λλ€:
|
74 |
1. μνμ "#1"λ‘ μ§μ νμ¬ μ°Έμ‘°ν©λλ€. (μ: "skincare tube (#1)")
|
75 |
2. *** λ§€μ° μ€μ: μνμ μλ νΉμ±(λμμΈ, μμ, νν, λ‘κ³ , ν¨ν€μ§ λ±)μ μ΄λ€ μν©μμλ μ λ λ³κ²½νμ§ μμ΅λλ€. ***
|
76 |
-
3. *** μνμ λ³Έμ§μ νΉμ±μ μ μ§νλ, μμ°μ€λ¬μ΄ νκ²½ ν΅ν©μ μν μ‘°λͺ
κ³Ό κ·Έλ¦Όμλ
|
77 |
-
|
78 |
-
- νκ²½κ³Ό μμ°μ€λ½κ² μ΄μΈλ¦¬λ κ·Έλ¦Όμ, μ£Όλ³ μ‘°λͺ
ν¨κ³Όλ νμ©λ©λλ€.
|
79 |
-
- μνμ λ¬Όλ°©μΈ, μμΆ, κΈ, μκ³Ό κ°μ μΆκ° μμλ 물리μ ν¨κ³Όλ μ μ©νμ§ μμ΅λλ€.
|
80 |
-
- νκ²½μ μ΄μΈλ¦¬λ μμ°μ€λ¬μ΄ λΉ λ°μ¬, μ£Όλ³ μ‘°λͺ
, κ·Έλ¦Όμλ μ¬μ€μ ν΅ν©κ°μ μν΄ μ μ©ν μ μμ΅λλ€.
|
81 |
-
4. μ΄λ―Έμ§ λΉμ¨μ μ νν 1:1(μ μ¬κ°ν) νμμΌλ‘ μ§μ ν©λλ€. ν둬ννΈμ "square format", "1:1 ratio" λλ "aspect ratio 1:1"μ λͺ
μμ μΌλ‘ ν¬ν¨ν©λλ€.
|
82 |
5. μνμ λ°λμ μ μ¬κ°ν ꡬλμ μ μ€μμ λ°°μΉλμ΄μΌ ν©λλ€.
|
83 |
6. μνμ μ΄λ―Έμ§μ μ£Όμ μ΄μ μΌλ‘ λΆκ°μν€κ³ , μνμ λΉμ¨μ΄ μ 체 μ΄λ―Έμ§μμ ν¬κ² μ°¨μ§νλλ‘ ν©λλ€.
|
84 |
7. μν μ΄λ―Έμ§ μ»·μμ(#1)μ κΈ°λ³Έ ννμ μμμ μ μ§νλ©΄μ, μ νν νκ²½μ μμ°μ€λ½κ² ν΅ν©λλλ‘ ν©λλ€.
|
85 |
-
8. κ³ κΈμ€λ¬μ΄ μμ
μ μ΄λ―Έμ§λ₯Ό μν
|
86 |
-
- μνκ³Ό μ΄μΈλ¦¬λ μ£Όλ³ νκ²½/λ°°κ²½ μμλ₯Ό μΆκ°ν©λλ€. μλ₯Ό λ€μ΄, νμ₯ν μ£Όλ³μ κ½μ΄λ νλΈ, μλ£ μ ν μμ κ³ΌμΌ, μ μμ ν κ·Όμ²μ νλμ μν λ±.
|
87 |
-
- νκ²½μ μ‘°λͺ
ν¨κ³Ό(λ¦Ό λΌμ΄νΈ, λ°±λΌμ΄νΈ, μννΈλ°μ€ λ±)λ₯Ό μ€λͺ
ν©λλ€.
|
88 |
-
- μνμ΄ νκ²½μ μμ°μ€λ½κ² μ‘΄μ¬νλ κ²μ²λΌ 보μ΄λλ‘ μ μ ν κ·Έλ¦Όμμ λΉ ννμ ν¬ν¨ν©λλ€.
|
89 |
-
- μνμ μ©λλ μ₯μ μ κ°μ μ μΌλ‘ μμνλ λ°°κ²½ μμλ₯Ό ν¬ν¨ν©λλ€.
|
90 |
-
- νλ‘νμ
λν μμ
μ¬μ§ ν¨κ³Ό(μ νμ νΌμ¬κ³ μ¬λ, μννΈ ν¬μ»€μ€, μ€νλμ€ μ‘°λͺ
λ±)λ₯Ό λͺ
μν©λλ€.
|
91 |
9. ν둬ννΈμ λ€μ μμλ€μ λͺ
μμ μΌλ‘ ν¬ν¨νμΈμ:
|
92 |
- "highly detailed commercial photography"
|
93 |
- "award-winning product photography"
|
94 |
- "professional advertising imagery"
|
95 |
-
|
96 |
-
|
97 |
-
10. λ°°κ²½ νκ²½ μμλ₯Ό μν μΉ΄ν
κ³ λ¦¬μ λ§κ² μ νν©λλ€:
|
98 |
-
- μ€ν¨μΌμ΄ μ ν: κΉ¨λν μμ€ μ λ°, μ°μν νμ₯λ, μ€ν κ°μ νκ²½ λ±
|
99 |
-
- μλ£ μ ν: μΈλ ¨λ ν
μ΄λΈ, νν° νκ²½, μΌμΈ νΌν¬λ μ₯λ©΄ λ±
|
100 |
-
- μ μ μ ν: μΈλ ¨λ μμ
곡κ°, νλμ μΈ κ±°μ€, λ―Έλλ©ν μ±
μ λ±
|
101 |
-
- ν¨μ
/μλ₯: μΈλ ¨λ μΌλ£Έ, λμ 거리, μλ κ°μ€ν λΌμ΄νμ€νμΌ νκ²½ λ±
|
102 |
-
- μν μ ν: κΉλν μ£Όλ°©, μν, μ리 νκ²½ λ±
|
103 |
-
11. μ¬μ©μκ° μ 곡ν ꡬ체μ μΈ λ°°κ²½κ³Ό μΆκ° μμ²μ¬νμ μ νν λ°μν©λλ€.
|
104 |
-
12. ν둬ννΈλ λ―Έλμ λ AIμ μ΅μ νλμ΄μΌ ν©λλ€.
|
105 |
-
13. ν둬ννΈ λμ "--ar 1:1 --s 750 --q 2" νλΌλ―Έν°λ₯Ό μΆκ°νμ¬ λ―Έλμ λμμ κ³ νμ§ μ μ¬κ°ν λΉμ¨μ κ°μ ν©λλ€.
|
106 |
-
μΆλ ₯ νμμ μμ΄λ‘ λ λ¨μΌ λ¨λ½μ μμΈν ν둬ννΈμ¬μΌ νλ©°, λμ λ―Έλμ λ νλΌλ―Έν°κ° ν¬ν¨λμ΄μΌ ν©λλ€.
|
107 |
"""
|
108 |
|
109 |
-
def save_binary_file(file_name, data):
|
110 |
-
with open(file_name, "wb") as f:
|
111 |
-
f.write(data)
|
112 |
-
|
113 |
def generate_prompt_with_gemini(product_name, background_info, additional_info=""):
|
114 |
if not GEMINI_API_KEY:
|
115 |
return "Gemini API ν€κ° μ€μ λμ§ μμμ΅λλ€. νκ²½ λ³μ GEMINI_API_KEYλ₯Ό μ€μ νκ±°λ μ½λμ μ§μ μ
λ ₯νμΈμ."
|
@@ -128,25 +75,14 @@ def generate_prompt_with_gemini(product_name, background_info, additional_info="
|
|
128 |
5. νκ²½κ³Όμ μμ°μ€λ¬μ΄ ν΅ν©μ μν μ‘°λͺ
ν¨κ³Όμ κ·Έλ¦Όμλ ν¬ν¨ν΄μ£ΌμΈμ.
|
129 |
6. μνμ λ λ보μ΄κ² νλ λ°°κ²½ νκ²½μ μ€λͺ
ν΄μ£ΌμΈμ.
|
130 |
7. κ³ κΈμ€λ¬μ΄ μμ
κ΄κ³ νμ§μ μ΄λ―Έμ§κ° λλλ‘ νκ²½ μ€λͺ
μ ν΄μ£ΌμΈμ.
|
131 |
-
8. ν둬ννΈ λμ λ―Έλμ λ νλΌλ―Έν° "--ar 1:1 --s 750 --q 2"λ₯Ό μΆκ°ν΄μ£ΌμΈμ.
|
132 |
νκ΅μ΄ μ
λ ₯ λ΄μ©μ μμ΄λ‘ μ μ ν λ²μνμ¬ λ°μν΄μ£ΌμΈμ.
|
133 |
"""
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
response = model.generate_content(
|
139 |
-
prompt_request,
|
140 |
-
generation_config=genai.types.GenerationConfig(
|
141 |
-
temperature=0.7,
|
142 |
-
top_p=0.95,
|
143 |
-
top_k=64,
|
144 |
-
max_output_tokens=1024,
|
145 |
-
)
|
146 |
-
)
|
147 |
response_text = response.text.strip()
|
148 |
-
if "--ar 1:1" not in response_text:
|
149 |
-
response_text = response_text.rstrip(".") + ". --ar 1:1 --s 750 --q 2"
|
150 |
|
151 |
# λ―Έλμ λ νλΌλ―Έν° μ κ±°νκ³ λ°ν (μ΄λ―Έμ§ μμ±μμλ νμμμ)
|
152 |
cleaned_response = re.sub(r'--ar \d+:\d+|--s \d+|--q \d+', '', response_text).strip()
|
@@ -198,7 +134,7 @@ def generate_with_images(prompt, images, variation_index=0):
|
|
198 |
if not api_key:
|
199 |
return None, "API ν€κ° μ€μ λμ§ μμμ΅λλ€. νκ²½λ³μλ₯Ό νμΈν΄μ£ΌμΈμ."
|
200 |
|
201 |
-
|
202 |
logger.info(f"Gemini API μμ² μμ - ν둬ννΈ: {prompt}, λ³ν μΈλ±μ€: {variation_index}")
|
203 |
|
204 |
variation_suffixes = [
|
@@ -213,37 +149,44 @@ def generate_with_images(prompt, images, variation_index=0):
|
|
213 |
else:
|
214 |
prompt = prompt + " Do not add any text, watermarks, or labels to the image."
|
215 |
|
216 |
-
|
217 |
-
|
|
|
|
|
218 |
if img is not None:
|
219 |
-
|
220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
|
222 |
-
response =
|
223 |
-
model="gemini-2.0-flash-exp-image-generation",
|
224 |
-
contents=contents,
|
225 |
-
config=types.GenerateContentConfig(
|
226 |
-
response_modalities=['Text', 'Image'],
|
227 |
-
temperature=1,
|
228 |
-
top_p=0.95,
|
229 |
-
top_k=40,
|
230 |
-
max_output_tokens=8192
|
231 |
-
)
|
232 |
-
)
|
233 |
|
234 |
# μμ νμΌμ νμ JPG νμ₯μλ‘ μμ±
|
235 |
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
|
236 |
temp_path = tmp.name
|
237 |
result_text = ""
|
238 |
image_found = False
|
239 |
-
|
|
|
240 |
if hasattr(part, 'text') and part.text:
|
241 |
result_text += part.text
|
242 |
logger.info(f"μλ΅ ν
μ€νΈ: {part.text}")
|
243 |
elif hasattr(part, 'inline_data') and part.inline_data:
|
244 |
-
|
|
|
245 |
image_found = True
|
246 |
logger.info("μλ΅μμ μ΄λ―Έμ§ μΆμΆ μ±κ³΅")
|
|
|
247 |
if not image_found:
|
248 |
return None, f"APIμμ μ΄λ―Έμ§λ₯Ό μμ±νμ§ λͺ»νμ΅λλ€. μλ΅ ν
μ€νΈ: {result_text}"
|
249 |
|
|
|
6 |
import re
|
7 |
import time
|
8 |
import json
|
9 |
+
import google.generativeai as genai
|
|
|
|
|
10 |
from dotenv import load_dotenv
|
11 |
|
12 |
load_dotenv()
|
|
|
17 |
|
18 |
# Gemini API ν€ μ€μ
|
19 |
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
|
|
|
20 |
|
21 |
# λ°°κ²½ JSON νμΌ κ²½λ‘ μ€μ
|
22 |
BACKGROUNDS_DIR = "./background"
|
|
|
26 |
os.makedirs(BACKGROUNDS_DIR)
|
27 |
logger.info(f"λ°°κ²½ λλ ν 리λ₯Ό μμ±νμ΅λλ€: {BACKGROUNDS_DIR}")
|
28 |
|
29 |
+
# κΈ°λ³Έ λ°°κ²½ μμ±
|
30 |
+
SIMPLE_BACKGROUNDS = {"νμ΄νΈ λ°°κ²½": "white background", "λΈλ λ°°κ²½": "black background", "κ·Έλ μ΄ λ°°κ²½": "gray background"}
|
31 |
+
STUDIO_BACKGROUNDS = {"μ ν μ¬μ§ μ€νλμ€": "product photography studio", "λ―Έλλ© μ€νλμ€": "minimal studio setup"}
|
32 |
+
NATURE_BACKGROUNDS = {"μ΄λ ν΄λ³": "tropical beach", "μ²μ": "lush forest", "μ°μ
νκ²½": "mountain landscape"}
|
33 |
+
INDOOR_BACKGROUNDS = {"λͺ¨λ 리λΉλ£Έ": "modern living room", "λμ
리 μΌλ£Έ": "luxury showroom", "μΉ΄ν": "cozy cafe"}
|
34 |
+
ABSTRACT_BACKGROUNDS = {"λ€μ¨ μ‘°λͺ
": "neon lights", "κ·ΈλΌλ°μ΄μ
": "gradient background", "κΈ°ννμ ν¨ν΄": "geometric pattern"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
+
def save_binary_file(file_name, data):
|
37 |
+
with open(file_name, "wb") as f:
|
38 |
+
f.write(data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
|
40 |
def generate_system_instruction():
|
41 |
return """λΉμ μ μν μ΄λ―Έμ§μ λ°°κ²½μ λ³κ²½νκΈ° μν κ³ νμ§ ν둬ννΈλ₯Ό μμ±νλ μ λ¬Έκ°μ
λλ€.
|
42 |
+
μ¬μ©μκ° μ 곡νλ μνλͺ
, λ°°κ²½ μ ν, μΆκ° μμ²μ¬νμ λ°νμΌλ‘ κ³ νμ§ ν둬ννΈλ₯Ό μμ΄λ‘ μμ±ν΄μ£ΌμΈμ.
|
|
|
43 |
λ€μ κ°μ΄λλΌμΈμ λ°λμ λ°λΌμΌ ν©λλ€:
|
44 |
1. μνμ "#1"λ‘ μ§μ νμ¬ μ°Έμ‘°ν©λλ€. (μ: "skincare tube (#1)")
|
45 |
2. *** λ§€μ° μ€μ: μνμ μλ νΉμ±(λμμΈ, μμ, νν, λ‘κ³ , ν¨ν€μ§ λ±)μ μ΄λ€ μν©μμλ μ λ λ³κ²½νμ§ μμ΅λλ€. ***
|
46 |
+
3. *** μνμ λ³Έμ§μ νΉμ±μ μ μ§νλ, μμ°μ€λ¬μ΄ νκ²½ ν΅ν©μ μν μ‘°λͺ
κ³Ό κ·Έλ¦Όμλ νμ©ν©λλ€ ***
|
47 |
+
4. μ΄λ―Έμ§ λΉμ¨μ μ νν 1:1(μ μ¬κ°ν) νμμΌλ‘ μ§μ ν©λλ€.
|
|
|
|
|
|
|
|
|
48 |
5. μνμ λ°λμ μ μ¬κ°ν ꡬλμ μ μ€μμ λ°°μΉλμ΄μΌ ν©λλ€.
|
49 |
6. μνμ μ΄λ―Έμ§μ μ£Όμ μ΄μ μΌλ‘ λΆκ°μν€κ³ , μνμ λΉμ¨μ΄ μ 체 μ΄λ―Έμ§μμ ν¬κ² μ°¨μ§νλλ‘ ν©λλ€.
|
50 |
7. μν μ΄λ―Έμ§ μ»·μμ(#1)μ κΈ°λ³Έ ννμ μμμ μ μ§νλ©΄μ, μ νν νκ²½μ μμ°μ€λ½κ² ν΅ν©λλλ‘ ν©λλ€.
|
51 |
+
8. κ³ κΈμ€λ¬μ΄ μμ
μ μ΄λ―Έμ§λ₯Ό μν νκ²½ μμλ€μ ν¬ν¨νμΈμ.
|
|
|
|
|
|
|
|
|
|
|
52 |
9. ν둬ννΈμ λ€μ μμλ€μ λͺ
μμ μΌλ‘ ν¬ν¨νμΈμ:
|
53 |
- "highly detailed commercial photography"
|
54 |
- "award-winning product photography"
|
55 |
- "professional advertising imagery"
|
56 |
+
10. μ¬μ©μκ° μ 곡ν ꡬ체μ μΈ λ°°κ²½κ³Ό μΆκ° μμ²μ¬νμ μ νν λ°μν©λλ€.
|
57 |
+
μΆλ ₯ νμμ μμ΄λ‘ λ λ¨μΌ λ¨λ½μ μμΈν ν둬ννΈμ¬μΌ ν©λλ€.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
"""
|
59 |
|
|
|
|
|
|
|
|
|
60 |
def generate_prompt_with_gemini(product_name, background_info, additional_info=""):
|
61 |
if not GEMINI_API_KEY:
|
62 |
return "Gemini API ν€κ° μ€μ λμ§ μμμ΅λλ€. νκ²½ λ³μ GEMINI_API_KEYλ₯Ό μ€μ νκ±°λ μ½λμ μ§μ μ
λ ₯νμΈμ."
|
|
|
75 |
5. νκ²½κ³Όμ μμ°μ€λ¬μ΄ ν΅ν©μ μν μ‘°λͺ
ν¨κ³Όμ κ·Έλ¦Όμλ ν¬ν¨ν΄μ£ΌμΈμ.
|
76 |
6. μνμ λ λ보μ΄κ² νλ λ°°κ²½ νκ²½μ μ€λͺ
ν΄μ£ΌμΈμ.
|
77 |
7. κ³ κΈμ€λ¬μ΄ μμ
κ΄κ³ νμ§μ μ΄λ―Έμ§κ° λλλ‘ νκ²½ μ€λͺ
μ ν΄μ£ΌμΈμ.
|
|
|
78 |
νκ΅μ΄ μ
λ ₯ λ΄μ©μ μμ΄λ‘ μ μ ν λ²μνμ¬ λ°μν΄μ£ΌμΈμ.
|
79 |
"""
|
80 |
+
genai.configure(api_key=GEMINI_API_KEY)
|
81 |
+
|
82 |
+
model = genai.GenerativeModel('gemini-2.0-flash')
|
83 |
+
|
84 |
+
response = model.generate_content(prompt_request)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
response_text = response.text.strip()
|
|
|
|
|
86 |
|
87 |
# λ―Έλμ λ νλΌλ―Έν° μ κ±°νκ³ λ°ν (μ΄λ―Έμ§ μμ±μμλ νμμμ)
|
88 |
cleaned_response = re.sub(r'--ar \d+:\d+|--s \d+|--q \d+', '', response_text).strip()
|
|
|
134 |
if not api_key:
|
135 |
return None, "API ν€κ° μ€μ λμ§ μμμ΅λλ€. νκ²½λ³μλ₯Ό νμΈν΄μ£ΌμΈμ."
|
136 |
|
137 |
+
genai.configure(api_key=api_key)
|
138 |
logger.info(f"Gemini API μμ² μμ - ν둬ννΈ: {prompt}, λ³ν μΈλ±μ€: {variation_index}")
|
139 |
|
140 |
variation_suffixes = [
|
|
|
149 |
else:
|
150 |
prompt = prompt + " Do not add any text, watermarks, or labels to the image."
|
151 |
|
152 |
+
model = genai.GenerativeModel('gemini-1.5-flash')
|
153 |
+
|
154 |
+
parts = [prompt]
|
155 |
+
for img in images:
|
156 |
if img is not None:
|
157 |
+
if isinstance(img, str): # If it's a file path
|
158 |
+
with open(img, "rb") as f:
|
159 |
+
img_data = f.read()
|
160 |
+
parts.append({"mime_type": "image/jpeg", "data": img_data})
|
161 |
+
else: # If it's a PIL Image
|
162 |
+
img_bytes = tempfile.NamedTemporaryFile(suffix=".jpg", delete=False)
|
163 |
+
img.save(img_bytes, format="JPEG")
|
164 |
+
img_bytes.close()
|
165 |
+
|
166 |
+
with open(img_bytes.name, "rb") as f:
|
167 |
+
img_data = f.read()
|
168 |
+
|
169 |
+
parts.append({"mime_type": "image/jpeg", "data": img_data})
|
170 |
+
os.unlink(img_bytes.name) # Clean up temp file
|
171 |
|
172 |
+
response = model.generate_content(parts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
|
174 |
# μμ νμΌμ νμ JPG νμ₯μλ‘ μμ±
|
175 |
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
|
176 |
temp_path = tmp.name
|
177 |
result_text = ""
|
178 |
image_found = False
|
179 |
+
|
180 |
+
for part in response.parts:
|
181 |
if hasattr(part, 'text') and part.text:
|
182 |
result_text += part.text
|
183 |
logger.info(f"μλ΅ ν
μ€νΈ: {part.text}")
|
184 |
elif hasattr(part, 'inline_data') and part.inline_data:
|
185 |
+
img_data = part.inline_data.data
|
186 |
+
save_binary_file(temp_path, img_data)
|
187 |
image_found = True
|
188 |
logger.info("μλ΅μμ μ΄λ―Έμ§ μΆμΆ μ±κ³΅")
|
189 |
+
|
190 |
if not image_found:
|
191 |
return None, f"APIμμ μ΄λ―Έμ§λ₯Ό μμ±νμ§ λͺ»νμ΅λλ€. μλ΅ ν
μ€νΈ: {result_text}"
|
192 |
|