from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, func, desc from typing import Optional import base64 import os from app.database import get_db from app.models.user import User from app.models.document import Document from app.schemas.document import ScanRequest, DocumentResponse, DocumentListResponse from app.services.ai_service import analyze_document from app.utils.security import get_current_user from app.config import settings router = APIRouter(prefix="/api/documents", tags=["documents"]) @router.post("/scan", response_model=DocumentResponse) async def scan_document( req: ScanRequest, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db) ): # Check scan limit for free users if user.plan == "free" and user.scan_count_today >= settings.FREE_SCAN_LIMIT: raise HTTPException(status_code=429, detail="Limite de scans diários atingido. Faça upgrade para Premium.") # Calculate file size image_data = req.image if "," in image_data: image_data_clean = image_data.split(",", 1)[1] else: image_data_clean = image_data file_size = len(base64.b64decode(image_data_clean)) # AI analysis try: result = await analyze_document(req.image) except Exception as e: raise HTTPException(status_code=500, detail=f"Erro na análise IA: {str(e)}") # Save document doc = Document( user_id=user.id, title=result.get("title", "Documento sem título"), category=result.get("category", "outro"), original_image=req.image, extracted_text=result.get("extracted_text", ""), summary=result.get("summary", ""), extracted_data=result.get("extracted_data", {}), risk_alerts=result.get("risk_alerts", []), tags=result.get("tags", []), file_size=file_size ) db.add(doc) # Update scan count user.scan_count_today += 1 await db.commit() await db.refresh(doc) return DocumentResponse( id=doc.id, title=doc.title, category=doc.category, extracted_text=doc.extracted_text, summary=doc.summary, extracted_data=doc.extracted_data, risk_alerts=doc.risk_alerts, tags=doc.tags, file_size=doc.file_size, created_at=doc.created_at ) @router.get("/", response_model=DocumentListResponse) async def list_documents( search: Optional[str] = None, category: Optional[str] = None, page: int = Query(1, ge=1), limit: int = Query(20, ge=1, le=100), user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db) ): query = select(Document).where(Document.user_id == user.id) count_query = select(func.count(Document.id)).where(Document.user_id == user.id) if category: query = query.where(Document.category == category) count_query = count_query.where(Document.category == category) if search: search_filter = Document.extracted_text.ilike(f"%{search}%") query = query.where(search_filter) count_query = count_query.where(search_filter) total = (await db.execute(count_query)).scalar() result = await db.execute(query.order_by(desc(Document.created_at)).offset((page-1)*limit).limit(limit)) docs = result.scalars().all() return DocumentListResponse( documents=[DocumentResponse( id=d.id, title=d.title, category=d.category, extracted_text=d.extracted_text, summary=d.summary, extracted_data=d.extracted_data, risk_alerts=d.risk_alerts, tags=d.tags, file_size=d.file_size, created_at=d.created_at ) for d in docs], total=total ) @router.get("/{doc_id}", response_model=DocumentResponse) async def get_document( doc_id: int, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db) ): result = await db.execute(select(Document).where(Document.id == doc_id, Document.user_id == user.id)) doc = result.scalar_one_or_none() if not doc: raise HTTPException(status_code=404, detail="Documento não encontrado") return DocumentResponse( id=doc.id, title=doc.title, category=doc.category, extracted_text=doc.extracted_text, summary=doc.summary, extracted_data=doc.extracted_data, risk_alerts=doc.risk_alerts, tags=doc.tags, file_size=doc.file_size, created_at=doc.created_at ) @router.get("/{doc_id}/image") async def get_document_image( doc_id: int, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db) ): result = await db.execute(select(Document).where(Document.id == doc_id, Document.user_id == user.id)) doc = result.scalar_one_or_none() if not doc: raise HTTPException(status_code=404, detail="Documento não encontrado") return {"image": doc.original_image} @router.delete("/{doc_id}") async def delete_document( doc_id: int, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db) ): result = await db.execute(select(Document).where(Document.id == doc_id, Document.user_id == user.id)) doc = result.scalar_one_or_none() if not doc: raise HTTPException(status_code=404, detail="Documento não encontrado") await db.delete(doc) await db.commit() return {"message": "Documento excluído"}