LocalMate / app /upload /__init__.py
Cuong2004's picture
add user endpoint + image handling
d7a7993
"""Upload Router - Image upload to Supabase Storage."""
import uuid
from datetime import datetime
from fastapi import APIRouter, UploadFile, File, HTTPException
from pydantic import BaseModel, Field
from app.shared.integrations.supabase_client import supabase
from app.core.config import settings
router = APIRouter(prefix="/upload", tags=["Upload"])
# Supabase Storage bucket name
BUCKET_NAME = "image"
# Allowed image types
ALLOWED_TYPES = {"image/jpeg", "image/png", "image/webp", "image/gif"}
MAX_SIZE_MB = 10
class UploadResponse(BaseModel):
"""Upload response model."""
url: str = Field(..., description="Public URL of uploaded image")
path: str = Field(..., description="Storage path")
size: int = Field(..., description="File size in bytes")
content_type: str = Field(..., description="MIME type")
@router.post(
"/image",
response_model=UploadResponse,
summary="Upload image to storage",
description="""
Upload an image file to Supabase Storage.
Returns a public URL that can be used with `/chat` endpoint's `image_url` parameter.
Supported formats: JPEG, PNG, WebP, GIF
Max size: 10MB
""",
)
async def upload_image(
file: UploadFile = File(..., description="Image file to upload"),
user_id: str = "anonymous",
) -> UploadResponse:
"""Upload image to Supabase Storage and return public URL."""
# Validate content type
if file.content_type not in ALLOWED_TYPES:
raise HTTPException(
status_code=400,
detail=f"Invalid file type. Allowed: {', '.join(ALLOWED_TYPES)}"
)
# Read file content
content = await file.read()
# Validate size
size = len(content)
if size > MAX_SIZE_MB * 1024 * 1024:
raise HTTPException(
status_code=400,
detail=f"File too large. Max size: {MAX_SIZE_MB}MB"
)
# Generate unique filename
ext = file.filename.split(".")[-1] if file.filename and "." in file.filename else "jpg"
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
unique_id = str(uuid.uuid4())[:8]
filename = f"{user_id}/{timestamp}_{unique_id}.{ext}"
try:
# Upload to Supabase Storage
result = supabase.storage.from_(BUCKET_NAME).upload(
path=filename,
file=content,
file_options={"content-type": file.content_type}
)
# Get public URL
public_url = supabase.storage.from_(BUCKET_NAME).get_public_url(filename)
return UploadResponse(
url=public_url,
path=filename,
size=size,
content_type=file.content_type,
)
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Upload failed: {str(e)}"
)