natalis3405 commited on
Commit
88d676a
·
1 Parent(s): 3df8d41
Files changed (1) hide show
  1. app.py +137 -73
app.py CHANGED
@@ -1,96 +1,160 @@
1
  import gradio as gr
2
  from transformers import pipeline
 
 
3
  import re
 
4
 
5
- # Load text classification pipeline
6
- classifier = pipeline(
7
- "text-classification",
8
- model="distilbert-base-uncased-finetuned-sst-2-english"
9
- )
10
-
11
- def process_application(company, monthly_revenue, monthly_expenses, requested_advance, additional_text):
12
- # Calculate net income
13
- net_income = monthly_revenue - monthly_expenses
14
-
15
- # Define reasonable request rule for MCA
16
- # Reasonable if advance <= 50% of net income and <= 80% of revenue
17
- is_reasonable = (
18
- (requested_advance <= (net_income * 0.5) if net_income > 0 else False)
19
- and (requested_advance <= (monthly_revenue * 0.8))
20
- )
21
 
22
- reasonable_text = (
23
- "\nNote: This request is considered reasonable for MCA based on net income and revenue guidelines."
24
- if is_reasonable
25
- else "\nNote: This request exceeds MCA reasonableness guidelines (advance > 50% of net income or > 80% of revenue)."
26
- )
27
 
28
- # Create application text with qualitative descriptors and reasonable note
29
- application_text = f"""
30
- Company: {company}
31
- Monthly Revenue: ${monthly_revenue:,}
32
- Monthly Expenses: ${monthly_expenses:,}
33
- Requested Advance: ${requested_advance:,}
34
- {reasonable_text}
35
- Additional Context: {additional_text or 'No additional context provided.'}
36
- """
37
 
38
- # Process with classifier
39
- result = classifier(application_text)
40
- label = result[0]['label']
41
- score = result[0]['score']
42
 
43
- # Rule-based financial checks
44
- ratio = monthly_revenue / monthly_expenses if monthly_expenses > 0 else float('inf')
45
- advance_coverage = net_income / requested_advance if requested_advance > 0 else float('inf')
 
 
46
 
47
- # Decision logic: Combine sentiment with financial rules
48
- if (label == "POSITIVE" and
49
- score > 0.9 and
50
- ratio > 1.2 and
51
- advance_coverage > 1.0 and
52
- is_reasonable):
53
- decision = "Approve"
54
- else:
55
- decision = "Reject"
56
 
57
- # Output JSON
58
- output = {
59
- "company": company,
60
- "requested_advance": requested_advance,
61
- "risk_label": label,
62
- "risk_score": score,
63
- "revenue_expense_ratio": round(ratio, 2),
64
- "advance_coverage": round(advance_coverage, 2),
65
- "reasonable_request": is_reasonable,
66
- "decision": decision,
67
- "additional_context": additional_text or "None"
68
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
- return str(output)
 
 
71
 
72
  # Create Gradio interface
73
- with gr.Blocks(title="MCA Application Processor") as demo:
74
- gr.Markdown("# 💼 MCA Application Processor")
75
- gr.Markdown("Enter application details to get a risk assessment and decision. Decision is based on sentiment analysis, financial ratios (Revenue/Expenses > 1.2, Advance Coverage > 1.0), and a reasonable request rule (Advance <= 50% of net income and <= 80% of revenue).")
76
 
77
  with gr.Row():
78
  with gr.Column():
79
- company = gr.Textbox(label="Company Name", value="Acme Corp")
80
- monthly_revenue = gr.Number(label="Monthly Revenue ($)", value=120000, precision=0)
81
- monthly_expenses = gr.Number(label="Monthly Expenses ($)", value=90000, precision=0)
82
- requested_advance = gr.Number(label="Requested Advance ($)", value=50000, precision=0)
83
- additional_text = gr.Textbox(label="Additional Context (Optional)", placeholder="e.g., 'Business has steady growth'", lines=2)
84
-
85
- submit_btn = gr.Button("Process Application", variant="primary")
86
 
87
  with gr.Column():
88
- output = gr.Textbox(label="Result", lines=10, interactive=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  submit_btn.click(
91
- fn=process_application,
92
- inputs=[company, monthly_revenue, monthly_expenses, requested_advance, additional_text],
93
- outputs=output
94
  )
95
 
96
  if __name__ == "__main__":
 
1
  import gradio as gr
2
  from transformers import pipeline
3
+ from PIL import Image
4
+ import pytesseract
5
  import re
6
+ import json
7
 
8
+ def clean_ocr_text(raw_text):
9
+ """Clean OCR text using regex - only for cleaning, not extraction"""
10
+ # Remove extra whitespace and normalize
11
+ cleaned = re.sub(r'\s+', ' ', raw_text)
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ # Remove common OCR artifacts
14
+ cleaned = re.sub(r'[^\w\s\.,;:/\-@#$%&*()]', ' ', cleaned)
 
 
 
15
 
16
+ # Normalize common OCR mistakes
17
+ cleaned = re.sub(r'\b([A-Z])\s+([A-Z])\b', r'\1\2', cleaned) # Fix split letters
 
 
 
 
 
 
 
18
 
19
+ # Clean up date patterns
20
+ cleaned = re.sub(r'(\d{2})\s*/\s*(\d{2})\s*/\s*(\d{4})', r'\1/\2/\3', cleaned)
 
 
21
 
22
+ return cleaned.strip()
23
+
24
+ def extract_dl_info(image):
25
+ """
26
+ Extracts driver's license information from an image file using OCR and AI model processing.
27
 
28
+ Args:
29
+ image: PIL Image object from Gradio
 
 
 
 
 
 
 
30
 
31
+ Returns:
32
+ tuple: (raw_ocr_text, cleaned_ocr_text, json_result)
33
+ """
34
+ try:
35
+ # Convert Gradio image to RGB
36
+ if hasattr(image, 'convert'):
37
+ image = image.convert("RGB")
38
+
39
+ # Use Tesseract OCR to extract text
40
+ print("Extracting text with Tesseract OCR...")
41
+ raw_text = pytesseract.image_to_string(image)
42
+ print(f"Raw OCR text: {raw_text}")
43
+
44
+ # Clean the OCR text using regex (only for cleaning, not extraction)
45
+ cleaned_text = clean_ocr_text(raw_text)
46
+ print(f"Cleaned OCR text: {cleaned_text}")
47
+
48
+ # Use AI model to process cleaned OCR text and extract structured information
49
+ print("Processing cleaned OCR text with AI model...")
50
+
51
+ # Load a text generation pipeline for structured extraction
52
+ generator = pipeline("text2text-generation", model="google/flan-t5-base")
53
+
54
+ # Create specific prompts for the AI model to extract individual fields
55
+ name_prompt = f"From this driver's license text, what is the person's full name? Text: {cleaned_text} Answer:"
56
+ address_prompt = f"From this driver's license text, what is the street address? Text: {cleaned_text} Answer:"
57
+ license_prompt = f"From this driver's license text, what is the license number (the long number)? Text: {cleaned_text} Answer:"
58
+ dob_prompt = f"From this driver's license text, what is the date of birth? Text: {cleaned_text} Answer:"
59
+ exp_prompt = f"From this driver's license text, what is the expiration date? Text: {cleaned_text} Answer:"
60
+ state_prompt = f"From this driver's license text, what is the state abbreviation? Text: {cleaned_text} Answer:"
61
+
62
+ # Extract each field separately using AI
63
+ try:
64
+ name_result = generator(name_prompt, max_length=50, do_sample=False)
65
+ name = name_result[0]['generated_text'].strip()
66
+
67
+ address_result = generator(address_prompt, max_length=50, do_sample=False)
68
+ address = address_result[0]['generated_text'].strip()
69
+
70
+ license_result = generator(license_prompt, max_length=50, do_sample=False)
71
+ license_number = license_result[0]['generated_text'].strip()
72
+
73
+ dob_result = generator(dob_prompt, max_length=50, do_sample=False)
74
+ date_of_birth = dob_result[0]['generated_text'].strip()
75
+
76
+ exp_result = generator(exp_prompt, max_length=50, do_sample=False)
77
+ expiration_date = exp_result[0]['generated_text'].strip()
78
+
79
+ state_result = generator(state_prompt, max_length=10, do_sample=False)
80
+ state = state_result[0]['generated_text'].strip()
81
+
82
+ # Clean up the AI responses
83
+ def clean_response(response, max_length=100):
84
+ if not response or response == "Not found":
85
+ return "Not found"
86
+ # Take only the first part if it's too long
87
+ if len(response) > max_length:
88
+ response = response[:max_length].split()[0] if response.split() else "Not found"
89
+ return response.strip()
90
+
91
+ # Create the extracted data
92
+ extracted = {
93
+ "name": clean_response(name, 50),
94
+ "address": clean_response(address, 100),
95
+ "license_number": clean_response(license_number, 30),
96
+ "date_of_birth": clean_response(date_of_birth, 20),
97
+ "expiration_date": clean_response(expiration_date, 20),
98
+ "state": clean_response(state, 10)
99
+ }
100
+
101
+ except Exception as e:
102
+ print(f"AI extraction failed: {e}")
103
+ extracted = {
104
+ "name": "AI extraction failed",
105
+ "address": "AI extraction failed",
106
+ "license_number": "AI extraction failed",
107
+ "date_of_birth": "AI extraction failed",
108
+ "expiration_date": "AI extraction failed",
109
+ "state": "AI extraction failed",
110
+ "error": f"AI model error: {str(e)}"
111
+ }
112
+
113
+ # Format JSON result
114
+ json_result = json.dumps(extracted, indent=2)
115
+
116
+ return raw_text, cleaned_text, json_result
117
 
118
+ except Exception as e:
119
+ error_msg = f"Processing failed: {str(e)}"
120
+ return error_msg, error_msg, json.dumps({"error": error_msg}, indent=2)
121
 
122
  # Create Gradio interface
123
+ with gr.Blocks(title="Driver's License Information Extractor") as demo:
124
+ gr.Markdown("# 🆔 Driver's License Information Extractor")
125
+ 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.")
126
 
127
  with gr.Row():
128
  with gr.Column():
129
+ image_input = gr.Image(
130
+ label="Upload Driver's License Image",
131
+ type="pil",
132
+ height=400
133
+ )
134
+ submit_btn = gr.Button("Extract Information", variant="primary")
 
135
 
136
  with gr.Column():
137
+ raw_ocr = gr.Textbox(
138
+ label="Raw OCR Text",
139
+ lines=8,
140
+ interactive=False,
141
+ placeholder="Raw text extracted by Tesseract OCR will appear here..."
142
+ )
143
+ cleaned_text = gr.Textbox(
144
+ label="Cleaned OCR Text",
145
+ lines=8,
146
+ interactive=False,
147
+ placeholder="Cleaned and normalized text will appear here..."
148
+ )
149
+ json_result = gr.JSON(
150
+ label="Extracted Information (JSON)",
151
+ interactive=False
152
+ )
153
 
154
  submit_btn.click(
155
+ fn=extract_dl_info,
156
+ inputs=[image_input],
157
+ outputs=[raw_ocr, cleaned_text, json_result]
158
  )
159
 
160
  if __name__ == "__main__":