from fastapi import FastAPI, File, UploadFile, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse import pdfplumber from io import BytesIO import base64 import uvicorn import logging # Set up logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) app = FastAPI() # Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Root route @app.get("/") async def root(): return {"message": "PDF to Figma API"} @app.post("/api/convert") async def convert_pdf(file: UploadFile = File(...)): try: logger.info("Received file: %s", file.filename) # Read the uploaded file contents = await file.read() if not contents: logger.error("Empty file uploaded") raise HTTPException(status_code=400, detail="Empty file uploaded") # Parse PDF with pdfplumber with pdfplumber.open(BytesIO(contents)) as pdf: if not pdf.pages: logger.error("No pages found in PDF") raise HTTPException(status_code=400, detail="No pages found in PDF") page = pdf.pages[0] # First page width, height = page.width, page.height logger.info("Processing PDF page: width=%s, height=%s", width, height) # Initialize result result = { "width": width, "height": height, "texts": [], "images": [], "shapes": [] } # Extract text for char in page.chars: result["texts"].append({ "content": char["text"], "x": char["x0"], "y": char["y0"], "font_family": char["fontname"].split("+")[-1] or "Arial", "font_style": "Regular", "font_size": char["size"], "color": {"r": 0, "g": 0, "b": 0} }) # Extract images for img in page.images: try: img_data = img["stream"].get_data() result["images"].append({ "data": list(img_data), "x": img["x0"], "y": img["y0"], "width": img["width"], "height": img["height"] }) except Exception as e: logger.warning("Failed to extract image: %s", str(e)) continue # Extract shapes for curve in page.curves: try: path = " ".join([f"M {p['x']},{p['y']}" for p in curve["points"]]) result["shapes"].append({ "path": path, "x": curve["x0"], "y": curve["y0"], "color": {"r": 0, "g": 0, "b": 0} }) except Exception as e: logger.warning("Failed to extract shape: %s", str(e)) continue logger.info("PDF processing complete") return JSONResponse(content=result) except Exception as e: logger.error("Failed to process PDF: %s", str(e)) raise HTTPException(status_code=500, detail=f"Failed to process PDF: {str(e)}") finally: await file.close() # Run uvicorn server if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=7860)