LogicGoInfotechSpaces commited on
Commit
a2164da
·
verified ·
1 Parent(s): 3f3e311

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +251 -279
app.py CHANGED
@@ -249,203 +249,281 @@ async def test_admin_db():
249
  except Exception as e:
250
  return {"ok": False, "error": str(e), "url": ADMIN_MONGO_URL}
251
 
252
- # @fastapi_app.post("/face-swap", dependencies=[Depends(verify_token)])
253
- # async def face_swap_api(
254
- # source: UploadFile = File(...),
255
- # target_category_id: str = Form(None),
256
- # new_category_id: str = Form(None),
257
- # user_id: Optional[str] = Form(None),
258
- # credentials: HTTPAuthorizationCredentials = Security(security)
259
- # ):
260
- # start_time = datetime.utcnow()
261
 
262
- # try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
 
264
- # # --------------------------------------------------------------
265
- # # NORMALIZE EMPTY STRINGS (BACKWARD COMPATIBILITY FOR ANDROID)
266
- # # --------------------------------------------------------------
267
- # if target_category_id == "":
268
- # target_category_id = None
269
 
270
- # if new_category_id == "":
271
- # new_category_id = None
 
272
 
273
- # if user_id == "":
274
- # user_id = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
 
276
- # # --------------------------------------------------------------
277
- # # VALIDATION
278
- # # --------------------------------------------------------------
279
- # if target_category_id and new_category_id:
280
- # raise HTTPException(400, "Provide only one of new_category_id or target_category_id.")
281
 
282
- # if not target_category_id and not new_category_id:
283
- # raise HTTPException(400, "Either new_category_id or target_category_id is required.")
 
 
 
 
284
 
285
- # # ------------------------------------------------------------------
286
- # # READ SOURCE IMAGE
287
- # # ------------------------------------------------------------------
288
- # src_bytes = await source.read()
289
- # src_key = f"faceswap/source/{uuid.uuid4().hex}_{source.filename}"
290
- # upload_to_spaces(src_bytes, src_key, content_type=source.content_type)
291
 
292
- # # ------------------------------------------------------------------
293
- # # CASE 1 : new_category_id → MongoDB lookup
294
- # # ------------------------------------------------------------------
295
- # if new_category_id:
296
 
297
- # doc = await subcategories_col.find_one({
298
- # "asset_images._id": ObjectId(new_category_id)
299
- # })
300
 
301
- # if not doc:
302
- # raise HTTPException(404, "Asset image not found in database")
303
-
304
- # # extract correct asset
305
- # asset = next(
306
- # (img for img in doc["asset_images"] if str(img["_id"]) == new_category_id),
307
- # None
308
- # )
309
-
310
- # if not asset:
311
- # raise HTTPException(404, "Asset image URL not found")
312
-
313
- # # correct URL
314
- # target_url = asset["url"]
315
-
316
- # # correct categoryId (ObjectId)
317
- # #category_oid = doc["categoryId"] # <-- DO NOT CONVERT TO STRING
318
- # subcategory_oid = doc["_id"]
319
-
320
- # # ------------------------------------------------------------------
321
- # # MEDIA_CLICKS (ONLY IF user_id PRESENT)
322
- # # ------------------------------------------------------------------
323
- # if user_id:
324
- # try:
325
- # user_oid = ObjectId(user_id.strip())
326
- # now = datetime.utcnow()
327
-
328
- # # ----------------------------------------------------------
329
- # # 1. UPDATE EXISTING SUBCATEGORY IF PRESENT
330
- # # ----------------------------------------------------------
331
- # update_result = await media_clicks_col.update_one(
332
- # {
333
- # "userId": user_oid,
334
- # "subCategories.subCategoryId": subcategory_oid
335
- # },
336
- # {
337
- # "$set": {
338
- # "updatedAt": now,
339
- # "subCategories.$.lastClickedAt": now
340
- # },
341
- # "$inc": {
342
- # "subCategories.$.click_count": 1
343
- # }
344
- # }
345
- # )
346
-
347
- # # ----------------------------------------------------------
348
- # # 2. If user exists BUT subCategory NOT found → push subCategory
349
- # # ----------------------------------------------------------
350
- # if update_result.matched_count == 0:
351
- # update_result_user = await media_clicks_col.update_one(
352
- # {"userId": user_oid},
353
- # {
354
- # "$set": {"updatedAt": now},
355
- # "$push": {
356
- # "subCategories": {
357
- # "subCategoryId": subcategory_oid,
358
- # "click_count": 1,
359
- # "lastClickedAt": now
360
- # }
361
- # }
362
- # }
363
- # )
364
-
365
- # # ------------------------------------------------------
366
- # # 3. If user document does NOT exist → CREATE NEW DOC
367
- # # ------------------------------------------------------
368
- # if update_result_user.matched_count == 0:
369
- # await media_clicks_col.insert_one({
370
- # "userId": user_oid,
371
- # "createdAt": now,
372
- # "updatedAt": now,
373
- # "categories": [], # keep empty or retain existing structure
374
- # "subCategories": [
375
- # {
376
- # "subCategoryId": subcategory_oid,
377
- # "click_count": 1,
378
- # "lastClickedAt": now
379
- # }
380
- # ]
381
- # })
382
-
383
- # except Exception as media_err:
384
- # logger.error(f"MEDIA_CLICK ERROR: {media_err}")
385
-
386
-
387
- # # ------------------------------------------------------------------
388
- # # CASE 2 : target_category_id → DigitalOcean path (unchanged logic)
389
- # # ------------------------------------------------------------------
390
- # if target_category_id:
391
- # client = get_spaces_client()
392
- # base_prefix = "faceswap/target/"
393
- # resp = client.list_objects_v2(
394
- # Bucket=DO_SPACES_BUCKET, Prefix=base_prefix, Delimiter="/"
395
- # )
396
- # categories = [p["Prefix"].split("/")[2] for p in resp.get("CommonPrefixes", [])]
397
-
398
- # target_url = None
399
-
400
- # for category in categories:
401
- # original_prefix = f"faceswap/target/{category}/original/"
402
- # original_objs = client.list_objects_v2(
403
- # Bucket=DO_SPACES_BUCKET, Prefix=original_prefix
404
- # ).get("Contents", [])
405
-
406
- # original_files = sorted([obj["Key"] for obj in original_objs])
407
-
408
- # for idx, file_key in enumerate(original_files, start=1):
409
- # cid = f"{category.lower()}image_{idx}"
410
- # if cid == target_category_id:
411
- # target_url = f"{DO_SPACES_ENDPOINT}/{DO_SPACES_BUCKET}/{file_key}"
412
- # break
413
-
414
- # if target_url:
415
- # break
416
 
417
- # if not target_url:
418
- # raise HTTPException(404, "Target categoryId not found")
 
 
 
 
419
 
420
- # # ------------------------------------------------------------------
421
- # # DOWNLOAD TARGET IMAGE
422
- # # ------------------------------------------------------------------
423
- # tgt_bytes = requests.get(target_url).content
424
 
425
- # src_bgr = cv2.imdecode(np.frombuffer(src_bytes, np.uint8), cv2.IMREAD_COLOR)
426
- # tgt_bgr = cv2.imdecode(np.frombuffer(tgt_bytes, np.uint8), cv2.IMREAD_COLOR)
427
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
428
  # if src_bgr is None or tgt_bgr is None:
429
- # raise HTTPException(400, "Invalid image data")
430
 
431
  # src_rgb = cv2.cvtColor(src_bgr, cv2.COLOR_BGR2RGB)
432
  # tgt_rgb = cv2.cvtColor(tgt_bgr, cv2.COLOR_BGR2RGB)
433
 
434
- # # ------------------------------------------------------------------
435
- # # FACE SWAP EXECUTION
436
- # # ------------------------------------------------------------------
437
  # final_img, final_path, err = face_swap_and_enhance(src_rgb, tgt_rgb)
438
  # if err:
439
- # raise HTTPException(500, err)
440
 
 
441
  # with open(final_path, "rb") as f:
442
  # result_bytes = f.read()
443
-
444
  # result_key = f"faceswap/result/{uuid.uuid4().hex}_enhanced.png"
445
- # result_url = upload_to_spaces(result_bytes, result_key,content_type="image/png")
446
-
 
447
  # end_time = datetime.utcnow()
448
  # response_time_ms = (end_time - start_time).total_seconds() * 1000
 
 
449
  # if database is not None:
450
  # await database.api_logs.insert_one({
451
  # "endpoint": "/face-swap",
@@ -454,17 +532,12 @@ async def test_admin_db():
454
  # "timestamp": end_time
455
  # })
456
 
457
-
458
- # return {
459
- # "result_key": result_key,
460
- # "result_url": result_url
461
- # }
462
-
463
 
464
  # except Exception as e:
 
465
  # end_time = datetime.utcnow()
466
  # response_time_ms = (end_time - start_time).total_seconds() * 1000
467
-
468
  # if database is not None:
469
  # await database.api_logs.insert_one({
470
  # "endpoint": "/face-swap",
@@ -473,108 +546,7 @@ async def test_admin_db():
473
  # "timestamp": end_time,
474
  # "error": str(e)
475
  # })
476
-
477
- # raise HTTPException(500, f"Face swap failed: {str(e)}")
478
-
479
-
480
-
481
-
482
- #-------------------------------------------------------------------------------------------------------------------------------#
483
- ####OLD CODE------------------------------------------------------------------------------------
484
- @fastapi_app.post("/face-swap", dependencies=[Depends(verify_token)])
485
- async def face_swap_api(
486
- source: UploadFile = File(...),
487
- target_category_id: str = Form(...),
488
- credentials: HTTPAuthorizationCredentials = Security(security)
489
- ):
490
- start_time = datetime.utcnow() # start timer
491
- try:
492
- # Read source image
493
- src_bytes = await source.read()
494
-
495
- # Save source to Spaces
496
- src_key = f"faceswap/source/{uuid.uuid4().hex}_{source.filename}"
497
- upload_to_spaces(src_bytes, src_key, content_type=source.content_type)
498
-
499
- # Find target image URL from categoryId
500
- client = get_spaces_client()
501
- base_prefix = "faceswap/target/"
502
- resp = client.list_objects_v2(Bucket=DO_SPACES_BUCKET, Prefix=base_prefix, Delimiter="/")
503
- categories = [prefix["Prefix"].split("/")[2] for prefix in resp.get("CommonPrefixes", [])]
504
- target_url = None
505
- for category in categories:
506
- original_prefix = f"faceswap/target/{category}/original/"
507
- thumb_prefix = f"faceswap/target/{category}/thumb/"
508
- original_objects = client.list_objects_v2(Bucket=DO_SPACES_BUCKET, Prefix=original_prefix)
509
- thumb_objects = client.list_objects_v2(Bucket=DO_SPACES_BUCKET, Prefix=thumb_prefix)
510
- original_files = [obj["Key"].split("/")[-1] for obj in original_objects.get("Contents", []) if obj["Key"].endswith(".png")]
511
- thumb_files = [obj["Key"].split("/")[-1] for obj in thumb_objects.get("Contents", []) if obj["Key"].endswith(".png")]
512
- for idx, filename in enumerate(sorted(original_files), start=1):
513
- cid = f"{category.lower()}image_{idx}"
514
- if filename in thumb_files and cid == target_category_id:
515
- target_url = f"https://{DO_SPACES_BUCKET}.blr1.digitaloceanspaces.com/{original_prefix}{filename}"
516
- break
517
- if target_url:
518
- break
519
- if not target_url:
520
- raise HTTPException(status_code=404, detail="Target categoryId not found")
521
-
522
- # Download target image from Spaces
523
- resp = requests.get(target_url)
524
- if resp.status_code != 200:
525
- raise HTTPException(status_code=404, detail="Target image not found in Spaces")
526
- tgt_bytes = resp.content
527
-
528
- # Decode for processing
529
- src_array = np.frombuffer(src_bytes, np.uint8)
530
- tgt_array = np.frombuffer(tgt_bytes, np.uint8)
531
- src_bgr = cv2.imdecode(src_array, cv2.IMREAD_COLOR)
532
- tgt_bgr = cv2.imdecode(tgt_array, cv2.IMREAD_COLOR)
533
- if src_bgr is None or tgt_bgr is None:
534
- raise HTTPException(status_code=400, detail="Invalid image data")
535
-
536
- src_rgb = cv2.cvtColor(src_bgr, cv2.COLOR_BGR2RGB)
537
- tgt_rgb = cv2.cvtColor(tgt_bgr, cv2.COLOR_BGR2RGB)
538
-
539
- # Run face swap pipeline
540
- final_img, final_path, err = face_swap_and_enhance(src_rgb, tgt_rgb)
541
- if err:
542
- raise HTTPException(status_code=500, detail=err)
543
-
544
- # Upload result to Spaces
545
- with open(final_path, "rb") as f:
546
- result_bytes = f.read()
547
- result_key = f"faceswap/result/{uuid.uuid4().hex}_enhanced.png"
548
- result_url = upload_to_spaces(result_bytes, result_key, content_type="image/png")
549
-
550
- # Calculate response time
551
- end_time = datetime.utcnow()
552
- response_time_ms = (end_time - start_time).total_seconds() * 1000
553
-
554
- # Log response time only
555
- if database is not None:
556
- await database.api_logs.insert_one({
557
- "endpoint": "/face-swap",
558
- "status": "success",
559
- "response_time_ms": response_time_ms,
560
- "timestamp": end_time
561
- })
562
-
563
- return {"result_key": result_key, "result_url": result_url}
564
-
565
- except Exception as e:
566
- # Log response time even on error
567
- end_time = datetime.utcnow()
568
- response_time_ms = (end_time - start_time).total_seconds() * 1000
569
- if database is not None:
570
- await database.api_logs.insert_one({
571
- "endpoint": "/face-swap",
572
- "status": "fail",
573
- "response_time_ms": response_time_ms,
574
- "timestamp": end_time,
575
- "error": str(e)
576
- })
577
- raise HTTPException(status_code=500, detail=f"Face swap failed: {str(e)}")
578
 
579
 
580
 
 
249
  except Exception as e:
250
  return {"ok": False, "error": str(e), "url": ADMIN_MONGO_URL}
251
 
252
+ @fastapi_app.post("/face-swap", dependencies=[Depends(verify_token)])
253
+ async def face_swap_api(
254
+ source: UploadFile = File(...),
255
+ target_category_id: str = Form(None),
256
+ new_category_id: str = Form(None),
257
+ user_id: Optional[str] = Form(None),
258
+ credentials: HTTPAuthorizationCredentials = Security(security)
259
+ ):
260
+ start_time = datetime.utcnow()
261
 
262
+ try:
263
+ # --------------------------------------------------------------
264
+ # NORMALIZE EMPTY STRINGS (BACKWARD COMPATIBILITY FOR ANDROID)
265
+ # --------------------------------------------------------------
266
+ if target_category_id == "":
267
+ target_category_id = None
268
+
269
+ if new_category_id == "":
270
+ new_category_id = None
271
+
272
+ if user_id == "":
273
+ user_id = None
274
+
275
+ # --------------------------------------------------------------
276
+ # XOR VALIDATION
277
+ # --------------------------------------------------------------
278
+ if target_category_id and new_category_id:
279
+ raise HTTPException(400, "Provide only one of new_category_id or target_category_id.")
280
+
281
+ if not target_category_id and not new_category_id:
282
+ raise HTTPException(400, "Either new_category_id or target_category_id is required.")
283
+
284
+ # --------------------------------------------------------------
285
+ # READ & UPLOAD SOURCE IMAGE
286
+ # --------------------------------------------------------------
287
+ src_bytes = await source.read()
288
+ src_key = f"faceswap/source/{uuid.uuid4().hex}_{source.filename}"
289
+ upload_to_spaces(src_bytes, src_key, content_type=source.content_type)
290
 
291
+ # --------------------------------------------------------------
292
+ # CASE 1: new_category_id MongoDB lookup
293
+ # --------------------------------------------------------------
294
+ if new_category_id:
 
295
 
296
+ doc = await subcategories_col.find_one({
297
+ "asset_images._id": ObjectId(new_category_id)
298
+ })
299
 
300
+ if not doc:
301
+ raise HTTPException(404, "Asset image not found in database")
302
+
303
+ asset = next((img for img in doc["asset_images"] if str(img["_id"]) == new_category_id), None)
304
+ if not asset:
305
+ raise HTTPException(404, "Asset image URL not found")
306
+
307
+ target_url = asset["url"]
308
+ subcategory_oid = doc["_id"]
309
+
310
+ # ------------------------ MEDIA CLICKS ------------------------
311
+ if user_id:
312
+ try:
313
+ user_oid = ObjectId(user_id.strip())
314
+ now = datetime.utcnow()
315
+
316
+ # 1. UPDATE EXISTING SUBCATEGORY
317
+ update_result = await media_clicks_col.update_one(
318
+ {"userId": user_oid, "subCategories.subCategoryId": subcategory_oid},
319
+ {"$set": {"updatedAt": now, "subCategories.$.lastClickedAt": now},
320
+ "$inc": {"subCategories.$.click_count": 1}}
321
+ )
322
+
323
+ # 2. USER EXISTS but subCategory missing → push
324
+ if update_result.matched_count == 0:
325
+ update_result_user = await media_clicks_col.update_one(
326
+ {"userId": user_oid},
327
+ {"$set": {"updatedAt": now},
328
+ "$push": {"subCategories": {
329
+ "subCategoryId": subcategory_oid,
330
+ "click_count": 1,
331
+ "lastClickedAt": now
332
+ }}}
333
+ )
334
+
335
+ # 3. USER DOCUMENT DOES NOT EXIST → create new
336
+ if update_result_user.matched_count == 0:
337
+ await media_clicks_col.insert_one({
338
+ "userId": user_oid,
339
+ "createdAt": now,
340
+ "updatedAt": now,
341
+ "categories": [],
342
+ "subCategories": [{
343
+ "subCategoryId": subcategory_oid,
344
+ "click_count": 1,
345
+ "lastClickedAt": now
346
+ }]
347
+ })
348
+
349
+ except Exception as media_err:
350
+ logger.error(f"MEDIA_CLICK ERROR: {media_err}")
351
+
352
+ # --------------------------------------------------------------
353
+ # CASE 2 : target_category_id → DigitalOcean Lookup
354
+ # --------------------------------------------------------------
355
+ if target_category_id:
356
+ client = get_spaces_client()
357
+ base_prefix = "faceswap/target/"
358
+
359
+ resp = client.list_objects_v2(
360
+ Bucket=DO_SPACES_BUCKET, Prefix=base_prefix, Delimiter="/"
361
+ )
362
+ categories = [p["Prefix"].split("/")[2] for p in resp.get("CommonPrefixes", [])]
363
+
364
+ target_url = None
365
+
366
+ for category in categories:
367
+ original_prefix = f"faceswap/target/{category}/original/"
368
+ objects = client.list_objects_v2(
369
+ Bucket=DO_SPACES_BUCKET, Prefix=original_prefix
370
+ ).get("Contents", [])
371
+
372
+ sorted_files = sorted([obj["Key"] for obj in objects])
373
+
374
+ for idx, key in enumerate(sorted_files, start=1):
375
+ cid = f"{category.lower()}image_{idx}"
376
+ if cid == target_category_id:
377
+
378
+ # FIXED URL (old code used correct DO URL)
379
+ target_url = (
380
+ f"https://{DO_SPACES_BUCKET}.{DO_SPACES_REGION}.digitaloceanspaces.com/{key}"
381
+ )
382
+ break
383
+
384
+ if target_url:
385
+ break
386
 
387
+ if not target_url:
388
+ raise HTTPException(404, "Target categoryId not found")
 
 
 
389
 
390
+ # --------------------------------------------------------------
391
+ # DOWNLOAD TARGET IMAGE
392
+ # --------------------------------------------------------------
393
+ response = requests.get(target_url)
394
+ if response.status_code != 200:
395
+ raise HTTPException(400, "Failed to download target image")
396
 
397
+ tgt_bytes = response.content
 
 
 
 
 
398
 
399
+ # Decode both images
400
+ src_bgr = cv2.imdecode(np.frombuffer(src_bytes, np.uint8), cv2.IMREAD_COLOR)
401
+ tgt_bgr = cv2.imdecode(np.frombuffer(tgt_bytes, np.uint8), cv2.IMREAD_COLOR)
 
402
 
403
+ if src_bgr is None or tgt_bgr is None:
404
+ raise HTTPException(400, "Invalid image data")
 
405
 
406
+ src_rgb = cv2.cvtColor(src_bgr, cv2.COLOR_BGR2RGB)
407
+ tgt_rgb = cv2.cvtColor(tgt_bgr, cv2.COLOR_BGR2RGB)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
 
409
+ # --------------------------------------------------------------
410
+ # RUN FACE SWAP
411
+ # --------------------------------------------------------------
412
+ final_img, final_path, err = face_swap_and_enhance(src_rgb, tgt_rgb)
413
+ if err:
414
+ raise HTTPException(500, err)
415
 
416
+ with open(final_path, "rb") as f:
417
+ result_bytes = f.read()
 
 
418
 
419
+ result_key = f"faceswap/result/{uuid.uuid4().hex}_enhanced.png"
420
+ result_url = upload_to_spaces(result_bytes, result_key, content_type="image/png")
421
 
422
+ # Log
423
+ end_time = datetime.utcnow()
424
+ response_time = (end_time - start_time).total_seconds() * 1000
425
+
426
+ if database:
427
+ await database.api_logs.insert_one({
428
+ "endpoint": "/face-swap",
429
+ "status": "success",
430
+ "response_time_ms": response_time,
431
+ "timestamp": end_time
432
+ })
433
+
434
+ return {"result_key": result_key, "result_url": result_url}
435
+
436
+ except Exception as e:
437
+ end_time = datetime.utcnow()
438
+
439
+ if database:
440
+ await database.api_logs.insert_one({
441
+ "endpoint": "/face-swap",
442
+ "status": "fail",
443
+ "response_time_ms": (end_time - start_time).total_seconds() * 1000,
444
+ "timestamp": end_time,
445
+ "error": str(e)
446
+ })
447
+
448
+ raise HTTPException(500, f"Face swap failed: {str(e)}")
449
+
450
+
451
+
452
+
453
+
454
+ #-------------------------------------------------------------------------------------------------------------------------------#
455
+ ####OLD CODE------------------------------------------------------------------------------------
456
+ # @fastapi_app.post("/face-swap", dependencies=[Depends(verify_token)])
457
+ # async def face_swap_api(
458
+ # source: UploadFile = File(...),
459
+ # target_category_id: str = Form(...),
460
+ # credentials: HTTPAuthorizationCredentials = Security(security)
461
+ # ):
462
+ # start_time = datetime.utcnow() # start timer
463
+ # try:
464
+ # # Read source image
465
+ # src_bytes = await source.read()
466
+
467
+ # # Save source to Spaces
468
+ # src_key = f"faceswap/source/{uuid.uuid4().hex}_{source.filename}"
469
+ # upload_to_spaces(src_bytes, src_key, content_type=source.content_type)
470
+
471
+ # # Find target image URL from categoryId
472
+ # client = get_spaces_client()
473
+ # base_prefix = "faceswap/target/"
474
+ # resp = client.list_objects_v2(Bucket=DO_SPACES_BUCKET, Prefix=base_prefix, Delimiter="/")
475
+ # categories = [prefix["Prefix"].split("/")[2] for prefix in resp.get("CommonPrefixes", [])]
476
+ # target_url = None
477
+ # for category in categories:
478
+ # original_prefix = f"faceswap/target/{category}/original/"
479
+ # thumb_prefix = f"faceswap/target/{category}/thumb/"
480
+ # original_objects = client.list_objects_v2(Bucket=DO_SPACES_BUCKET, Prefix=original_prefix)
481
+ # thumb_objects = client.list_objects_v2(Bucket=DO_SPACES_BUCKET, Prefix=thumb_prefix)
482
+ # original_files = [obj["Key"].split("/")[-1] for obj in original_objects.get("Contents", []) if obj["Key"].endswith(".png")]
483
+ # thumb_files = [obj["Key"].split("/")[-1] for obj in thumb_objects.get("Contents", []) if obj["Key"].endswith(".png")]
484
+ # for idx, filename in enumerate(sorted(original_files), start=1):
485
+ # cid = f"{category.lower()}image_{idx}"
486
+ # if filename in thumb_files and cid == target_category_id:
487
+ # target_url = f"https://{DO_SPACES_BUCKET}.blr1.digitaloceanspaces.com/{original_prefix}{filename}"
488
+ # break
489
+ # if target_url:
490
+ # break
491
+ # if not target_url:
492
+ # raise HTTPException(status_code=404, detail="Target categoryId not found")
493
+
494
+ # # Download target image from Spaces
495
+ # resp = requests.get(target_url)
496
+ # if resp.status_code != 200:
497
+ # raise HTTPException(status_code=404, detail="Target image not found in Spaces")
498
+ # tgt_bytes = resp.content
499
+
500
+ # # Decode for processing
501
+ # src_array = np.frombuffer(src_bytes, np.uint8)
502
+ # tgt_array = np.frombuffer(tgt_bytes, np.uint8)
503
+ # src_bgr = cv2.imdecode(src_array, cv2.IMREAD_COLOR)
504
+ # tgt_bgr = cv2.imdecode(tgt_array, cv2.IMREAD_COLOR)
505
  # if src_bgr is None or tgt_bgr is None:
506
+ # raise HTTPException(status_code=400, detail="Invalid image data")
507
 
508
  # src_rgb = cv2.cvtColor(src_bgr, cv2.COLOR_BGR2RGB)
509
  # tgt_rgb = cv2.cvtColor(tgt_bgr, cv2.COLOR_BGR2RGB)
510
 
511
+ # # Run face swap pipeline
 
 
512
  # final_img, final_path, err = face_swap_and_enhance(src_rgb, tgt_rgb)
513
  # if err:
514
+ # raise HTTPException(status_code=500, detail=err)
515
 
516
+ # # Upload result to Spaces
517
  # with open(final_path, "rb") as f:
518
  # result_bytes = f.read()
 
519
  # result_key = f"faceswap/result/{uuid.uuid4().hex}_enhanced.png"
520
+ # result_url = upload_to_spaces(result_bytes, result_key, content_type="image/png")
521
+
522
+ # # Calculate response time
523
  # end_time = datetime.utcnow()
524
  # response_time_ms = (end_time - start_time).total_seconds() * 1000
525
+
526
+ # # Log response time only
527
  # if database is not None:
528
  # await database.api_logs.insert_one({
529
  # "endpoint": "/face-swap",
 
532
  # "timestamp": end_time
533
  # })
534
 
535
+ # return {"result_key": result_key, "result_url": result_url}
 
 
 
 
 
536
 
537
  # except Exception as e:
538
+ # # Log response time even on error
539
  # end_time = datetime.utcnow()
540
  # response_time_ms = (end_time - start_time).total_seconds() * 1000
 
541
  # if database is not None:
542
  # await database.api_logs.insert_one({
543
  # "endpoint": "/face-swap",
 
546
  # "timestamp": end_time,
547
  # "error": str(e)
548
  # })
549
+ # raise HTTPException(status_code=500, detail=f"Face swap failed: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
550
 
551
 
552