Spaces:
Sleeping
Sleeping
File size: 4,680 Bytes
ef7075f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | import asyncio
from fastapi import APIRouter, Form, HTTPException, Request, Depends
from src.core.config import DEFAULT_PINECONE_KEY, IDX_FACES, IDX_OBJECTS
from src.core.security import get_verified_keys
from src.services.db_client import (
cld_delete_folder_resources, cld_delete_resource, cld_list_folder_images,
cld_remove_folder, cld_root_folders, pinecone_pool,
)
from src.core.logging import log, warn
from src.common.utils import cld_thumb_url, get_ip, url_to_public_id
router = APIRouter()
@router.post("/api/categories")
async def get_categories(
request: Request,
user_id: str = Form(""),
keys: dict = Depends(get_verified_keys)
):
ip = get_ip(request)
try:
result = await asyncio.to_thread(cld_root_folders, keys["cloudinary_creds"])
categories = [f["name"] for f in result.get("folders", [])]
log("INFO", "categories.fetched", user_id=user_id or "anonymous", ip=ip, count=len(categories))
return {"categories": categories}
except Exception as e:
log("ERROR", "categories.error", user_id=user_id or "anonymous", ip=ip, error=str(e))
return {"categories": []}
@router.post("/api/cloudinary/folder-images")
async def list_folder_images(
request: Request,
folder_name: str = Form(...),
user_id: str = Form(""),
next_cursor: str = Form(""),
page_size: int = Form(100),
keys: dict = Depends(get_verified_keys)
):
ip = get_ip(request)
result = await asyncio.to_thread(
cld_list_folder_images,
folder_name, keys["cloudinary_creds"], next_cursor or None, page_size,
)
images = [
{
"url": r["secure_url"],
"thumb_url": cld_thumb_url(r["secure_url"]),
"public_id": r["public_id"],
}
for r in result.get("resources", [])
]
next_cur = result.get("next_cursor") or ""
log("INFO", "explorer.folder_opened", user_id=user_id or "anonymous", ip=ip,
folder=folder_name, count=len(images), has_more=bool(next_cur))
return {"images": images, "count": len(images), "next_cursor": next_cur}
@router.post("/api/delete-image")
async def delete_image(
request: Request,
image_url: str = Form(""),
public_id: str = Form(""),
user_id: str = Form(""),
keys: dict = Depends(get_verified_keys)
):
ip = get_ip(request)
pid = public_id or url_to_public_id(image_url)
if not pid:
raise HTTPException(400, "Could not determine public_id.")
await asyncio.to_thread(cld_delete_resource, pid, keys["cloudinary_creds"])
try:
pc = pinecone_pool.get(keys["pinecone_key"])
for idx_name in [IDX_OBJECTS, IDX_FACES]:
await asyncio.to_thread(
pc.Index(idx_name).delete, filter={"url": {"$eq": image_url}}
)
except Exception as e:
warn(f"Pinecone delete warning: {e}")
log("INFO", "explorer.image_deleted", user_id=user_id or "anonymous", ip=ip, image_url=image_url, public_id=pid)
return {"message": "Image deleted successfully."}
@router.post("/api/delete-folder")
async def delete_folder(
request: Request,
folder_name: str = Form(...),
user_id: str = Form(""),
keys: dict = Depends(get_verified_keys)
):
ip = get_ip(request)
all_images, cursor = [], None
while True:
result = await asyncio.to_thread(cld_list_folder_images, folder_name, keys["cloudinary_creds"], cursor)
all_images.extend(result.get("resources", []))
cursor = result.get("next_cursor")
if not cursor:
break
await asyncio.to_thread(cld_delete_folder_resources, folder_name, keys["cloudinary_creds"])
await asyncio.to_thread(cld_remove_folder, folder_name, keys["cloudinary_creds"])
try:
pc = pinecone_pool.get(keys["pinecone_key"])
for idx_name in [IDX_OBJECTS, IDX_FACES]:
idx = pc.Index(idx_name)
try:
await asyncio.to_thread(idx.delete, filter={"folder": {"$eq": folder_name}})
except Exception:
for img in all_images:
url = img.get("secure_url", "")
if url:
try:
await asyncio.to_thread(idx.delete, filter={"url": {"$eq": url}})
except Exception:
pass
except Exception as e:
warn(f"Pinecone folder delete warning: {e}")
log("INFO", "explorer.folder_deleted", user_id=user_id or "anonymous", ip=ip, folder=folder_name, deleted_count=len(all_images))
return {"message": f"Folder '{folder_name}' and contents deleted.", "deleted_count": len(all_images)} |