natalis3405's picture
removed print
35ae7df
Raw
History Blame Contribute Delete
9.78 kB
import gradio as gr
from transformers import pipeline
from PIL import Image
import pytesseract
import re
import json
# Global variable to store the loaded model
loaded_generator = None
current_model = None
def clean_ocr_text(raw_text):
"""Clean OCR text using regex - only for cleaning, not extraction"""
# Remove extra whitespace and normalize
cleaned = re.sub(r'\s+', ' ', raw_text)
# Remove common OCR artifacts
cleaned = re.sub(r'[^\w\s\.,;:/\-@#$%&*()]', ' ', cleaned)
# Normalize common OCR mistakes
cleaned = re.sub(r'\b([A-Z])\s+([A-Z])\b', r'\1\2', cleaned) # Fix split letters
# Clean up date patterns
cleaned = re.sub(r'(\d{2})\s*/\s*(\d{2})\s*/\s*(\d{4})', r'\1/\2/\3', cleaned)
return cleaned.strip()
def load_model(model_choice):
"""Load the AI model only when needed"""
global loaded_generator, current_model
model_map = {
"FLAN-T5 Small (60M)": "google/flan-t5-small",
"FLAN-T5 Base (220M)": "google/flan-t5-base",
"FLAN-T5 Large (770M)": "google/flan-t5-large",
"FLAN-T5 XL (3B)": "google/flan-t5-xl"
}
selected_model = model_map.get(model_choice, "google/flan-t5-base")
# Only load if different model is requested
if current_model != selected_model:
try:
loaded_generator = pipeline("text2text-generation", model=selected_model)
current_model = selected_model
except Exception as e:
# Fallback to base model
if selected_model != "google/flan-t5-base":
loaded_generator = pipeline("text2text-generation", model="google/flan-t5-base")
current_model = "google/flan-t5-base"
else:
raise e
return loaded_generator
def extract_dl_info(image, model_choice, manual_text, use_manual_text):
"""
Extracts driver's license information from an image file using OCR and AI model processing.
Args:
image: PIL Image object from Gradio
model_choice: Selected model from radio button
manual_text: Manual text input from user
use_manual_text: Boolean to determine if manual text should be used instead of OCR
Returns:
tuple: (raw_ocr_text, cleaned_ocr_text, json_result)
"""
try:
# Determine text source
if use_manual_text and manual_text and manual_text.strip():
# Use manual text input
raw_text = manual_text.strip()
cleaned_text = clean_ocr_text(raw_text)
else:
# Use OCR on image
if image is None:
return "No image provided", "No image provided", json.dumps({"error": "No image provided"}, indent=2)
# Convert Gradio image to RGB
if hasattr(image, 'convert'):
image = image.convert("RGB")
# Use Tesseract OCR to extract text
raw_text = pytesseract.image_to_string(image)
# Clean the OCR text using regex (only for cleaning, not extraction)
cleaned_text = clean_ocr_text(raw_text)
# Use AI model to process cleaned OCR text and extract structured information
# Load model only when needed
try:
generator = load_model(model_choice)
except Exception as e:
error_msg = f"Failed to load AI model: {str(e)}"
return raw_text, cleaned_text, json.dumps({"error": error_msg}, indent=2)
# Create specific prompts for the AI model to extract individual fields
name_prompt = f"From this driver's license text, what is the person's full name? Text: {cleaned_text} Answer:"
address_prompt = f"From this driver's license text, what is the street address? Text: {cleaned_text} Answer:"
license_prompt = f"From this driver's license text, what is the license number (the long number)? Text: {cleaned_text} Answer:"
dob_prompt = f"From this driver's license text, what is the date of birth? Text: {cleaned_text} Answer:"
exp_prompt = f"From this driver's license text, what is the expiration date? Text: {cleaned_text} Answer:"
state_prompt = f"From this driver's license text, what is the state abbreviation? Text: {cleaned_text} Answer:"
# Extract each field separately using AI
try:
name_result = generator(name_prompt, max_length=50, do_sample=False)
name = name_result[0]['generated_text'].strip()
address_result = generator(address_prompt, max_length=50, do_sample=False)
address = address_result[0]['generated_text'].strip()
license_result = generator(license_prompt, max_length=50, do_sample=False)
license_number = license_result[0]['generated_text'].strip()
dob_result = generator(dob_prompt, max_length=50, do_sample=False)
date_of_birth = dob_result[0]['generated_text'].strip()
exp_result = generator(exp_prompt, max_length=50, do_sample=False)
expiration_date = exp_result[0]['generated_text'].strip()
state_result = generator(state_prompt, max_length=10, do_sample=False)
state = state_result[0]['generated_text'].strip()
# Clean up the AI responses
def clean_response(response, max_length=100):
if not response or response == "Not found":
return "Not found"
# Take only the first part if it's too long
if len(response) > max_length:
response = response[:max_length].split()[0] if response.split() else "Not found"
return response.strip()
# Create the extracted data
extracted = {
"name": clean_response(name, 50),
"address": clean_response(address, 100),
"license_number": clean_response(license_number, 30),
"date_of_birth": clean_response(date_of_birth, 20),
"expiration_date": clean_response(expiration_date, 20),
"state": clean_response(state, 10)
}
except Exception as e:
extracted = {
"name": "AI extraction failed",
"address": "AI extraction failed",
"license_number": "AI extraction failed",
"date_of_birth": "AI extraction failed",
"expiration_date": "AI extraction failed",
"state": "AI extraction failed",
"error": f"AI model error: {str(e)}"
}
# Format JSON result
json_result = json.dumps(extracted, indent=2)
return raw_text, cleaned_text, json_result
except Exception as e:
error_msg = f"Processing failed: {str(e)}"
return error_msg, error_msg, json.dumps({"error": error_msg}, indent=2)
# Create Gradio interface
with gr.Blocks(title="Driver's License Information Extractor") as demo:
gr.Markdown("# 🆔 Driver's License Information Extractor")
gr.Markdown("Upload a driver's license image to extract information using OCR and AI processing. The system will show raw OCR text, cleaned text, and structured JSON results.")
with gr.Row():
with gr.Column():
image_input = gr.Image(
label="Upload Driver's License Image",
type="pil",
height=400
)
model_choice = gr.Radio(
choices=[
"FLAN-T5 Small (60M)",
"FLAN-T5 Base (220M)",
"FLAN-T5 Large (770M)",
"FLAN-T5 XL (3B)"
],
value="FLAN-T5 Base (220M)",
label="Select AI Model",
info="Larger models are more accurate but slower to load and process"
)
use_manual_text = gr.Checkbox(
label="Use Manual Text Input",
value=False,
info="Check this to type text manually instead of using OCR"
)
manual_text_input = gr.Textbox(
label="Manual Text Input",
lines=6,
placeholder="Type or paste the driver's license text here...",
visible=False
)
submit_btn = gr.Button("Extract Information", variant="primary")
with gr.Column():
raw_ocr = gr.Textbox(
label="Raw OCR Text",
lines=8,
interactive=False,
placeholder="Raw text extracted by Tesseract OCR will appear here..."
)
cleaned_text = gr.Textbox(
label="Cleaned OCR Text",
lines=8,
interactive=False,
placeholder="Cleaned and normalized text will appear here..."
)
json_result = gr.JSON(
label="Extracted Information (JSON)"
)
# Show/hide manual text input based on checkbox
def toggle_manual_input(use_manual):
return gr.update(visible=use_manual)
use_manual_text.change(
fn=toggle_manual_input,
inputs=[use_manual_text],
outputs=[manual_text_input]
)
submit_btn.click(
fn=extract_dl_info,
inputs=[image_input, model_choice, manual_text_input, use_manual_text],
outputs=[raw_ocr, cleaned_text, json_result]
)
if __name__ == "__main__":
demo.launch(share=True)