Spaces:
Sleeping
Sleeping
Download server/src/utils/cloudinary.py from VashuTheGreat2/ML-Learner: direct link, hf CLI and curl.
- Browser
- Download file 3.16 kB
-
https://huggingface.co/spaces/VashuTheGreat2/ML-Learner/resolve/main/server/src/utils/cloudinary.py
- Command line
-
hf download hf://spaces/VashuTheGreat2/ML-Learner/server/src/utils/cloudinary.py
-
curl -L -o cloudinary.py https://huggingface.co/spaces/VashuTheGreat2/ML-Learner/resolve/main/server/src/utils/cloudinary.py
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 | |