from fastapi import FastAPI, UploadFile, File, Form, HTTPException from fastapi.responses import StreamingResponse, JSONResponse from core.renderer import ExcelRenderer import io import logging # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) app = FastAPI( title="Excel2Pic API", description="A lightweight service to convert Excel sheets to images.", version="0.1.0" ) @app.post("/api/v1/convert", summary="Convert Excel to Image") async def convert_excel( file: UploadFile = File(..., description="The Excel file to convert"), sheet_name: str = Form(None, description="Name of the sheet to convert (optional, defaults to active sheet)"), scale: int = Form(3, description="Scaling factor for high-DPI rendering (default 3, best for mobile/retina screens)"), ): """ Convert an uploaded Excel file to a PNG image. """ # Validation if not file.filename.endswith(('.xlsx', '.xls')): raise HTTPException(status_code=400, detail="Invalid file format. Please upload .xlsx or .xls file.") try: # Read file content contents = await file.read() # Initialize Renderer # Note: In a real deployment, font paths might come from env vars renderer = ExcelRenderer(contents) # Render # Use scale parameter image_bytes = renderer.render_to_bytes(sheet_name=sheet_name, scale=scale) # Return as streaming response # Handle Chinese filenames in Content-Disposition from urllib.parse import quote filename = file.filename.split('.')[0] + ".png" encoded_filename = quote(filename) return StreamingResponse( io.BytesIO(image_bytes), media_type="image/png", headers={"Content-Disposition": f"inline; filename*=utf-8''{encoded_filename}"} ) except ValueError as ve: # Often raised when sheet name is not found logger.warning(f"Value Error: {str(ve)}") raise HTTPException(status_code=400, detail=str(ve)) except Exception as e: logger.error(f"Internal Server Error: {str(e)}", exc_info=True) raise HTTPException(status_code=500, detail=f"An error occurred during conversion: {str(e)}") @app.get("/health", summary="Health Check") def health_check(): return {"status": "ok"}