- ---------------------------
- CONFIG
- ---------------------------
- ---------------------------
- SCHEMA
- ---------------------------
- ---------------------------
- OCR
- ---------------------------
- sort by reading order
- ---------------------------
- IMAGE TO BASE64
- ---------------------------
- ---------------------------
- PROMPT
- ---------------------------
- ---------------------------
- OLLAMA VISION CALL
- ---------------------------
- remove markdown wrappers
- ---------------------------
- PARSE JSON
- ---------------------------
import cv2 import json import base64 import requests from paddleocr import PaddleOCR from pydantic import BaseModel
---------------------------
CONFIG
---------------------------
IMAGE_PATH = "voter_card.jpg" OLLAMA_URL = "http://localhost:11434/api/chat" MODEL = "qwen2.5vl:7b"
---------------------------
SCHEMA
---------------------------
class VoterID(BaseModel): epic_number: str | None = None name: str | None = None father_name: str | None = None husband_name: str | None = None dob: str | None = None gender: str | None = None
---------------------------
OCR
---------------------------
ocr = PaddleOCR( use_angle_cls=True, lang="en" )
result = ocr.ocr(IMAGE_PATH, cls=True)
ocr_blocks = []
for line in result[0]:
bbox = line[0]
text = line[1][0]
confidence = float(line[1][1])
ocr_blocks.append({
"text": text,
"confidence": round(confidence, 3),
"bbox": bbox
})
sort by reading order
ocr_blocks.sort( key=lambda item: ( min(p[1] for p in item["bbox"]), min(p[0] for p in item["bbox"]) ) )
---------------------------
IMAGE TO BASE64
---------------------------
with open(IMAGE_PATH, "rb") as f: image_b64 = base64.b64encode(f.read()).decode()
---------------------------
PROMPT
---------------------------
prompt = f""" You are an expert Indian document extraction engine.
Document may be:
- Voter ID
- PAN Card
- Aadhaar
- Driving License
Use BOTH:
- The image
- OCR text
- OCR coordinates
OCR Results:
{json.dumps(ocr_blocks, ensure_ascii=False, indent=2)}
Return ONLY valid JSON.
Schema:
{{ "document_type": null, "id_number": null, "name": null, "father_name": null, "husband_name": null, "dob": null, "gender": null }}
Rules:
- Correct obvious OCR mistakes.
- Use image when OCR is incorrect.
- Return null if field missing.
- No explanation.
- Output JSON only. """
---------------------------
OLLAMA VISION CALL
---------------------------
payload = { "model": MODEL, "messages": [ { "role": "user", "content": prompt, "images": [image_b64] } ], "stream": False }
response = requests.post( OLLAMA_URL, json=payload, timeout=300 )
response.raise_for_status()
content = response.json()["message"]["content"]
remove markdown wrappers
content = (
content.replace("json", "") .replace("", "")
.strip()
)
print("\nRAW RESPONSE\n") print(content)
---------------------------
PARSE JSON
---------------------------
try: data = json.loads(content)
print("\nSTRUCTURED DATA\n")
print(json.dumps(data, indent=4))
except Exception as e: print("JSON parsing failed") print(e)