Fill-the-Frames / backend /app /api /upload.py
sid385's picture
feat(backend): organize huggingface bucket folders and add geographical reprojection
f409028
Raw
History Blame Contribute Delete
3.96 kB
import asyncio
from pathlib import Path
from typing import List
from fastapi import APIRouter, File, HTTPException, UploadFile
from huggingface_hub import HfFileSystem
from app.core.config import HF_BUCKET_ID, HF_TOKEN
from app.schemas.common import ApiResponse
from app.services.upload_service import UploadService
router = APIRouter()
# Initialize Hugging Face File System
fs = HfFileSystem(token=HF_TOKEN)
# 🚨 FIX: Do add ki gayi hai trailing slash error se bachne ke liye
@router.post("/", response_model=ApiResponse)
async def upload_file(file: UploadFile = File(...)):
"""
Upload a single satellite dataset (.nc, .h5, .hdf5) to the server.
"""
try:
upload_data = await UploadService.process_upload(file)
return ApiResponse(
success=True,
message="Dataset uploaded successfully",
data=upload_data.model_dump(by_alias=True),
)
except HTTPException as he:
raise he
except Exception as e:
return ApiResponse(success=False, message=f"Upload failed: {str(e)}", data=None)
@router.post("/batch", response_model=ApiResponse)
async def upload_multiple_files(files: List[UploadFile] = File(...)):
"""
Upload multiple satellite datasets at once.
"""
try:
tasks = [UploadService.process_upload(file) for file in files]
results = await asyncio.gather(*tasks)
return ApiResponse(
success=True,
message=f"{len(results)} files uploaded successfully",
data=[res.model_dump(by_alias=True) for res in results],
)
except HTTPException as he:
raise he
except Exception as e:
return ApiResponse(
success=False, message=f"Batch upload failed: {str(e)}", data=None
)
# 🚨 FIX: Double routing yahan bhi
@router.get("/", response_model=ApiResponse)
async def list_uploaded_files():
"""
Get a list of all uploaded dataset folders and their sizes directly from Hugging Face.
"""
try:
bucket_path = f"hf://buckets/{HF_BUCKET_ID}/uploads/"
if not fs.exists(bucket_path):
return ApiResponse(success=True, message="No files uploaded yet", data=[])
folders = fs.ls(bucket_path, detail=False)
files_info = []
for folder_path in folders:
folder_name = Path(folder_path).name # The UUID
inner_files = fs.glob(f"{folder_path}/*")
if inner_files:
actual_file = inner_files[0]
file_metadata = fs.info(actual_file)
files_info.append(
{
"fileId": folder_name,
"filename": Path(actual_file).name,
"size_bytes": file_metadata.get("size", 0),
}
)
return ApiResponse(
success=True,
message="Files retrieved successfully",
data=files_info,
)
except Exception as e:
return ApiResponse(
success=False, message=f"Failed to list files: {str(e)}", data=[]
)
@router.delete("/{file_id}", response_model=ApiResponse)
async def delete_file(file_id: str):
"""
Delete an uploaded dataset from Hugging Face Bucket to clear space.
"""
remote_dir = f"hf://buckets/{HF_BUCKET_ID}/uploads/{file_id}"
# Fallback to legacy root check
if not fs.exists(remote_dir):
remote_dir = f"hf://buckets/{HF_BUCKET_ID}/{file_id}"
if not fs.exists(remote_dir):
raise HTTPException(status_code=404, detail="File directory not found in cloud")
try:
fs.rm(remote_dir, recursive=True)
return ApiResponse(
success=True,
message=f"File {file_id} deleted successfully from cloud",
data=None,
)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Could not delete file: {str(e)}")