from fastapi import FastAPI, File, UploadFile, HTTPException from fastapi.responses import FileResponse from fastapi.middleware.cors import CORSMiddleware import os import tempfile import shutil from pdf2docx import Converter import uvicorn app = FastAPI(title="PDF to Word Converter API") # CORS configuration for Next.js app.add_middleware( CORSMiddleware, allow_origins=["*"], # In production, replace with your Next.js domain allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Create temp directory if it doesn't exist TEMP_DIR = "/tmp/conversions" os.makedirs(TEMP_DIR, exist_ok=True) @app.get("/") def read_root(): return { "message": "PDF to Word Converter API", "endpoints": { "/convert": "POST - Upload PDF to convert to Word", "/health": "GET - Health check" } } @app.get("/health") def health_check(): return {"status": "healthy"} @app.post("/convert") async def convert_pdf_to_word(file: UploadFile = File(...)): """ Convert uploaded PDF file to Word document """ # Validate file type if not file.filename.endswith('.pdf'): raise HTTPException(status_code=400, detail="Only PDF files are allowed") # Create unique temporary files temp_pdf = tempfile.NamedTemporaryFile(delete=False, suffix='.pdf', dir=TEMP_DIR) temp_docx = tempfile.NamedTemporaryFile(delete=False, suffix='.docx', dir=TEMP_DIR) try: # Save uploaded PDF content = await file.read() temp_pdf.write(content) temp_pdf.close() # Convert PDF to DOCX cv = Converter(temp_pdf.name) cv.convert(temp_docx.name) cv.close() # Get original filename without extension original_name = os.path.splitext(file.filename)[0] output_filename = f"{original_name}.docx" # Return the converted file return FileResponse( temp_docx.name, media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document", filename=output_filename, background=None ) except Exception as e: # Clean up on error if os.path.exists(temp_pdf.name): os.unlink(temp_pdf.name) if os.path.exists(temp_docx.name): os.unlink(temp_docx.name) raise HTTPException(status_code=500, detail=f"Conversion failed: {str(e)}") finally: # Schedule cleanup (files will be removed after response is sent) if os.path.exists(temp_pdf.name): try: os.unlink(temp_pdf.name) except: pass if __name__ == "__main__": port = int(os.environ.get("PORT", 7860)) uvicorn.run(app, host="0.0.0.0", port=port)