from fastapi import APIRouter, File, UploadFile, Form, Depends, HTTPException, status from fastapi.responses import JSONResponse from src.services.image_processor import image_processor from src.services.ocr_engine import ocr_service from src.services.markdown_formatter import format_ocr_result from src.api.dependencies import verify_api_key router = APIRouter() @router.get("/health") def health_check(): """Unauthenticated endpoint to check server health.""" return {"status": "healthy"} @router.post("/api/v1/image/extract-text") async def extract_text( image: UploadFile = File(...), lang: str = Form("en", description="Target language code (e.g. 'en', 'hi', 'ar') or 'auto' for automatic language detection."), api_key: str = Depends(verify_api_key) ): """ Receives an image file via multipart form, processes it with PaddleOCR, and returns both plain text and structured Markdown in the JSON response. Supported lang values: 'auto' (automatic detection), or specific codes like 'en', 'hi', 'ar', 'es', 'pt', etc. Response shape: { "success": true, "data": { "result": "", "markdown": "", "fileName": "" } } """ try: # Validate mime type if not image.content_type.startswith("image/"): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Uploaded file is not a supported image format." ) # Read raw bytes image_bytes = await image.read() # Preprocess: EXIF correction → resolution guard → CLAHE → unsharp mask img_np = image_processor.process_bytes_to_numpy(image_bytes) # Run OCR — returns raw bounding-box result list (not yet formatted) raw_result = await ocr_service.run_ocr_raw(img_np, lang) # Convert raw result → plain text + structured Markdown plain_text, markdown_text = format_ocr_result(raw_result) return { "success": True, "data": { "result": plain_text, "markdown": markdown_text, "fileName": image.filename or "uploaded_image.jpg" } } except HTTPException as he: raise he except Exception as e: import traceback traceback.print_exc() return JSONResponse( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={ "success": False, "error": f"OCR processing failed: {str(e)}" } )