ML-Learner / server /src /utils /cloudinary.py
VashuTheGreat2's picture
Upload folder using huggingface_hub
0225ffc verified
Raw History Blame Contribute Delete
3.16 kB
import asyncio
import os
import shutil
import uuid
from fastapi import UploadFile
from config.app_config import app_config
from src.constants import PUBLIC_TEMP_DIR
import cloudinary
import cloudinary.uploader
# Configure Cloudinary
cloudinary.config(
cloud_name=app_config.cloudinary_cloud_name,
api_key=app_config.cloudinary_api_key,
api_secret=app_config.cloudinary_api_secret,
secure=True
)
def extract_public_id(url: str) -> str | None:
"""
Extracts the public_id from a Cloudinary URL.
E.g., https://res.cloudinary.com/cloud_name/image/upload/v1234567/avatars/abc123xyz.png -> avatars/abc123xyz
"""
if not url or "res.cloudinary.com" not in url:
return None
try:
parts = url.split("/upload/")
if len(parts) < 2:
return None
# Remove version prefix (e.g. v1619000000/) if present
subparts = parts[1].split("/", 1)
if len(subparts) < 2:
return None
path_with_ext = subparts[1]
public_id = os.path.splitext(path_with_ext)[0]
return public_id
except Exception:
return None
async def upload_avatar_to_cloudinary(file: UploadFile) -> str:
"""
Saves an uploaded file locally to the public temp directory,
uploads it to Cloudinary, deletes the local file, and returns the Cloudinary URL.
"""
# Ensure public/temp directory exists
os.makedirs(PUBLIC_TEMP_DIR, exist_ok=True)
# Create a unique file name to avoid collisions
file_extension = os.path.splitext(file.filename)[1] if file.filename else ".jpg"
unique_filename = f"{uuid.uuid4()}{file_extension}"
temp_file_path = os.path.join(PUBLIC_TEMP_DIR, unique_filename)
try:
# Save file locally in public/temp
with open(temp_file_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
# Upload to Cloudinary using threadpool to keep it async
upload_result = await asyncio.to_thread(
cloudinary.uploader.upload,
temp_file_path,
folder="avatars"
)
secure_url = upload_result.get("secure_url")
if not secure_url:
raise Exception("Cloudinary upload failed: secure_url was not returned.")
return secure_url
finally:
# Delete local file after upload
if os.path.exists(temp_file_path):
os.remove(temp_file_path)
async def delete_avatar_from_cloudinary(url: str) -> bool:
"""
Deletes an asset from Cloudinary using its secure URL.
"""
public_id = extract_public_id(url)
if not public_id:
print(f"[DEBUG] Could not extract public_id from url: {url}")
return False
try:
result = await asyncio.to_thread(
cloudinary.uploader.destroy,
public_id,
invalidate=True
)
print(f"[DEBUG] Cloudinary destroy result for {public_id}: {result}")
return result.get("result") == "ok"
except Exception as e:
print(f"[ERROR] Failed to delete image from Cloudinary: {e}")
return False