53 lines
1.6 KiB
Python
53 lines
1.6 KiB
Python
"""Document storage service."""
|
|
|
|
import shutil
|
|
import uuid
|
|
import pymupdf
|
|
from pathlib import Path
|
|
from fastapi import UploadFile, HTTPException
|
|
|
|
from app.config import settings
|
|
|
|
def validate_pdf(filepath: Path) -> None:
|
|
"""Validate PDF magic bytes and PyMuPDF openability."""
|
|
with open(filepath, "rb") as f:
|
|
header = f.read(5)
|
|
if header != b"%PDF-":
|
|
raise ValueError("Not a valid PDF file (missing magic bytes)")
|
|
|
|
try:
|
|
doc = pymupdf.open(filepath)
|
|
doc.close()
|
|
except Exception as e:
|
|
raise ValueError(f"Failed to open PDF with PyMuPDF: {e}")
|
|
|
|
async def save_upload_file(upload_file: UploadFile) -> tuple[str, int, int]:
|
|
"""Save an uploaded file to disk and validate it."""
|
|
file_id = str(uuid.uuid4())
|
|
filepath = settings.PDF_STORAGE_PATH / f"{file_id}.pdf"
|
|
|
|
try:
|
|
with open(filepath, "wb") as f:
|
|
shutil.copyfileobj(upload_file.file, f)
|
|
except Exception as e:
|
|
if filepath.exists():
|
|
filepath.unlink()
|
|
raise HTTPException(status_code=500, detail="Failed to save file")
|
|
|
|
page_count = 0
|
|
try:
|
|
doc = pymupdf.open(filepath)
|
|
page_count = len(doc)
|
|
doc.close()
|
|
except Exception as e:
|
|
filepath.unlink()
|
|
raise HTTPException(status_code=400, detail=f"Failed to open PDF with PyMuPDF: {e}")
|
|
|
|
size = filepath.stat().st_size
|
|
return file_id, size, page_count
|
|
|
|
def delete_pdf_file(file_id: str) -> None:
|
|
"""Delete a PDF file from storage."""
|
|
filepath = settings.PDF_STORAGE_PATH / f"{file_id}.pdf"
|
|
if filepath.exists():
|
|
filepath.unlink()
|