Update api/main.py
Browse files- api/main.py +42 -4
api/main.py
CHANGED
|
@@ -423,6 +423,24 @@ def _load_rgba_image(path: str) -> Image.Image:
|
|
| 423 |
return img.convert("RGBA")
|
| 424 |
|
| 425 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 426 |
def _load_rgba_mask_from_image(img: Image.Image) -> np.ndarray:
|
| 427 |
"""
|
| 428 |
Convert mask image to RGBA format (black/white mask).
|
|
@@ -477,11 +495,12 @@ def _load_rgba_mask_from_image(img: Image.Image) -> np.ndarray:
|
|
| 477 |
return rgba
|
| 478 |
|
| 479 |
@app.post("/inpaint")
|
| 480 |
-
def inpaint(req: InpaintRequest, _: None = Depends(bearer_auth)) -> Dict[str, str]:
|
| 481 |
start_time = time.time()
|
| 482 |
status = "success"
|
| 483 |
error_msg = None
|
| 484 |
output_name = None
|
|
|
|
| 485 |
|
| 486 |
try:
|
| 487 |
if req.image_id not in file_store or file_store[req.image_id]["type"] != "image":
|
|
@@ -510,8 +529,21 @@ def inpaint(req: InpaintRequest, _: None = Depends(bearer_auth)) -> Dict[str, st
|
|
| 510 |
output_path, "PNG", optimize=False, compress_level=1
|
| 511 |
)
|
| 512 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 513 |
log_media_click(req.user_id, req.category_id)
|
| 514 |
-
|
|
|
|
|
|
|
|
|
|
| 515 |
|
| 516 |
except Exception as e:
|
| 517 |
status = "fail"
|
|
@@ -949,7 +981,6 @@ def view_result(filename: str):
|
|
| 949 |
@app.get("/logs")
|
| 950 |
def get_logs(_: None = Depends(bearer_auth)) -> JSONResponse:
|
| 951 |
return JSONResponse(content=logs)
|
| 952 |
-
|
| 953 |
# import os
|
| 954 |
# import uuid
|
| 955 |
# import shutil
|
|
@@ -1145,6 +1176,14 @@ def get_logs(_: None = Depends(bearer_auth)) -> JSONResponse:
|
|
| 1145 |
# }
|
| 1146 |
# )
|
| 1147 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1148 |
# # Enforce 32-entry limit (keep the most recent 32 days)
|
| 1149 |
# if len(result) > 32:
|
| 1150 |
# result = result[-32:]
|
|
@@ -1269,7 +1308,6 @@ def get_logs(_: None = Depends(bearer_auth)) -> JSONResponse:
|
|
| 1269 |
# ],
|
| 1270 |
# "createdAt": now,
|
| 1271 |
# "updatedAt": now,
|
| 1272 |
-
# "ai_edit_complete": 0, # Default for new users
|
| 1273 |
# "ai_edit_daily_count": daily_for_new,
|
| 1274 |
# },
|
| 1275 |
# "$inc": {"ai_edit_complete": 1}, # Increment to 1 on first use
|
|
|
|
| 423 |
return img.convert("RGBA")
|
| 424 |
|
| 425 |
|
| 426 |
+
def _compress_image(image_path: str, output_path: str, quality: int = 85) -> None:
|
| 427 |
+
"""
|
| 428 |
+
Compress an image to reduce file size.
|
| 429 |
+
Converts to JPEG format with specified quality to achieve smaller file size.
|
| 430 |
+
"""
|
| 431 |
+
img = Image.open(image_path)
|
| 432 |
+
# Convert RGBA to RGB if needed (JPEG doesn't support alpha)
|
| 433 |
+
if img.mode == "RGBA":
|
| 434 |
+
rgb_img = Image.new("RGB", img.size, (255, 255, 255))
|
| 435 |
+
rgb_img.paste(img, mask=img.split()[3]) # Use alpha channel as mask
|
| 436 |
+
img = rgb_img
|
| 437 |
+
elif img.mode != "RGB":
|
| 438 |
+
img = img.convert("RGB")
|
| 439 |
+
|
| 440 |
+
# Save as JPEG with quality setting for compression
|
| 441 |
+
img.save(output_path, "JPEG", quality=quality, optimize=True)
|
| 442 |
+
|
| 443 |
+
|
| 444 |
def _load_rgba_mask_from_image(img: Image.Image) -> np.ndarray:
|
| 445 |
"""
|
| 446 |
Convert mask image to RGBA format (black/white mask).
|
|
|
|
| 495 |
return rgba
|
| 496 |
|
| 497 |
@app.post("/inpaint")
|
| 498 |
+
def inpaint(req: InpaintRequest, request: Request, _: None = Depends(bearer_auth)) -> Dict[str, str]:
|
| 499 |
start_time = time.time()
|
| 500 |
status = "success"
|
| 501 |
error_msg = None
|
| 502 |
output_name = None
|
| 503 |
+
compressed_url = None
|
| 504 |
|
| 505 |
try:
|
| 506 |
if req.image_id not in file_store or file_store[req.image_id]["type"] != "image":
|
|
|
|
| 529 |
output_path, "PNG", optimize=False, compress_level=1
|
| 530 |
)
|
| 531 |
|
| 532 |
+
# Create compressed version
|
| 533 |
+
compressed_name = f"compressed_{output_name.replace('.png', '.jpg')}"
|
| 534 |
+
compressed_path = os.path.join(OUTPUT_DIR, compressed_name)
|
| 535 |
+
try:
|
| 536 |
+
_compress_image(output_path, compressed_path, quality=85)
|
| 537 |
+
compressed_url = str(request.url_for("download_file", filename=compressed_name))
|
| 538 |
+
except Exception as compress_err:
|
| 539 |
+
log.warning("Failed to create compressed image: %s", compress_err)
|
| 540 |
+
compressed_url = None
|
| 541 |
+
|
| 542 |
log_media_click(req.user_id, req.category_id)
|
| 543 |
+
response = {"result": output_name}
|
| 544 |
+
if compressed_url:
|
| 545 |
+
response["Compressed_Image_URL"] = compressed_url
|
| 546 |
+
return response
|
| 547 |
|
| 548 |
except Exception as e:
|
| 549 |
status = "fail"
|
|
|
|
| 981 |
@app.get("/logs")
|
| 982 |
def get_logs(_: None = Depends(bearer_auth)) -> JSONResponse:
|
| 983 |
return JSONResponse(content=logs)
|
|
|
|
| 984 |
# import os
|
| 985 |
# import uuid
|
| 986 |
# import shutil
|
|
|
|
| 1176 |
# }
|
| 1177 |
# )
|
| 1178 |
|
| 1179 |
+
# # Sort by date ascending (older dates first) to guarantee stable ordering:
|
| 1180 |
+
# # [oldest, ..., newest]
|
| 1181 |
+
# try:
|
| 1182 |
+
# result.sort(key=lambda entry: _to_date_only(entry.get("date")))
|
| 1183 |
+
# except Exception:
|
| 1184 |
+
# # If anything goes wrong during sort, fall back to current ordering
|
| 1185 |
+
# pass
|
| 1186 |
+
|
| 1187 |
# # Enforce 32-entry limit (keep the most recent 32 days)
|
| 1188 |
# if len(result) > 32:
|
| 1189 |
# result = result[-32:]
|
|
|
|
| 1308 |
# ],
|
| 1309 |
# "createdAt": now,
|
| 1310 |
# "updatedAt": now,
|
|
|
|
| 1311 |
# "ai_edit_daily_count": daily_for_new,
|
| 1312 |
# },
|
| 1313 |
# "$inc": {"ai_edit_complete": 1}, # Increment to 1 on first use
|