CoolFace
Modelpublic

aigenrec/luminabackend

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
documents.py138 linesDownload Raw Back to endpoints
1import shutil2import os3import uuid4import tempfile5from typing import List6from fastapi import APIRouter, UploadFile, File, HTTPException, BackgroundTasks, Depends, Form, status7from services.document_service import document_service8from models.schemas import DocumentUploadResponse, DocumentList9from config.settings import settings10from api.deps import get_current_user11 12router = APIRouter()13 14@router.post("/upload", response_model=DocumentUploadResponse)15async def upload_document(16    background_tasks: BackgroundTasks,17    file: UploadFile = File(...),18    project_id: str = Form(...),19    current_user: dict = Depends(get_current_user)20):21    """22    Upload a document and start processing it.23    Securely handles file uploads.24    """25    temp_file = None26    try:27        # 1. Validate Project Access (Check ownership)28        # Ideally we check if project exists and belongs to user first.29        # For now, relying on RLS at database level or simple check.30        31        # 2. Validate File Type (MIME & Extension)32        allowed_mimes = [33            "application/pdf",34            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",35            "text/plain"36        ]37        if file.content_type not in allowed_mimes:38            raise HTTPException(status.HTTP_400_BAD_REQUEST, "Invalid file type. Only PDF, DOCX, and TXT are supported.")39        40        file_ext = os.path.splitext(file.filename)[1].lower().replace('.', '')41        if file_ext not in settings.ALLOWED_EXTENSIONS:42             raise HTTPException(status.HTTP_400_BAD_REQUEST, f"Invalid file extension. Allowed: {settings.ALLOWED_EXTENSIONS}")43 44        # 3. Secure Temp File Creation45        # Use tempfile module for safer handling46        temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=f".{file_ext}", dir="temp")47        48        # 4. Stream content to check size49        file_size = 050        chunk_size = 1024 * 1024 # 1MB chunks51        52        while True:53            chunk = await file.read(chunk_size)54            if not chunk:55                break56            file_size += len(chunk)57            if file_size > settings.MAX_FILE_SIZE:58                temp_file.close()59                os.unlink(temp_file.name)60                raise HTTPException(status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, f"File size exceeds limit of {settings.MAX_FILE_SIZE} bytes")61            temp_file.write(chunk)62            63        temp_file.close()64        temp_path = temp_file.name65            66        # 5. Create document record in Supabase67        doc_data = {68            "project_id": project_id,69            "filename": file.filename,70            "file_type": file.content_type,71            "file_size": file_size,72            "upload_status": "pending"73        }74        75        response = document_service.client.table("documents").insert(doc_data).execute()76        77        if not response.data:78            raise HTTPException(500, "Failed to create document record")79            80        document = response.data[0]81        document_id = document["id"]82        83        # 6. Start background processing84        background_tasks.add_task(85            document_service.process_document,86            document_id=document_id,87            project_id=project_id,88            file_path=temp_path,89            filename=file.filename90        )91        92        return document93        94    except HTTPException as he:95        if temp_file and os.path.exists(temp_file.name):96            try:97                os.unlink(temp_file.name)98            except: pass99        raise he100    except Exception as e:101        if temp_file and os.path.exists(temp_file.name):102            try:103                os.unlink(temp_file.name)104            except: pass105        raise HTTPException(500, str(e))106 107@router.get("/{project_id}", response_model=DocumentList)108async def list_documents(109    project_id: str,110    current_user: dict = Depends(get_current_user)111):112    """113    List all documents for a project114    """115    try:116        # Verify project access first ideally, but RLS should handle filtering if configured.117        # Adding manual check for extra safety.118        119        # Basic query120        response = document_service.client.table("documents").select("*").eq("project_id", project_id).execute()121        return {"documents": response.data}122    except Exception as e:123        raise HTTPException(500, str(e))124 125@router.delete("/{document_id}")126async def delete_document(127    document_id: str,128    project_id: str,129    current_user: dict = Depends(get_current_user)130):131    """132    Delete a document133    """134    try:135        await document_service.delete_document(project_id, document_id)136        return {"message": "Document deleted successfully"}137    except Exception as e:138        raise HTTPException(500, str(e))