OCR_API / app.py
AdityaAjithKumar
Added Aadhar Support
2c3822b
Raw
History Blame Contribute Delete
3.38 kB
import asyncio
from fastapi import FastAPI, UploadFile, File, HTTPException
from ocr.gemini_service import parse_pan
from ocr.gemini_aadhar_service import parse_aadhar
from ocr.gemini_face_extractor import detect_face
from utils.crop import crop_face
from utils.pdf import pdf_to_image_bytes
app = FastAPI()
SUPPORTED_TYPES = {"image/jpeg", "image/png", "image/webp", "application/pdf"}
def _resolve_image(raw_bytes: bytes, content_type: str) -> bytes:
if content_type == "application/pdf":
return pdf_to_image_bytes(raw_bytes)
return raw_bytes
@app.post("/kyc/pan")
async def process_pan(file: UploadFile = File(...)):
if file.content_type not in SUPPORTED_TYPES:
raise HTTPException(
status_code=415,
detail=f"Unsupported file type '{file.content_type}'. Upload a JPEG, PNG, WebP, or PDF.",
)
raw_bytes = await file.read()
try:
image_bytes = _resolve_image(raw_bytes, file.content_type)
except ValueError as e:
raise HTTPException(status_code=422, detail=str(e))
try:
pan_result, face_result = await asyncio.gather(
asyncio.to_thread(parse_pan, image_bytes),
asyncio.to_thread(detect_face, image_bytes),
)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
face_bbox = face_result.get("box_2d")
if face_bbox is None:
raise HTTPException(status_code=422, detail="Could not detect face on the PAN card.")
face_image = crop_face(image_bytes, face_bbox)
return {
"success": True,
"parsed_data": pan_result.get("data"),
"face_image": face_image,
"engine_used": pan_result.get("engine_used"),
}
@app.post("/kyc/aadhar")
async def process_aadhar(file: UploadFile = File(...)):
if file.content_type not in SUPPORTED_TYPES:
raise HTTPException(
status_code=415,
detail=f"Unsupported file type '{file.content_type}'. Upload a JPEG, PNG, WebP, or PDF.",
)
raw_bytes = await file.read()
try:
image_bytes = _resolve_image(raw_bytes, file.content_type)
except ValueError as e:
raise HTTPException(status_code=422, detail=str(e))
# Face detection is best-effort — back side of Aadhaar has no photo.
# return_exceptions=True prevents one failure from cancelling the other.
ocr_result, face_result = await asyncio.gather(
asyncio.to_thread(parse_aadhar, image_bytes),
asyncio.to_thread(detect_face, image_bytes),
return_exceptions=True,
)
if isinstance(ocr_result, Exception):
raise HTTPException(status_code=500, detail=str(ocr_result))
data = ocr_result.get("data", {})
address_found = data.get("address_found", False)
# Attempt to crop face; silently skip if detection failed (e.g. back side)
face_image = None
if not isinstance(face_result, Exception):
face_bbox = face_result.get("box_2d")
if face_bbox:
try:
face_image = crop_face(image_bytes, face_bbox)
except Exception:
pass
return {
"success": True,
"parsed_data": data,
"face_image": face_image,
"face_found": face_image is not None,
"address_found": address_found,
"engine_used": ocr_result.get("engine_used"),
}