Spaces:
Sleeping
Sleeping
File size: 2,785 Bytes
35d761c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | # backend/app/api/upload.py
from fastapi import APIRouter, UploadFile, File, HTTPException, Depends
import os
import tempfile
import csv
import io
from app.models.schemas import Transaction, UploadResponse
from app.ai.extraction_agent import extract_text_from_pdf, parse_text_to_json, extract_all_transaction
from app.api.rate_limiter import upload_rate_limiter
router = APIRouter()
@router.post("/", response_model=UploadResponse, dependencies=[Depends(upload_rate_limiter)])
async def upload_document(file: UploadFile = File(...)):
"""Receives a CSV file, performs security validation, and parses it into structured data."""
transactions = []
try:
# --- SECURITY VERIFICATION ---
MAX_FILE_SIZE = 5 * 1024 * 1024 # 5 MB
# 1. Validate Extension & MIME Type to prevent malicious scripts
if not file.filename.lower().endswith('.csv') or file.content_type not in ["text/csv", "application/vnd.ms-excel"]:
raise HTTPException(status_code=400, detail="Security Error: Only valid CSV files are allowed.")
contents = await file.read()
# 2. Prevent massive files from crashing memory
if len(contents) > MAX_FILE_SIZE:
raise HTTPException(status_code=413, detail="File too large. Maximum size is 5MB.")
# --- PATH 1: The CSV Fast-Track ---
print(f"✅ Fast-Track triggered for CSV: {file.filename}")
# Use utf-8-sig to handle Excel BOM characters automatically!
decoded_contents = contents.decode('utf-8-sig')
reader = csv.DictReader(io.StringIO(decoded_contents))
print(f"🔍 CSV Headers detected: {reader.fieldnames}")
for row in reader:
# Convert all keys in the row to lowercase and strip whitespace
lower_row = {k.lower().strip() if k else '': str(v).strip() for k, v in row.items()}
raw_amount = lower_row.get('amount', '0').replace('$', '').replace(',', '')
txn = Transaction(
date=lower_row.get('date', ''),
description=lower_row.get('description', ''),
amount=float(raw_amount) if raw_amount else 0.0
)
transactions.append(txn)
print(f"🎯 Total transactions parsed from CSV: {len(transactions)}")
# (PDF Parsing hidden for MVP)
return {
"message": "Upload & Extraction successful",
"transaction_count": len(transactions),
"preview": transactions[:3],
"transactions": transactions
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error processing file: {str(e)}") |