hansoneze commited on
Commit
4b969ec
·
1 Parent(s): 7de6fb0

Switch to Gemini + update requirements

Browse files
Files changed (1) hide show
  1. app.py +124 -60
app.py CHANGED
@@ -1,6 +1,7 @@
1
  import os
2
  import time
3
  from datetime import datetime
 
4
 
5
  from fastapi import FastAPI, UploadFile, Form
6
  from fastapi.responses import FileResponse, JSONResponse
@@ -13,9 +14,13 @@ import uvicorn
13
 
14
  from dotenv import load_dotenv
15
 
16
- # Load environment variables
17
  load_dotenv()
18
- print("Gemini API Key Loaded:", os.getenv("GEMINI_API_KEY") is not None)
 
 
 
 
19
 
20
  # ---------------------------
21
  # CONFIG
@@ -29,7 +34,7 @@ LIFETIME = 24 * 60 * 60 # 24 hours
29
  os.makedirs(UPLOAD_DIR, exist_ok=True)
30
  os.makedirs(RESULTS_DIR, exist_ok=True)
31
 
32
- # Gemini setup
33
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
34
  model = genai.GenerativeModel("gemini-1.5-flash")
35
 
@@ -48,55 +53,84 @@ def check_size(filepath):
48
  os.remove(filepath)
49
  raise ValueError(f"File too large! Max {MAX_SIZE_MB}MB allowed.")
50
 
51
- def process_image(input_img, bg_choice, bg_upload=None, brand_color="#FFFFFF", logo_upload=None, logo_opacity=80, logo_position="bottom-right"):
52
- """Main image processor with custom bg, brand color, and logo support"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  if input_img is None:
54
  return []
55
 
56
  temp_path = os.path.join(UPLOAD_DIR, f"upload_{int(time.time())}.png")
57
  input_img.save(temp_path)
58
 
59
- fg = remove(Image.open(temp_path).convert("RGBA"))
60
-
61
- # --- Background selection ---
62
- if bg_choice and bg_choice in os.listdir(BG_DIR):
63
- bg = Image.open(os.path.join(BG_DIR, bg_choice)).convert("RGBA").resize(fg.size)
64
- elif bg_choice == "Custom Upload" and bg_upload is not None:
65
- bg = bg_upload.convert("RGBA").resize(fg.size)
66
- elif bg_choice == "Solid Brand Color" and brand_color:
67
- bg = Image.new("RGBA", fg.size, brand_color)
68
  else:
69
- bg = Image.new("RGBA", fg.size, (255, 255, 255, 255))
 
 
 
 
70
 
 
71
  result = Image.alpha_composite(bg, fg)
72
 
73
- # --- Logo overlay ---
74
  if logo_upload is not None:
75
  logo = logo_upload.convert("RGBA")
76
- logo_size = int(result.width * 0.15)
77
- logo.thumbnail((logo_size, logo_size))
78
- alpha = logo.split()[3].point(lambda p: int(p * (logo_opacity / 100)))
 
 
79
  logo.putalpha(alpha)
80
 
81
- if logo_position == "top-left":
82
- pos = (20, 20)
83
- elif logo_position == "top-right":
84
- pos = (result.width - logo.width - 20, 20)
85
- elif logo_position == "bottom-left":
86
- pos = (20, result.height - logo.height - 20)
87
- elif logo_position == "center":
88
- pos = ((result.width - logo.width) // 2, (result.height - logo.height) // 2)
89
- else: # default bottom-right
90
- pos = (result.width - logo.width - 20, result.height - logo.height - 20)
91
-
92
- result.alpha_composite(logo, pos)
93
-
 
 
 
94
  timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
95
  result_path = os.path.join(RESULTS_DIR, f"result_{timestamp}.png")
96
  result.save(result_path)
97
  cleanup_old_files(RESULTS_DIR)
 
98
 
 
 
 
 
 
 
 
 
99
  return [result_path]
 
100
 
101
  def generate_caption(prompt="Promote my product"):
102
  try:
@@ -115,9 +149,10 @@ def generate_caption(prompt="Promote my product"):
115
  # ---------------------------
116
  app = FastAPI(title="SnapLift API")
117
 
 
118
  app.add_middleware(
119
  CORSMiddleware,
120
- allow_origins=["*"],
121
  allow_credentials=True,
122
  allow_methods=["*"],
123
  allow_headers=["*"],
@@ -129,8 +164,9 @@ async def process_image_api(file: UploadFile, bg_choice: str = Form(...)):
129
  input_path = os.path.join(UPLOAD_DIR, file.filename)
130
  with open(input_path, "wb") as f:
131
  f.write(await file.read())
132
- result_path = process_image(Image.open(input_path), bg_choice)
133
- return FileResponse(result_path[0])
 
134
  except Exception as e:
135
  return JSONResponse(content={"error": str(e)}, status_code=400)
136
 
@@ -146,50 +182,74 @@ with gr.Blocks(css="footer {display:none !important}") as demo:
146
  gr.Markdown("# ✨ SnapLift – AI Social Media Booster")
147
  gr.Markdown("Upload your product photo, replace background, and auto-generate marketing captions + hashtags!")
148
 
149
- # --- Image Editor ---
 
150
  with gr.Tab("📸 Image Editor"):
151
  with gr.Row():
152
  input_img = gr.Image(type="pil", label="Upload Main Photo")
153
 
154
  with gr.Column():
155
  bg_choices = gr.Dropdown(
156
- choices=os.listdir(BG_DIR) + ["Custom Upload", "Solid Brand Color"],
157
  value=os.listdir(BG_DIR)[0] if os.listdir(BG_DIR) else None,
158
  label="Choose Background"
159
  )
160
- bg_preview = gr.Image(label="Background Preview", type="filepath")
161
- bg_upload = gr.Image(type="pil", label="Upload Custom Background")
162
- brand_color = gr.ColorPicker(label="Pick Brand Colour", value="#FFFFFF")
163
-
164
- logo_upload = gr.Image(type="pil", label="Upload Brand Logo (Optional)")
165
- logo_opacity = gr.Slider(minimum=0, maximum=100, value=80, step=5, label="Logo Transparency (%)")
166
- logo_position = gr.Radio(
167
- choices=["top-left", "top-right", "bottom-left", "bottom-right", "center"],
168
- value="bottom-right",
169
- label="Logo Position"
170
- )
171
-
172
- def update_preview(bg_choice):
173
- return os.path.join(BG_DIR, bg_choice) if bg_choice in os.listdir(BG_DIR) else None
174
 
175
- bg_choices.change(fn=update_preview, inputs=bg_choices, outputs=bg_preview)
 
 
 
 
 
 
 
 
 
176
 
177
  btn = gr.Button("✨ Generate New Photo")
178
  output_imgs = gr.Gallery(label="Generated Image", elem_id="gallery", columns=1, rows=1)
 
179
  btn.click(
180
  fn=process_image,
181
- inputs=[input_img, bg_choices, bg_upload, brand_color, logo_upload, logo_opacity, logo_position],
182
  outputs=output_imgs
183
  )
184
 
185
- # --- Caption Generator ---
186
- with gr.Tab("✍️ Caption Generator"):
187
- prompt = gr.Textbox(label="Enter product/promotion text", value="Promote my skincare product")
188
- btn2 = gr.Button("💡 Suggest Captions + Hashtags")
189
- caption_box = gr.Textbox(label="Suggested Posts (multi-platform)", lines=12)
190
- btn2.click(fn=generate_caption, inputs=[prompt], outputs=[caption_box])
191
 
192
- # ---------------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  # START SERVER
194
  # ---------------------------
195
  if __name__ == "__main__":
@@ -200,3 +260,7 @@ if __name__ == "__main__":
200
 
201
  threading.Thread(target=run_gradio).start()
202
  uvicorn.run(app, host="0.0.0.0", port=8000)
 
 
 
 
 
1
  import os
2
  import time
3
  from datetime import datetime
4
+ from typing import List
5
 
6
  from fastapi import FastAPI, UploadFile, Form
7
  from fastapi.responses import FileResponse, JSONResponse
 
14
 
15
  from dotenv import load_dotenv
16
 
17
+ # Load environment variables from .env
18
  load_dotenv()
19
+
20
+ # Confirm API key is loaded
21
+ print("Gemini API Key Loaded:", os.getenv("GOOGLE_API_KEY") is not None)
22
+
23
+
24
 
25
  # ---------------------------
26
  # CONFIG
 
34
  os.makedirs(UPLOAD_DIR, exist_ok=True)
35
  os.makedirs(RESULTS_DIR, exist_ok=True)
36
 
37
+ # Gemini API key
38
  genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
39
  model = genai.GenerativeModel("gemini-1.5-flash")
40
 
 
53
  os.remove(filepath)
54
  raise ValueError(f"File too large! Max {MAX_SIZE_MB}MB allowed.")
55
 
56
+ def replace_background(input_path, bg_choice):
57
+ """Replace background with selected file"""
58
+ check_size(input_path)
59
+ input_img = Image.open(input_path).convert("RGBA")
60
+ fg = remove(input_img)
61
+
62
+ bg_path = os.path.join(BG_DIR, bg_choice)
63
+ bg = Image.open(bg_path).convert("RGBA").resize(fg.size)
64
+
65
+ result = Image.alpha_composite(bg, fg)
66
+ timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
67
+ result_path = os.path.join(RESULTS_DIR, f"result_{timestamp}.png")
68
+ result.save(result_path)
69
+ cleanup_old_files(RESULTS_DIR)
70
+ return result_path
71
+
72
+ def process_image(input_img, bg_choice, bg_upload, logo_upload, logo_transparency, logo_position, brand_color):
73
  if input_img is None:
74
  return []
75
 
76
  temp_path = os.path.join(UPLOAD_DIR, f"upload_{int(time.time())}.png")
77
  input_img.save(temp_path)
78
 
79
+ # Background selection
80
+ if bg_upload is not None:
81
+ bg = bg_upload.convert("RGBA").resize(input_img.size)
 
 
 
 
 
 
82
  else:
83
+ bg_path = os.path.join(BG_DIR, bg_choice)
84
+ bg = Image.open(bg_path).convert("RGBA").resize(input_img.size)
85
+
86
+ # Foreground (removed background)
87
+ fg = remove(input_img.convert("RGBA"))
88
 
89
+ # Merge main photo with background
90
  result = Image.alpha_composite(bg, fg)
91
 
92
+ # If logo uploaded
93
  if logo_upload is not None:
94
  logo = logo_upload.convert("RGBA")
95
+ # Resize logo (20% of image width)
96
+ scale = result.width // 5
97
+ logo.thumbnail((scale, scale))
98
+ # Apply transparency
99
+ alpha = logo.split()[3].point(lambda p: p * (logo_transparency / 100))
100
  logo.putalpha(alpha)
101
 
102
+ # Position logo
103
+ pos_map = {
104
+ "Top-Left": (10, 10),
105
+ "Top-Right": (result.width - logo.width - 10, 10),
106
+ "Bottom-Left": (10, result.height - logo.height - 10),
107
+ "Bottom-Right": (result.width - logo.width - 10, result.height - logo.height - 10),
108
+ "Center": ((result.width - logo.width) // 2, (result.height - logo.height) // 2),
109
+ }
110
+ result.paste(logo, pos_map[logo_position], logo)
111
+
112
+ # Apply brand colour tint
113
+ if brand_color:
114
+ tint = Image.new("RGBA", result.size, brand_color + "20") # ~12% opacity overlay
115
+ result = Image.alpha_composite(result, tint)
116
+
117
+ # Save result
118
  timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
119
  result_path = os.path.join(RESULTS_DIR, f"result_{timestamp}.png")
120
  result.save(result_path)
121
  cleanup_old_files(RESULTS_DIR)
122
+ return [result_path]
123
 
124
+
125
+ '''
126
+ def process_image(input_img, bg_choice):
127
+ if input_img is None:
128
+ return []
129
+ temp_path = os.path.join(UPLOAD_DIR, f"upload_{int(time.time())}.png")
130
+ input_img.save(temp_path)
131
+ result_path = replace_background(temp_path, bg_choice)
132
  return [result_path]
133
+ '''
134
 
135
  def generate_caption(prompt="Promote my product"):
136
  try:
 
149
  # ---------------------------
150
  app = FastAPI(title="SnapLift API")
151
 
152
+ # Allow CORS for mobile app access
153
  app.add_middleware(
154
  CORSMiddleware,
155
+ allow_origins=["*"], # Change later for security
156
  allow_credentials=True,
157
  allow_methods=["*"],
158
  allow_headers=["*"],
 
164
  input_path = os.path.join(UPLOAD_DIR, file.filename)
165
  with open(input_path, "wb") as f:
166
  f.write(await file.read())
167
+
168
+ result_path = replace_background(input_path, bg_choice)
169
+ return FileResponse(result_path)
170
  except Exception as e:
171
  return JSONResponse(content={"error": str(e)}, status_code=400)
172
 
 
182
  gr.Markdown("# ✨ SnapLift – AI Social Media Booster")
183
  gr.Markdown("Upload your product photo, replace background, and auto-generate marketing captions + hashtags!")
184
 
185
+
186
+ # Image Editor Tab
187
  with gr.Tab("📸 Image Editor"):
188
  with gr.Row():
189
  input_img = gr.Image(type="pil", label="Upload Main Photo")
190
 
191
  with gr.Column():
192
  bg_choices = gr.Dropdown(
193
+ choices=os.listdir(BG_DIR),
194
  value=os.listdir(BG_DIR)[0] if os.listdir(BG_DIR) else None,
195
  label="Choose Background"
196
  )
197
+ bg_upload = gr.Image(type="pil", label="Or Upload Your Background (Optional)")
 
 
 
 
 
 
 
 
 
 
 
 
 
198
 
199
+ # Logo + Branding Controls
200
+ with gr.Row():
201
+ logo_upload = gr.Image(type="pil", label="Upload Logo (Optional)")
202
+ logo_transparency = gr.Slider(0, 100, value=70, label="Logo Transparency (%)")
203
+ logo_position = gr.Dropdown(
204
+ ["Top-Left", "Top-Right", "Bottom-Left", "Bottom-Right", "Center"],
205
+ value="Bottom-Right",
206
+ label="Logo Position"
207
+ )
208
+ brand_color = gr.ColorPicker(label="Brand Colour")
209
 
210
  btn = gr.Button("✨ Generate New Photo")
211
  output_imgs = gr.Gallery(label="Generated Image", elem_id="gallery", columns=1, rows=1)
212
+
213
  btn.click(
214
  fn=process_image,
215
+ inputs=[input_img, bg_choices, bg_upload, logo_upload, logo_transparency, logo_position, brand_color],
216
  outputs=output_imgs
217
  )
218
 
 
 
 
 
 
 
219
 
220
+
221
+ '''
222
+ # Image Editor Tab
223
+ with gr.Tab("📸 Image Editor"):
224
+ with gr.Row():
225
+ input_img = gr.Image(type="pil", label="Upload Photo")
226
+
227
+ with gr.Column():
228
+ bg_choices = gr.Dropdown(
229
+ choices=os.listdir(BG_DIR),
230
+ value=os.listdir(BG_DIR)[0] if os.listdir(BG_DIR) else None,
231
+ label="Choose Background"
232
+ )
233
+ bg_preview = gr.Image(
234
+ label="Background Preview",
235
+ type="filepath"
236
+ )
237
+
238
+ # Update preview whenever background changes
239
+ def update_preview(bg_choice):
240
+ return os.path.join(BG_DIR, bg_choice) if bg_choice else None
241
+
242
+ bg_choices.change(fn=update_preview, inputs=bg_choices, outputs=bg_preview)
243
+
244
+ btn = gr.Button("✨ Generate New Photo")
245
+ output_imgs = gr.Gallery(label="Generated Image", elem_id="gallery", columns=1, rows=1)
246
+ btn.click(fn=process_image, inputs=[input_img, bg_choices], outputs=output_imgs)
247
+
248
+
249
+ '''
250
+
251
+
252
+
253
  # START SERVER
254
  # ---------------------------
255
  if __name__ == "__main__":
 
260
 
261
  threading.Thread(target=run_gradio).start()
262
  uvicorn.run(app, host="0.0.0.0", port=8000)
263
+
264
+ threading.Thread(target=start_fastapi, daemon=True).start()
265
+
266
+ demo.launch(server_name="0.0.0.0", server_port=7860)