LogicGoInfotechSpaces commited on
Commit
cc4e1a8
·
verified ·
1 Parent(s): 67584c5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +174 -137
app.py CHANGED
@@ -31,6 +31,7 @@ from typing import Optional
31
  import requests
32
  import json
33
  from bson import ObjectId
 
34
  # --------------------- Logging ---------------------
35
  logging.basicConfig(level=logging.INFO)
36
  logger = logging.getLogger(__name__)
@@ -148,12 +149,16 @@ client = None
148
  database = None
149
 
150
  # --------------------- Admin Panel DB (categories + media_clicks) ---------------------
 
151
  ADMIN_MONGO_URL = os.getenv("ADMIN_MONGO_URL")
152
  admin_client = AsyncIOMotorClient(ADMIN_MONGO_URL)
153
  admin_db = admin_client.adminPanel
154
 
 
155
  categories_col = admin_db.categories
 
156
  media_clicks_col = admin_db.media_clicks
 
157
 
158
  # --------------------- FastAPI ---------------------
159
  fastapi_app = FastAPI()
@@ -289,185 +294,217 @@ def root():
289
  async def health():
290
  return {"status": "healthy"}
291
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  # @fastapi_app.post("/face-swap")
293
  # async def face_swap_api(
294
  # source: UploadFile = File(...),
295
  # target_category_id: str = Form(...),
296
- # user_id: Optional[str] = Form(None),
297
- # category_id: Optional[str] = Form(None),
298
  # user_email: str = Depends(verify_firebase_token)
299
  # ):
 
300
  # start_time = datetime.now(timezone.utc)
301
-
302
  # try:
303
- # # READ SOURCE
304
  # src_bytes = await source.read()
305
  # src_key = f"bikini-theme/source/{uuid.uuid4().hex}_{source.filename}"
306
  # upload_to_spaces(src_bytes, src_key, content_type=source.content_type)
307
 
308
- # # ------------------------------------------------------------------
309
- # # OPTIONAL CATEGORY CLICK LOGGING
310
- # # ------------------------------------------------------------------
311
- # if user_id and category_id:
312
- # try:
313
- # user_oid = ObjectId(user_id)
314
- # category_oid = ObjectId(category_id)
315
- # now = datetime.utcnow()
316
-
317
- # # check category exists
318
- # category_doc = await categories_col.find_one({"_id": category_oid})
319
- # if category_doc:
320
- # update_res = await media_clicks_col.update_one(
321
- # {"userId": user_oid, "categories.categoryId": category_oid},
322
- # {
323
- # "$set": {
324
- # "updatedAt": now,
325
- # "categories.$.lastClickedAt": now
326
- # },
327
- # "$inc": {"categories.$.click_count": 1}
328
- # }
329
- # )
330
-
331
- # if update_res.matched_count == 0:
332
- # await media_clicks_col.update_one(
333
- # {"userId": user_oid},
334
- # {
335
- # "$setOnInsert": {"createdAt": now},
336
- # "$set": {"updatedAt": now},
337
- # "$push": {
338
- # "categories": {
339
- # "categoryId": category_oid,
340
- # "click_count": 1,
341
- # "lastClickedAt": now
342
- # }
343
- # }
344
- # },
345
- # upsert=True
346
- # )
347
- # else:
348
- # logger.error(f"Invalid category_id (not in categories collection): {category_id}")
349
-
350
- # except Exception as log_err:
351
- # logger.error(f"MEDIA_CLICK ERROR: {log_err}")
352
-
353
- # # ------------------------------------------------------------------
354
- # # TARGET IMAGE DOWNLOAD
355
- # # ------------------------------------------------------------------
356
  # target_filename = f"{target_category_id}.png"
357
  # target_url = f"https://{DO_SPACES_BUCKET}.{DO_SPACES_REGION}.digitaloceanspaces.com/bikini-theme/target/{target_filename}"
358
 
359
  # resp = requests.get(target_url)
360
  # if resp.status_code != 200:
 
361
  # end_time = datetime.now(timezone.utc)
362
- # await log_faceswap_hit(user_email, "error", start_time, end_time)
363
- # raise HTTPException(404, f"Target not found at {target_url}")
364
 
365
  # tgt_bytes = resp.content
366
 
367
- # # FACE SWAP
368
- # src_bgr = cv2.imdecode(np.frombuffer(src_bytes, np.uint8), cv2.IMREAD_COLOR)
369
- # tgt_bgr = cv2.imdecode(np.frombuffer(tgt_bytes, np.uint8), cv2.IMREAD_COLOR)
 
370
 
371
  # if src_bgr is None or tgt_bgr is None:
 
372
  # end_time = datetime.now(timezone.utc)
373
- # await log_faceswap_hit(user_email, "error", start_time, end_time)
374
- # raise HTTPException(400, "Invalid image data")
 
375
 
376
  # src_rgb = cv2.cvtColor(src_bgr, cv2.COLOR_BGR2RGB)
377
  # tgt_rgb = cv2.cvtColor(tgt_bgr, cv2.COLOR_BGR2RGB)
378
 
379
  # final_img, final_path, err = face_swap_and_enhance(src_rgb, tgt_rgb)
380
  # if err:
381
- # end_time = datetime.now(timezone.utc)
382
- # await log_faceswap_hit(user_email, "error", start_time, end_time)
383
- # raise HTTPException(500, err)
384
 
385
  # with open(final_path, "rb") as f:
386
  # result_bytes = f.read()
387
-
388
  # result_key = f"bikini-theme/result/{uuid.uuid4().hex}_enhanced.png"
389
- # result_url = upload_to_spaces(result_bytes, result_key, "image/png")
390
 
 
391
  # end_time = datetime.now(timezone.utc)
392
- # await log_faceswap_hit(user_email, "success", start_time, end_time)
393
 
394
  # return {"result_url": result_url}
395
 
396
  # except Exception as e:
 
397
  # end_time = datetime.now(timezone.utc)
398
- # try:
399
- # await log_faceswap_hit(user_email, "error", start_time, end_time)
400
- # except:
401
- # pass
402
- # raise HTTPException(500, f"Face swap failed: {e}")
403
-
404
- @fastapi_app.post("/face-swap")
405
- async def face_swap_api(
406
- source: UploadFile = File(...),
407
- target_category_id: str = Form(...),
408
- user_email: str = Depends(verify_firebase_token)
409
- ):
410
- # start_time = datetime.utcnow()
411
- start_time = datetime.now(timezone.utc)
412
- try:
413
- src_bytes = await source.read()
414
- src_key = f"bikini-theme/source/{uuid.uuid4().hex}_{source.filename}"
415
- upload_to_spaces(src_bytes, src_key, content_type=source.content_type)
416
-
417
- target_filename = f"{target_category_id}.png"
418
- target_url = f"https://{DO_SPACES_BUCKET}.{DO_SPACES_REGION}.digitaloceanspaces.com/bikini-theme/target/{target_filename}"
419
-
420
- resp = requests.get(target_url)
421
- if resp.status_code != 200:
422
- # end_time = datetime.utcnow()
423
- end_time = datetime.now(timezone.utc)
424
- await log_faceswap_hit(user_email, status="error", start_time=start_time, end_time=end_time)
425
- raise HTTPException(status_code=404, detail=f"Target image not found at {target_url}")
426
-
427
- tgt_bytes = resp.content
428
-
429
- src_array = np.frombuffer(src_bytes, np.uint8)
430
- tgt_array = np.frombuffer(tgt_bytes, np.uint8)
431
- src_bgr = cv2.imdecode(src_array, cv2.IMREAD_COLOR)
432
- tgt_bgr = cv2.imdecode(tgt_array, cv2.IMREAD_COLOR)
433
-
434
- if src_bgr is None or tgt_bgr is None:
435
- #end_time = datetime.utcnow()
436
- end_time = datetime.now(timezone.utc)
437
 
438
- await log_faceswap_hit(user_email, status="error", start_time=start_time, end_time=end_time)
439
- raise HTTPException(status_code=400, detail="Invalid image data")
440
-
441
- src_rgb = cv2.cvtColor(src_bgr, cv2.COLOR_BGR2RGB)
442
- tgt_rgb = cv2.cvtColor(tgt_bgr, cv2.COLOR_BGR2RGB)
443
-
444
- final_img, final_path, err = face_swap_and_enhance(src_rgb, tgt_rgb)
445
- if err:
446
- end_time = datetime.utcnow()
447
- await log_faceswap_hit(user_email, status="error", start_time=start_time, end_time=end_time)
448
- raise HTTPException(status_code=500, detail=err)
449
-
450
- with open(final_path, "rb") as f:
451
- result_bytes = f.read()
452
- result_key = f"bikini-theme/result/{uuid.uuid4().hex}_enhanced.png"
453
- result_url = upload_to_spaces(result_bytes, result_key, content_type="image/png")
454
-
455
- #end_time = datetime.utcnow()
456
- end_time = datetime.now(timezone.utc)
457
- await log_faceswap_hit(user_email, status="success", start_time=start_time, end_time=end_time)
458
-
459
- return {"result_url": result_url}
460
-
461
- except Exception as e:
462
- #end_time = datetime.utcnow()
463
- end_time = datetime.now(timezone.utc)
464
-
465
- # Ensure we log the error with timestamps before raising
466
- try:
467
- await log_faceswap_hit(user_email, status="error", start_time=start_time, end_time=end_time)
468
- except Exception as log_exc:
469
- logger.error("Failed to write log_faceswap_hit: %s", log_exc)
470
- raise HTTPException(status_code=500, detail=f"Face swap failed: {str(e)}")
471
 
472
 
473
  @fastapi_app.get("/preview/{result_key:path}")
 
31
  import requests
32
  import json
33
  from bson import ObjectId
34
+
35
  # --------------------- Logging ---------------------
36
  logging.basicConfig(level=logging.INFO)
37
  logger = logging.getLogger(__name__)
 
149
  database = None
150
 
151
  # --------------------- Admin Panel DB (categories + media_clicks) ---------------------
152
+ # --------------------- Admin Panel DB (categories + subcategories + media_clicks) ---------------------
153
  ADMIN_MONGO_URL = os.getenv("ADMIN_MONGO_URL")
154
  admin_client = AsyncIOMotorClient(ADMIN_MONGO_URL)
155
  admin_db = admin_client.adminPanel
156
 
157
+ # Collections
158
  categories_col = admin_db.categories
159
+ subcategories_col = admin_db.subcategories
160
  media_clicks_col = admin_db.media_clicks
161
+ users_col = admin_db.users # optional, only if needed
162
 
163
  # --------------------- FastAPI ---------------------
164
  fastapi_app = FastAPI()
 
294
  async def health():
295
  return {"status": "healthy"}
296
 
297
+ @fastapi_app.post("/face-swap")
298
+ async def face_swap_api(
299
+ source: UploadFile = File(...),
300
+ target_category_id: str = Form(...), # REQUIRED (old behavior preserved)
301
+ category_id: Optional[str] = Form(None),
302
+ user_id: Optional[str] = Form(None),
303
+ new_subcategory_id: Optional[str] = Form(None),
304
+ user_email: str = Depends(verify_firebase_token)
305
+ ):
306
+ start_time = datetime.now(timezone.utc)
307
+
308
+ try:
309
+ # ---------------------------------------------------------
310
+ # NORMALIZE EMPTY STRINGS (Android older versions)
311
+ # ---------------------------------------------------------
312
+ if target_category_id == "":
313
+ target_category_id = None
314
+
315
+ if new_subcategory_id == "":
316
+ new_subcategory_id = None
317
+
318
+ if category_id == "":
319
+ category_id = None
320
+
321
+ if user_id == "":
322
+ user_id = None
323
+
324
+ # ---------------------------------------------------------
325
+ # STRICT XOR VALIDATION
326
+ # ---------------------------------------------------------
327
+ if target_category_id and new_subcategory_id:
328
+ raise HTTPException(
329
+ status_code=400,
330
+ detail="Provide ONLY ONE of: target_category_id OR new_subcategory_id"
331
+ )
332
+
333
+ if not target_category_id and not new_subcategory_id:
334
+ raise HTTPException(
335
+ status_code=400,
336
+ detail="Either target_category_id OR new_subcategory_id is required"
337
+ )
338
+
339
+ # ---------------------------------------------------------
340
+ # READ SOURCE IMAGE
341
+ # ---------------------------------------------------------
342
+ src_bytes = await source.read()
343
+ src_key = f"bikini-theme/source/{uuid.uuid4().hex}_{source.filename}"
344
+ upload_to_spaces(src_bytes, src_key, content_type=source.content_type)
345
+
346
+ # ---------------------------------------------------------
347
+ # CASE 1 — Old behavior (use DO Spaces target image)
348
+ # ---------------------------------------------------------
349
+ if target_category_id:
350
+ target_filename = f"{target_category_id}.png"
351
+ target_url = (
352
+ f"https://{DO_SPACES_BUCKET}.{DO_SPACES_REGION}."
353
+ f"digitaloceanspaces.com/bikini-theme/target/{target_filename}"
354
+ )
355
+
356
+ resp = requests.get(target_url)
357
+ if resp.status_code != 200:
358
+ await log_faceswap_hit(user_email, "error", start_time, datetime.now(timezone.utc))
359
+ raise HTTPException(status_code=404, detail=f"Target image not found: {target_url}")
360
+
361
+ tgt_bytes = resp.content
362
+
363
+ # ---------------------------------------------------------
364
+ # CASE 2 — New behavior (use subcategory asset image)
365
+ # ---------------------------------------------------------
366
+ else:
367
+ # Find subcategory asset by asset_images._id
368
+ asset = await admin_db.subcategories.find_one(
369
+ {"asset_images._id": ObjectId(new_subcategory_id)},
370
+ {"asset_images.$": 1}
371
+ )
372
+
373
+ if not asset or "asset_images" not in asset:
374
+ await log_faceswap_hit(user_email, "error", start_time, datetime.now(timezone.utc))
375
+ raise HTTPException(
376
+ status_code=404,
377
+ detail="Subcategory asset image not found"
378
+ )
379
+
380
+ # Extract the single matching image URL
381
+ asset_url = asset["asset_images"][0]["url"]
382
+
383
+ resp = requests.get(asset_url)
384
+ if resp.status_code != 200:
385
+ raise HTTPException(
386
+ status_code=404,
387
+ detail=f"Failed to download asset image: {asset_url}"
388
+ )
389
+
390
+ tgt_bytes = resp.content
391
+
392
+ # ---------------------------------------------------------
393
+ # DECODE BOTH IMAGES
394
+ # ---------------------------------------------------------
395
+ src_array = np.frombuffer(src_bytes, np.uint8)
396
+ tgt_array = np.frombuffer(tgt_bytes, np.uint8)
397
+
398
+ src_bgr = cv2.imdecode(src_array, cv2.IMREAD_COLOR)
399
+ tgt_bgr = cv2.imdecode(tgt_array, cv2.IMREAD_COLOR)
400
+
401
+ if src_bgr is None or tgt_bgr is None:
402
+ await log_faceswap_hit(user_email, "error", start_time, datetime.now(timezone.utc))
403
+ raise HTTPException(status_code=400, detail="Invalid image data")
404
+
405
+ src_rgb = cv2.cvtColor(src_bgr, cv2.COLOR_BGR2RGB)
406
+ tgt_rgb = cv2.cvtColor(tgt_bgr, cv2.COLOR_BGR2RGB)
407
+
408
+ # ---------------------------------------------------------
409
+ # FACE SWAP & ENHANCE
410
+ # ---------------------------------------------------------
411
+ final_img, final_path, err = face_swap_and_enhance(src_rgb, tgt_rgb)
412
+ if err:
413
+ await log_faceswap_hit(user_email, "error", start_time, datetime.now(timezone.utc))
414
+ raise HTTPException(status_code=500, detail=err)
415
+
416
+ # Save final output to DO Spaces
417
+ with open(final_path, "rb") as f:
418
+ result_bytes = f.read()
419
+
420
+ result_key = f"bikini-theme/result/{uuid.uuid4().hex}_enhanced.png"
421
+ result_url = upload_to_spaces(result_bytes, result_key, "image/png")
422
+
423
+ await log_faceswap_hit(user_email, "success", start_time, datetime.now(timezone.utc))
424
+
425
+ # ---------------------------------------------------------
426
+ # SUCCESS RESPONSE
427
+ # ---------------------------------------------------------
428
+ return {
429
+ "result_url": result_url,
430
+ "category_id": category_id,
431
+ "user_id": user_id,
432
+ "new_subcategory_id": new_subcategory_id
433
+ }
434
+
435
+ except Exception as e:
436
+ await log_faceswap_hit(user_email, "error", start_time, datetime.now(timezone.utc))
437
+ raise HTTPException(status_code=500, detail=f"Face swap failed: {str(e)}")
438
+
439
+
440
+ ####------------------------------------OLD CODE------------------------------------####
441
  # @fastapi_app.post("/face-swap")
442
  # async def face_swap_api(
443
  # source: UploadFile = File(...),
444
  # target_category_id: str = Form(...),
 
 
445
  # user_email: str = Depends(verify_firebase_token)
446
  # ):
447
+ # # start_time = datetime.utcnow()
448
  # start_time = datetime.now(timezone.utc)
 
449
  # try:
 
450
  # src_bytes = await source.read()
451
  # src_key = f"bikini-theme/source/{uuid.uuid4().hex}_{source.filename}"
452
  # upload_to_spaces(src_bytes, src_key, content_type=source.content_type)
453
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
454
  # target_filename = f"{target_category_id}.png"
455
  # target_url = f"https://{DO_SPACES_BUCKET}.{DO_SPACES_REGION}.digitaloceanspaces.com/bikini-theme/target/{target_filename}"
456
 
457
  # resp = requests.get(target_url)
458
  # if resp.status_code != 200:
459
+ # # end_time = datetime.utcnow()
460
  # end_time = datetime.now(timezone.utc)
461
+ # await log_faceswap_hit(user_email, status="error", start_time=start_time, end_time=end_time)
462
+ # raise HTTPException(status_code=404, detail=f"Target image not found at {target_url}")
463
 
464
  # tgt_bytes = resp.content
465
 
466
+ # src_array = np.frombuffer(src_bytes, np.uint8)
467
+ # tgt_array = np.frombuffer(tgt_bytes, np.uint8)
468
+ # src_bgr = cv2.imdecode(src_array, cv2.IMREAD_COLOR)
469
+ # tgt_bgr = cv2.imdecode(tgt_array, cv2.IMREAD_COLOR)
470
 
471
  # if src_bgr is None or tgt_bgr is None:
472
+ # #end_time = datetime.utcnow()
473
  # end_time = datetime.now(timezone.utc)
474
+
475
+ # await log_faceswap_hit(user_email, status="error", start_time=start_time, end_time=end_time)
476
+ # raise HTTPException(status_code=400, detail="Invalid image data")
477
 
478
  # src_rgb = cv2.cvtColor(src_bgr, cv2.COLOR_BGR2RGB)
479
  # tgt_rgb = cv2.cvtColor(tgt_bgr, cv2.COLOR_BGR2RGB)
480
 
481
  # final_img, final_path, err = face_swap_and_enhance(src_rgb, tgt_rgb)
482
  # if err:
483
+ # end_time = datetime.utcnow()
484
+ # await log_faceswap_hit(user_email, status="error", start_time=start_time, end_time=end_time)
485
+ # raise HTTPException(status_code=500, detail=err)
486
 
487
  # with open(final_path, "rb") as f:
488
  # result_bytes = f.read()
 
489
  # result_key = f"bikini-theme/result/{uuid.uuid4().hex}_enhanced.png"
490
+ # result_url = upload_to_spaces(result_bytes, result_key, content_type="image/png")
491
 
492
+ # #end_time = datetime.utcnow()
493
  # end_time = datetime.now(timezone.utc)
494
+ # await log_faceswap_hit(user_email, status="success", start_time=start_time, end_time=end_time)
495
 
496
  # return {"result_url": result_url}
497
 
498
  # except Exception as e:
499
+ # #end_time = datetime.utcnow()
500
  # end_time = datetime.now(timezone.utc)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
501
 
502
+ # # Ensure we log the error with timestamps before raising
503
+ # try:
504
+ # await log_faceswap_hit(user_email, status="error", start_time=start_time, end_time=end_time)
505
+ # except Exception as log_exc:
506
+ # logger.error("Failed to write log_faceswap_hit: %s", log_exc)
507
+ # raise HTTPException(status_code=500, detail=f"Face swap failed: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
 
509
 
510
  @fastapi_app.get("/preview/{result_key:path}")