Spaces:
Sleeping
Sleeping
File size: 9,781 Bytes
dc07627 a2ed7e3 88d676a ef2c140 88d676a a3feeee fe67e79 88d676a 3df8d41 88d676a 3df8d41 88d676a dc07627 88d676a a2ed7e3 88d676a fe67e79 88d676a 3df8d41 88d676a fe67e79 a2ed7e3 88d676a 13f302e 88d676a fe67e79 88d676a fe67e79 88d676a 13f302e a2ed7e3 88d676a 13f302e e076dcd ef2c140 88d676a ef2c140 dc07627 88d676a fe67e79 88d676a a2ed7e3 dc07627 88d676a 2baca8e 88d676a ef2c140 fe67e79 a2ed7e3 88d676a fe67e79 13f302e dc07627 9dd47a2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | 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) |