idvpackage 3.0.10__py3-none-any.whl → 3.0.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- idvpackage/common.py +4 -964
- idvpackage/iraq_id_extraction_withopenai.py +374 -893
- idvpackage/jor_passport_extraction.py +1 -6
- idvpackage/liveness_spoofing_v2.py +2 -45
- idvpackage/ocr.py +1051 -2448
- idvpackage/ocr_utils.py +144 -486
- idvpackage/pse_passport_extraction.py +18 -292
- idvpackage/qatar_id_extraction.py +4 -956
- idvpackage/sudan_passport_extraction.py +0 -928
- idvpackage/syr_passport_extraction.py +27 -402
- idvpackage/uae_id_extraction.py +87 -151
- {idvpackage-3.0.10.dist-info → idvpackage-3.0.12.dist-info}/METADATA +1 -1
- idvpackage-3.0.12.dist-info/RECORD +34 -0
- {idvpackage-3.0.10.dist-info → idvpackage-3.0.12.dist-info}/WHEEL +1 -1
- idvpackage/ekyc.py +0 -78
- idvpackage/genai_utils.py +0 -309
- idvpackage/iraq_id_extraction.py +0 -992
- idvpackage/iraq_passport_extraction.py +0 -588
- idvpackage/lazy_imports.py +0 -44
- idvpackage/lebanon_passport_extraction.py +0 -161
- idvpackage/sau_id_extraction.py +0 -248
- idvpackage/sudan_id_extraction.py +0 -764
- idvpackage-3.0.10.dist-info/RECORD +0 -42
- {idvpackage-3.0.10.dist-info → idvpackage-3.0.12.dist-info}/licenses/LICENSE +0 -0
- {idvpackage-3.0.10.dist-info → idvpackage-3.0.12.dist-info}/top_level.txt +0 -0
idvpackage/ocr_utils.py
CHANGED
|
@@ -6,11 +6,11 @@ from google.cloud import vision_v1
|
|
|
6
6
|
from idvpackage.constants import *
|
|
7
7
|
import pkg_resources
|
|
8
8
|
import base64
|
|
9
|
-
from googletrans import Translator
|
|
10
9
|
from rapidfuzz import fuzz
|
|
11
10
|
import logging
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
12
13
|
logging.basicConfig(level=logging.INFO)
|
|
13
|
-
translator = Translator()
|
|
14
14
|
|
|
15
15
|
def create_final_result(dictionary):
|
|
16
16
|
result = ""
|
|
@@ -53,7 +53,6 @@ def create_sub_result(document_report):
|
|
|
53
53
|
|
|
54
54
|
return sub_result
|
|
55
55
|
|
|
56
|
-
|
|
57
56
|
def mark_clear(data, keys):
|
|
58
57
|
if isinstance(data, dict):
|
|
59
58
|
for key, value in list(data.items()):
|
|
@@ -67,7 +66,6 @@ def mark_clear(data, keys):
|
|
|
67
66
|
else:
|
|
68
67
|
return data
|
|
69
68
|
|
|
70
|
-
|
|
71
69
|
def mark_nested_result(data, value):
|
|
72
70
|
if isinstance(data, dict):
|
|
73
71
|
if 'result' in data:
|
|
@@ -81,20 +79,18 @@ def mark_nested_result(data, value):
|
|
|
81
79
|
else:
|
|
82
80
|
return data
|
|
83
81
|
|
|
84
|
-
from datetime import datetime
|
|
85
|
-
import logging
|
|
86
82
|
|
|
87
83
|
def parse_date(date_str: str, fmt: str = "%d/%m/%Y"):
|
|
88
84
|
"""Safely parse a date string and return a datetime object or None."""
|
|
89
85
|
if not date_str:
|
|
90
86
|
return None
|
|
87
|
+
date_str = date_str.replace(".", "/").replace("-", "/") # unify separators
|
|
91
88
|
try:
|
|
92
89
|
return datetime.strptime(date_str, fmt)
|
|
93
90
|
except Exception as e:
|
|
94
91
|
logging.exception(f"Failed to parse date: {date_str}, Error: {e}")
|
|
95
92
|
return None
|
|
96
93
|
|
|
97
|
-
|
|
98
94
|
def validation_checks_passport(data: dict, id_number_type: str, country: str):
|
|
99
95
|
"""
|
|
100
96
|
Perform validation checks for passport-related fields such as:
|
|
@@ -103,18 +99,28 @@ def validation_checks_passport(data: dict, id_number_type: str, country: str):
|
|
|
103
99
|
- Expiry and Issue date validations
|
|
104
100
|
- Gender consistency
|
|
105
101
|
"""
|
|
102
|
+
# Initialize validation_range with default value
|
|
103
|
+
validation_range = range(1823, 1829) # Default: 6 years +/- 2 days
|
|
104
|
+
|
|
106
105
|
if country == 'SDN':
|
|
107
106
|
validation_range = range(3648, 3654) # 10 years +/- 2 days for Sudanese passports
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
elif country == 'LBN':
|
|
110
109
|
validation_range = list(range(1823, 1828)) + list(range(3648, 3654)) # 5 years +/- 2 days for Lebanon passports
|
|
111
110
|
|
|
112
|
-
|
|
111
|
+
elif country == 'JOR':
|
|
113
112
|
validation_range = range(1823, 1828) # 5 years (1825) +/- 2 days for Jordan passports
|
|
114
113
|
|
|
114
|
+
elif country == 'IRQ': #range is 8 years , in days
|
|
115
|
+
validation_range = range(2920, 2928) # 8 years Iraq passports
|
|
116
|
+
|
|
117
|
+
elif country == 'PSE':
|
|
118
|
+
validation_range = range(1823, 1828) # 5 years +/- 2 days for Palestinian passports
|
|
119
|
+
|
|
120
|
+
elif country == 'SYR':
|
|
121
|
+
validation_range = [days for years in [2, 3, 6] for days in range(years * 365 - 2, years * 365 + 3)]
|
|
115
122
|
|
|
116
123
|
logging.info(f"Performing validation checks for country: {country} and validation_range: {validation_range}")
|
|
117
|
-
# --- Normalize dates ---
|
|
118
124
|
|
|
119
125
|
dob = normalize_date_generic(data.get("dob"))
|
|
120
126
|
dob_mrz = normalize_date_generic(data.get("dob_mrz"))
|
|
@@ -131,7 +137,11 @@ def validation_checks_passport(data: dict, id_number_type: str, country: str):
|
|
|
131
137
|
gender = data.get("gender", "")
|
|
132
138
|
gender_mrz = data.get("gender_mrz", "")
|
|
133
139
|
|
|
134
|
-
|
|
140
|
+
if gender:
|
|
141
|
+
gender = gender[0].upper()
|
|
142
|
+
if gender_mrz:
|
|
143
|
+
gender_mrz = gender_mrz[0].upper()
|
|
144
|
+
logging.info(f"Extracted Data for Validation - DOB: {dob}, DOB MRZ: {dob_mrz}, Expiry Date: {expiry_date}, Expiry Date MRZ: {expiry_date_mrz}, Issue Date: {issue_date}, ID Number: {id_number}, ID Number MRZ: {id_number_mrz}, Gender: {gender}, Gender MRZ: {gender_mrz}")
|
|
135
145
|
# --- Initialize Flags ---
|
|
136
146
|
is_id_number_same_mrz = False
|
|
137
147
|
is_expiry_date_same_mrz = False
|
|
@@ -140,13 +150,14 @@ def validation_checks_passport(data: dict, id_number_type: str, country: str):
|
|
|
140
150
|
is_gender_mrz_match = False
|
|
141
151
|
|
|
142
152
|
# --- ID Number Validation ---
|
|
153
|
+
logging.info(f"Comparing ID Number: data field {id_number} vs MRZ {id_number_mrz}")
|
|
154
|
+
|
|
143
155
|
if id_number and id_number_mrz:
|
|
144
|
-
logging.info(f"Comparing ID Number: data field {id_number} vs MRZ {id_number_mrz}")
|
|
145
156
|
is_id_number_same_mrz = (id_number == id_number_mrz)
|
|
146
157
|
|
|
147
158
|
# --- Expiry Date Match (OCR vs MRZ) ---
|
|
159
|
+
logging.info(f"Comparing Expiry Date: data field {expiry_date} vs MRZ {expiry_date_mrz}")
|
|
148
160
|
if expiry_date and expiry_date_mrz:
|
|
149
|
-
logging.info(f"Comparing Expiry Date: data field {expiry_date} vs MRZ {expiry_date_mrz}")
|
|
150
161
|
is_expiry_date_same_mrz = (expiry_date == expiry_date_mrz)
|
|
151
162
|
|
|
152
163
|
# --- Issue vs Expiry Duration (MRZ) ---
|
|
@@ -187,72 +198,6 @@ def validation_checks_passport(data: dict, id_number_type: str, country: str):
|
|
|
187
198
|
"is_gender_mrz_match": is_gender_mrz_match
|
|
188
199
|
}
|
|
189
200
|
|
|
190
|
-
# def validation_checks_passport(data, country):
|
|
191
|
-
|
|
192
|
-
# dob_back_str = data.get("dob", "")
|
|
193
|
-
# dob_back_mrz_str = data.get("date_of_birth_mrz", "")
|
|
194
|
-
|
|
195
|
-
# dob_back = normalize_date_generic(dob_back_str)
|
|
196
|
-
# dob_back_mrz = normalize_date_generic(dob_back_mrz_str)
|
|
197
|
-
|
|
198
|
-
# expiry_date = data.get("expiry_date", "")
|
|
199
|
-
# issue_date = data.get("issue_date", "")
|
|
200
|
-
# expiry_date_mrz = data.get("expiry_date_mrz", "")
|
|
201
|
-
|
|
202
|
-
# id_number = data.get("id_number", "")
|
|
203
|
-
# id_number_mrz = data.get("id_number_mrz", "")
|
|
204
|
-
|
|
205
|
-
# if id_number and id_number_mrz:
|
|
206
|
-
# if id_number == id_number_mrz:
|
|
207
|
-
# is_id_number_same_mrz= True
|
|
208
|
-
# else:
|
|
209
|
-
# is_id_number_same_mrz = False
|
|
210
|
-
|
|
211
|
-
# if data.get('expiry_date','') and data.get('expiry_date_mrz',''):
|
|
212
|
-
|
|
213
|
-
# try:
|
|
214
|
-
# #check if both dates are same
|
|
215
|
-
# expiry_date_obj = datetime.strptime(data.get("expiry_date", ""), "%d/%m/%Y")
|
|
216
|
-
# expiry_date_mrz_obj = datetime.strptime(data.get("expiry_date_mrz", ""), "%d/%m/%Y")
|
|
217
|
-
|
|
218
|
-
# logging.info(f"expiry_date_obj: {expiry_date_obj}, expiry_date_mrz_obj: {expiry_date_mrz_obj}")
|
|
219
|
-
|
|
220
|
-
# if expiry_date_obj == expiry_date_mrz_obj:
|
|
221
|
-
# is_expiry_date_same_mrz = True
|
|
222
|
-
# else:
|
|
223
|
-
# is_expiry_date_same_mrz = False
|
|
224
|
-
# except:
|
|
225
|
-
|
|
226
|
-
# is_expiry_date_same_mrz = False
|
|
227
|
-
# logging.info("Error in comparing expiry dates for SDN ID")
|
|
228
|
-
# pass
|
|
229
|
-
|
|
230
|
-
# if data.get('issue_date', '') and data.get("expiry_date_mrz",''):
|
|
231
|
-
# try:
|
|
232
|
-
# issue_date_obj = datetime.strptime(data.get("issue_date", ""), "%d/%m/%Y")
|
|
233
|
-
# logging.info(f"difference_in_days issue_date_mrz_obj: {issue_date_obj}, expiry_date_mrz_obj: {expiry_date_mrz_obj} differece is : {(expiry_date_mrz_obj - issue_date_obj).days}")
|
|
234
|
-
# difference_in_days_mrz_obj = (expiry_date_mrz_obj - issue_date_obj).days
|
|
235
|
-
|
|
236
|
-
# valid_id_duration_mrz = difference_in_days_mrz_obj in [3649,3650, 3651, 3652, 3653]
|
|
237
|
-
# except:
|
|
238
|
-
# logging.info("Error in calculating date difference between issue and expiry dates for SDN ID")
|
|
239
|
-
# pass
|
|
240
|
-
|
|
241
|
-
# if data.get("issue_date",'') and data.get("expiry_date",''):
|
|
242
|
-
# try:
|
|
243
|
-
|
|
244
|
-
# logging.info(f"difference_in_days issue_date_obj: {issue_date_obj}, expiry_date_obj: {expiry_date_obj} differece is : {(expiry_date_obj - issue_date_obj).days}")
|
|
245
|
-
# difference_in_days_obj = (expiry_date_obj - issue_date_obj).days
|
|
246
|
-
|
|
247
|
-
# valid_id_duration = difference_in_days_obj in [ 3649,3650, 3651, 3652, 3653]
|
|
248
|
-
|
|
249
|
-
# except:
|
|
250
|
-
# logging.info("Error in calculating date difference between issue and expiry dates from MRZ for SDN ID")
|
|
251
|
-
# pass
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
201
|
def age_validation(dob, age_threshold=18):
|
|
257
202
|
age_val = {
|
|
258
203
|
"breakdown": {
|
|
@@ -319,46 +264,43 @@ def is_valid_and_not_expired(expiry_date, country):
|
|
|
319
264
|
except:
|
|
320
265
|
return 'consider'
|
|
321
266
|
|
|
322
|
-
def
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
iqama_id_pattern = r'KINGDOM OF SAUDI ARABIA|RESIDENT IDENTITY|MINISTRY OF INTERIOR'
|
|
326
|
-
iraq_id_pattern = r'Register|Signature|Family Number|The Directorate of Nationality|IDIRQ|The Republic of Iraq|Ministry of|National Card|Iraq'
|
|
327
|
-
lbn_id_pattern = r'Marital status|Family|Lebanon Republic|Republic of Lebanon'
|
|
328
|
-
qtr_id_pattern = r'State of Qatar|Residency Permit|Director General of the General Department|Directorate of Passports|Passport number'
|
|
329
|
-
passport_pattern = r'\b(PASSPORT|PPT)\b'
|
|
330
|
-
driver_license_pattern = r'\b(DRIVER|LICENSE|DL)\b'
|
|
331
|
-
|
|
332
|
-
if re.search(emirates_id_pattern, text, re.IGNORECASE):
|
|
333
|
-
return "EID"
|
|
267
|
+
def normalize_gender(gender: str):
|
|
268
|
+
if not gender:
|
|
269
|
+
return None
|
|
334
270
|
|
|
335
|
-
|
|
336
|
-
return "INC"
|
|
337
|
-
|
|
338
|
-
if country == 'LBN' and re.search(lbn_id_pattern, text, re.IGNORECASE):
|
|
339
|
-
return "LBN"
|
|
340
|
-
|
|
341
|
-
if country == 'QAT' and re.search(qtr_id_pattern, text, re.IGNORECASE):
|
|
342
|
-
return "QAT"
|
|
343
|
-
|
|
344
|
-
if re.search(passport_pattern, text, re.IGNORECASE):
|
|
345
|
-
return "PASSPORT"
|
|
271
|
+
gender = gender.strip().lower()
|
|
346
272
|
|
|
347
|
-
if
|
|
348
|
-
return "
|
|
273
|
+
if gender in {"m", "male"}:
|
|
274
|
+
return "Male"
|
|
349
275
|
|
|
350
|
-
|
|
276
|
+
if gender in {"f", "female"}:
|
|
277
|
+
return "Female"
|
|
351
278
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
return
|
|
279
|
+
return None
|
|
280
|
+
|
|
281
|
+
def normalize_mrz_date(mrz_date, out_format="%Y-%m-%d"):
|
|
282
|
+
"""
|
|
283
|
+
MRZ date format: YYMMDD
|
|
284
|
+
"""
|
|
285
|
+
if not mrz_date or len(mrz_date) != 6:
|
|
286
|
+
return None
|
|
287
|
+
|
|
288
|
+
try:
|
|
289
|
+
yy = int(mrz_date[0:2])
|
|
290
|
+
mm = int(mrz_date[2:4])
|
|
291
|
+
dd = int(mrz_date[4:6])
|
|
292
|
+
|
|
293
|
+
# Century inference
|
|
294
|
+
|
|
295
|
+
year = 2000 + yy
|
|
296
|
+
|
|
297
|
+
dt = datetime(year, mm, dd)
|
|
298
|
+
return dt.strftime(out_format)
|
|
299
|
+
|
|
300
|
+
except Exception as e:
|
|
301
|
+
logging.info(f"Failed to parse MRZ date {mrz_date}: {e}")
|
|
302
|
+
return None
|
|
360
303
|
|
|
361
|
-
from datetime import datetime
|
|
362
304
|
def normalize_date_generic(date_str, out_format="%Y-%m-%d"):
|
|
363
305
|
date_str = date_str.replace(".", "/").replace("-", "/") # unify separators
|
|
364
306
|
logging.info(f"Normalizing date: {date_str}")
|
|
@@ -381,74 +323,6 @@ def normalize_date_generic(date_str, out_format="%Y-%m-%d"):
|
|
|
381
323
|
logging.info(f"Unable to parse date: {date_str}")
|
|
382
324
|
return None
|
|
383
325
|
|
|
384
|
-
def identify_back_id(text):
|
|
385
|
-
back_id_keywords = ['ILARE', 'IDARE', 'Signature']
|
|
386
|
-
pattern = '|'.join(map(re.escape, back_id_keywords))
|
|
387
|
-
|
|
388
|
-
if re.search(pattern, text, re.IGNORECASE):
|
|
389
|
-
return True
|
|
390
|
-
else:
|
|
391
|
-
return False
|
|
392
|
-
|
|
393
|
-
def identify_front_id_iraq(text):
|
|
394
|
-
front_id_keywords = ['The Republic of Iraq', 'Ministry of', 'National Card', 'Passports and Residence', 'Republic', 'Ministry', 'Iraq']
|
|
395
|
-
pattern = '|'.join(map(re.escape, front_id_keywords))
|
|
396
|
-
|
|
397
|
-
if re.search(pattern, text, re.IGNORECASE):
|
|
398
|
-
return True
|
|
399
|
-
else:
|
|
400
|
-
return False
|
|
401
|
-
|
|
402
|
-
def identify_back_id_iraq(back_id_text, text):
|
|
403
|
-
back_id_keywords = ['IDIRQ', 'Signature', 'Register', 'Family Number', 'The Directorate of Nationality', 'IDIR']
|
|
404
|
-
pattern = '|'.join(map(re.escape, back_id_keywords))
|
|
405
|
-
|
|
406
|
-
if re.search(pattern, text, re.IGNORECASE):
|
|
407
|
-
return True
|
|
408
|
-
else:
|
|
409
|
-
if re.search(pattern, back_id_text, re.IGNORECASE):
|
|
410
|
-
return True
|
|
411
|
-
else:
|
|
412
|
-
return False
|
|
413
|
-
|
|
414
|
-
def identify_front_id_lebanon(text):
|
|
415
|
-
front_id_keywords = ['Lebanon Republic', 'Ministry of', 'Republic of Lebanon']
|
|
416
|
-
pattern = '|'.join(map(re.escape, front_id_keywords))
|
|
417
|
-
|
|
418
|
-
if re.search(pattern, text, re.IGNORECASE):
|
|
419
|
-
return True
|
|
420
|
-
else:
|
|
421
|
-
return False
|
|
422
|
-
|
|
423
|
-
def identify_back_id_lebanon(text):
|
|
424
|
-
logging.info(f'\n\nIdentifying back ID Lebanon with text: {text}\n')
|
|
425
|
-
back_id_keywords = ['Marital status', 'Family']
|
|
426
|
-
pattern = '|'.join(map(re.escape, back_id_keywords))
|
|
427
|
-
|
|
428
|
-
if re.search(pattern, text, re.IGNORECASE):
|
|
429
|
-
return True
|
|
430
|
-
else:
|
|
431
|
-
return False
|
|
432
|
-
|
|
433
|
-
def identify_front_id_qatar(text):
|
|
434
|
-
front_id_keywords = ['State of Qatar', 'Residency Permit']
|
|
435
|
-
pattern = '|'.join(map(re.escape, front_id_keywords))
|
|
436
|
-
|
|
437
|
-
if re.search(pattern, text, re.IGNORECASE):
|
|
438
|
-
return True
|
|
439
|
-
else:
|
|
440
|
-
return False
|
|
441
|
-
|
|
442
|
-
def identify_back_id_qatar(text):
|
|
443
|
-
back_id_keywords = ['Director General of the General Department', 'Directorate of Passports', 'Passport number']
|
|
444
|
-
pattern = '|'.join(map(re.escape, back_id_keywords))
|
|
445
|
-
|
|
446
|
-
logging.info(f'{re.search(pattern, text, re.IGNORECASE)}')
|
|
447
|
-
if re.search(pattern, text, re.IGNORECASE):
|
|
448
|
-
return True
|
|
449
|
-
else:
|
|
450
|
-
return False
|
|
451
|
-
|
|
452
326
|
def document_on_printed_paper(image, block_size=11, c_value=2, texture_threshold=0.4, contour_area_threshold=5000):
|
|
453
327
|
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
454
328
|
image_thresh = cv2.adaptiveThreshold(image_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, block_size, c_value)
|
|
@@ -466,142 +340,6 @@ def document_on_printed_paper(image, block_size=11, c_value=2, texture_threshold
|
|
|
466
340
|
else:
|
|
467
341
|
return 'clear'
|
|
468
342
|
|
|
469
|
-
|
|
470
|
-
def check_logo_existence_iraq(logo_content, id_card_content, threshold=3, good_mathces_filter=0.6):
|
|
471
|
-
nparr_logo = np.frombuffer(logo_content, np.uint8)
|
|
472
|
-
logo = cv2.imdecode(nparr_logo, cv2.IMREAD_GRAYSCALE)
|
|
473
|
-
|
|
474
|
-
nparr_id_card = np.frombuffer(id_card_content, np.uint8)
|
|
475
|
-
id_card = cv2.imdecode(nparr_id_card, cv2.IMREAD_COLOR)
|
|
476
|
-
id_card_gray = cv2.cvtColor(id_card, cv2.COLOR_BGR2GRAY)
|
|
477
|
-
|
|
478
|
-
sift = cv2.SIFT_create()
|
|
479
|
-
|
|
480
|
-
kp1, des1 = sift.detectAndCompute(logo, None)
|
|
481
|
-
kp2, des2 = sift.detectAndCompute(id_card_gray, None)
|
|
482
|
-
|
|
483
|
-
FLANN_INDEX_KDTREE = 1
|
|
484
|
-
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
|
|
485
|
-
search_params = dict(checks=50)
|
|
486
|
-
flann = cv2.FlannBasedMatcher(index_params, search_params)
|
|
487
|
-
|
|
488
|
-
matches = flann.knnMatch(des1, des2, k=2)
|
|
489
|
-
|
|
490
|
-
good_matches = []
|
|
491
|
-
for m, n in matches:
|
|
492
|
-
if m.distance < good_mathces_filter * n.distance:
|
|
493
|
-
good_matches.append(m)
|
|
494
|
-
|
|
495
|
-
# 40
|
|
496
|
-
min_good_matches = threshold
|
|
497
|
-
# min_good_matches = 3
|
|
498
|
-
|
|
499
|
-
if len(good_matches) >= min_good_matches:
|
|
500
|
-
return True
|
|
501
|
-
else:
|
|
502
|
-
return False
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
def detect_logo(client, input_image_content, country, compare_type=None, side=None):
|
|
506
|
-
if country == 'UAE':
|
|
507
|
-
reference_logo_path = pkg_resources.resource_filename('idvpackage', 'template_images/emirates_id_logo.jpeg')
|
|
508
|
-
|
|
509
|
-
with open(reference_logo_path, 'rb') as logo_file:
|
|
510
|
-
reference_image_content = logo_file.read()
|
|
511
|
-
|
|
512
|
-
reference_image = vision_v1.types.Image(content=reference_image_content)
|
|
513
|
-
input_image = vision_v1.types.Image(content=input_image_content)
|
|
514
|
-
|
|
515
|
-
reference_response = client.logo_detection(image=reference_image)
|
|
516
|
-
input_response = client.logo_detection(image=input_image)
|
|
517
|
-
|
|
518
|
-
reference_logos = reference_response.logo_annotations
|
|
519
|
-
input_logos = input_response.logo_annotations
|
|
520
|
-
|
|
521
|
-
for reference_logo in reference_logos:
|
|
522
|
-
for input_logo in input_logos:
|
|
523
|
-
if reference_logo.description.lower() == input_logo.description.lower():
|
|
524
|
-
return 'clear'
|
|
525
|
-
|
|
526
|
-
return 'consider'
|
|
527
|
-
|
|
528
|
-
if country in ['IRQ', 'LBN', 'QAT'] and compare_type != 'template':
|
|
529
|
-
if country == 'IRQ':
|
|
530
|
-
logo_path = 'template_images/iraq_id_logo.png'
|
|
531
|
-
good_mathces_filter = 0.6
|
|
532
|
-
elif country == 'QAT':
|
|
533
|
-
logo_path = 'template_images/qatar_id_logo.jpeg'
|
|
534
|
-
good_mathces_filter = 0.7
|
|
535
|
-
|
|
536
|
-
reference_logo_path = pkg_resources.resource_filename('idvpackage', logo_path)
|
|
537
|
-
with open(reference_logo_path, 'rb') as logo_file:
|
|
538
|
-
reference_image_content = logo_file.read()
|
|
539
|
-
result = check_logo_existence_iraq(reference_image_content, input_image_content, 3, good_mathces_filter)
|
|
540
|
-
|
|
541
|
-
if result:
|
|
542
|
-
return 'clear'
|
|
543
|
-
else:
|
|
544
|
-
return 'consider'
|
|
545
|
-
|
|
546
|
-
if country in ['IRQ', 'LBN', 'QAT'] and compare_type == 'template':
|
|
547
|
-
if side == 'front':
|
|
548
|
-
if country == 'QAT':
|
|
549
|
-
threshold = 300
|
|
550
|
-
front_template_path = 'template_images/qatar_front_standard_template.jpeg'
|
|
551
|
-
elif country == 'IRQ':
|
|
552
|
-
threshold = 40
|
|
553
|
-
front_template_path = 'template_images/iraq_standard_template.png'
|
|
554
|
-
else: # LBN
|
|
555
|
-
threshold = 60
|
|
556
|
-
front_template_path = 'template_images/lbn_front_standard_template.png'
|
|
557
|
-
reference_logo_path = pkg_resources.resource_filename('idvpackage', front_template_path)
|
|
558
|
-
if side == 'back':
|
|
559
|
-
if country == 'QAT':
|
|
560
|
-
threshold = 235
|
|
561
|
-
back_template_path = 'template_images/qatar_back_standard_template.jpeg'
|
|
562
|
-
elif country == 'IRQ':
|
|
563
|
-
threshold = 140
|
|
564
|
-
back_template_path = 'template_images/iraq_back_standard_template.jpg'
|
|
565
|
-
else: # LBN
|
|
566
|
-
threshold = 120
|
|
567
|
-
back_template_path = 'template_images/lbn_back_standard_template.png'
|
|
568
|
-
reference_logo_path = pkg_resources.resource_filename('idvpackage', back_template_path)
|
|
569
|
-
|
|
570
|
-
with open(reference_logo_path, 'rb') as logo_file:
|
|
571
|
-
reference_image_content = logo_file.read()
|
|
572
|
-
|
|
573
|
-
result = check_logo_existence_iraq(reference_image_content, input_image_content, threshold)
|
|
574
|
-
|
|
575
|
-
if result:
|
|
576
|
-
return 'clear'
|
|
577
|
-
else:
|
|
578
|
-
return 'consider'
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
def detect_logo_saudi(client, input_image):
|
|
583
|
-
reference_logo_path = pkg_resources.resource_filename('idvpackage', 'template_images/sau_id_logo.png')
|
|
584
|
-
|
|
585
|
-
with open(reference_logo_path, 'rb') as logo_file:
|
|
586
|
-
reference_image_content = logo_file.read()
|
|
587
|
-
|
|
588
|
-
reference_image = vision_v1.types.Image(content=reference_image_content)
|
|
589
|
-
input_image = vision_v1.types.Image(content=input_image)
|
|
590
|
-
|
|
591
|
-
reference_response = client.logo_detection(image=reference_image)
|
|
592
|
-
input_response = client.logo_detection(image=input_image)
|
|
593
|
-
|
|
594
|
-
reference_logos = reference_response.logo_annotations
|
|
595
|
-
input_logos = input_response.logo_annotations
|
|
596
|
-
|
|
597
|
-
for reference_logo in reference_logos:
|
|
598
|
-
for input_logo in input_logos:
|
|
599
|
-
if reference_logo.description.lower() == input_logo.description.lower():
|
|
600
|
-
return 'clear'
|
|
601
|
-
|
|
602
|
-
return 'consider'
|
|
603
|
-
|
|
604
|
-
|
|
605
343
|
def perform_feature_matching(image, template_image_path):
|
|
606
344
|
template_image = cv2.imread(template_image_path, cv2.IMREAD_COLOR)
|
|
607
345
|
|
|
@@ -625,8 +363,6 @@ def perform_feature_matching(image, template_image_path):
|
|
|
625
363
|
|
|
626
364
|
return similarity_score
|
|
627
365
|
|
|
628
|
-
|
|
629
|
-
# part of detecting screenshot - checks for time values seen on phone
|
|
630
366
|
def extract_time_values(text_annotations):
|
|
631
367
|
time_values = []
|
|
632
368
|
for annotation in text_annotations:
|
|
@@ -635,7 +371,6 @@ def extract_time_values(text_annotations):
|
|
|
635
371
|
time_values.extend(time_matches)
|
|
636
372
|
return time_values
|
|
637
373
|
|
|
638
|
-
|
|
639
374
|
def detect_screenshot(client, image):
|
|
640
375
|
icons = 0
|
|
641
376
|
battery_value_and_time = 0
|
|
@@ -667,26 +402,20 @@ def detect_screenshot(client, image):
|
|
|
667
402
|
else:
|
|
668
403
|
return 'clear'
|
|
669
404
|
|
|
670
|
-
|
|
671
405
|
def detect_photo_on_screen(client, image):
|
|
672
406
|
flag = 'clear'
|
|
673
407
|
|
|
674
408
|
image_data = vision_v1.Image(content=base64.b64decode(image))
|
|
675
|
-
|
|
676
409
|
image_response = client.label_detection(image=image_data)
|
|
677
410
|
image_labels = image_response.label_annotations
|
|
678
411
|
|
|
679
412
|
confidence_threshold = 0.58
|
|
680
|
-
|
|
681
413
|
# 'display device'
|
|
682
|
-
|
|
683
414
|
keywords = ['mobile phone', 'mobile device', 'portable communications device', 'communication device', 'smartphone', 'cell phone', 'touchscreen', 'laptop', 'notebook', 'computer', 'screen', 'gadget']
|
|
684
415
|
|
|
685
416
|
for label in image_labels:
|
|
686
417
|
description = label.description.lower()
|
|
687
418
|
confidence = label.score
|
|
688
|
-
# print(f"Description: {description}")
|
|
689
|
-
# print(f"Confidence: {confidence}")
|
|
690
419
|
if confidence >= confidence_threshold:
|
|
691
420
|
match = any(fuzz.ratio(description, keyword.lower()) >= 90 for keyword in keywords)
|
|
692
421
|
if match:
|
|
@@ -699,28 +428,8 @@ def fuzzy_match_fields(field1, field2, threshold=55):
|
|
|
699
428
|
# print(f"similarity: {similarity}")
|
|
700
429
|
return similarity >= threshold
|
|
701
430
|
|
|
702
|
-
def standardize_date(input_date):
|
|
703
|
-
input_formats = [
|
|
704
|
-
"%Y-%m-%d", "%m-%d-%Y", "%Y%m%d",
|
|
705
|
-
"%Y/%m/%d", "%m/%d/%Y", "%d/%m/%Y",
|
|
706
|
-
"%Y.%m.%d", "%d.%m.%Y", "%m.%d.%Y",
|
|
707
|
-
"%Y %m %d", "%d %m %Y", "%m %d %Y",
|
|
708
|
-
]
|
|
709
|
-
|
|
710
|
-
for format in input_formats:
|
|
711
|
-
try:
|
|
712
|
-
parsed_date = datetime.strptime(input_date, format)
|
|
713
|
-
standardized_date = parsed_date.strftime("%d/%m/%Y")
|
|
714
|
-
print(f"\n\n---------------Standardized date: { standardized_date}")
|
|
715
|
-
return standardized_date
|
|
716
|
-
except ValueError:
|
|
717
|
-
pass
|
|
718
|
-
|
|
719
|
-
return None
|
|
720
|
-
|
|
721
431
|
def compare_dates(date_str1, date_str2):
|
|
722
432
|
date_format = "%d/%m/%Y"
|
|
723
|
-
|
|
724
433
|
date1 = datetime.strptime(date_str1, date_format)
|
|
725
434
|
date2 = datetime.strptime(date_str2, date_format)
|
|
726
435
|
|
|
@@ -758,9 +467,6 @@ def data_comparison_check(data, country):
|
|
|
758
467
|
data_comparison['breakdown']['gender']['result'] = 'clear'
|
|
759
468
|
else:
|
|
760
469
|
data_comparison['breakdown']['gender']['result'] = 'consider'
|
|
761
|
-
|
|
762
|
-
# if not fuzzy_match_fields(data.get('gender', '').lower(),user_data.get('gender', '').lower()):
|
|
763
|
-
# data_comparison['breakdown']['gender']['result'] = 'consider'
|
|
764
470
|
|
|
765
471
|
if country == 'IRQ':
|
|
766
472
|
if data.get('doc_type') == 'national_identity_card':
|
|
@@ -796,18 +502,12 @@ def data_comparison_check(data, country):
|
|
|
796
502
|
last_name = data.get('last_name', '')
|
|
797
503
|
|
|
798
504
|
if user_data.get('first_name', ''):
|
|
799
|
-
# print(f'\n\n--------------------------- Extracted first name: {first_name}')
|
|
800
|
-
# print(f"--------------------------- User first name: {user_data.get('first_name', '')}")
|
|
801
|
-
|
|
802
505
|
if fuzzy_match_fields(first_name.lower(), user_data.get('first_name', '').lower()):
|
|
803
506
|
data_comparison['breakdown']['first_name']['result'] = 'clear'
|
|
804
507
|
else:
|
|
805
508
|
data_comparison['breakdown']['first_name']['result'] = 'consider'
|
|
806
509
|
|
|
807
510
|
if user_data.get('last_name', ''):
|
|
808
|
-
# print(f"\n--------------------------- Extracted last name: {last_name}")
|
|
809
|
-
# print(f"--------------------------- User last name: {user_data.get('last_name', '')}")
|
|
810
|
-
|
|
811
511
|
if fuzzy_match_fields(last_name.lower().replace('-', '').replace('_', ''), user_data.get('last_name', '').lower().replace('-', '').replace('_', '')):
|
|
812
512
|
data_comparison['breakdown']['last_name']['result'] = 'clear'
|
|
813
513
|
else:
|
|
@@ -829,15 +529,7 @@ def data_comparison_check(data, country):
|
|
|
829
529
|
|
|
830
530
|
return data_comparison
|
|
831
531
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
532
|
def data_consistency_check(data, front_id_text, back_id_text, country, back_img):
|
|
838
|
-
print(f"Country here: {country}")
|
|
839
|
-
from deep_translator import GoogleTranslator
|
|
840
|
-
|
|
841
533
|
data_consistency = DATA_CONSISTENCY
|
|
842
534
|
data_consistency = mark_clear(data_consistency, ['breakdown', 'result'])
|
|
843
535
|
|
|
@@ -858,42 +550,21 @@ def data_consistency_check(data, front_id_text, back_id_text, country, back_img)
|
|
|
858
550
|
if not fuzzy_match_fields(data.get('last_name').lower(),passport_data.get('passport_surname').lower()):
|
|
859
551
|
data_consistency['breakdown']['last_name']['result'] = 'consider'
|
|
860
552
|
|
|
861
|
-
#### For data consistency compare data from different sources, like id and passport.
|
|
862
|
-
#### so the dob from id should match with dob extracted from passport
|
|
863
|
-
|
|
864
553
|
if country == 'UAE':
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
if
|
|
868
|
-
|
|
869
|
-
else:
|
|
870
|
-
data_consistency['breakdown']['document_type']['result'] = 'consider'
|
|
871
|
-
|
|
872
|
-
if data.get('id_number_front', '') and data.get('id_number', ''):
|
|
873
|
-
if data.get('id_number_front', '') != data.get('id_number', ''):
|
|
554
|
+
|
|
555
|
+
data_consistency['breakdown']['document_type']['result'] = 'clear'
|
|
556
|
+
if data.get('id_number', '') and data.get('id_number_mrz', ''):
|
|
557
|
+
if data.get('id_number', '') != data.get('id_number_mrz', ''):
|
|
874
558
|
data_consistency['breakdown']['multiple_data_sources_present']['result'] = 'consider'
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
if country == 'SAU':
|
|
879
|
-
doc_type1 = identify_front_id(front_id_text)
|
|
880
|
-
if doc_type1:
|
|
881
|
-
data_consistency['breakdown']['document_type']['result'] = 'clear'
|
|
882
|
-
else:
|
|
883
|
-
data_consistency['breakdown']['document_type']['result'] = 'consider'
|
|
884
559
|
|
|
885
560
|
if country == 'IRQ':
|
|
886
|
-
|
|
887
|
-
if 'passport' and ('iraq' or 'republic of iraq') in data.get('passport_data').lower():
|
|
888
|
-
data_consistency['breakdown']['document_type']['result'] = 'clear'
|
|
889
|
-
else:
|
|
890
|
-
data_consistency['breakdown']['document_type']['result'] = 'clear'
|
|
891
|
-
else:
|
|
892
|
-
|
|
893
|
-
data_consistency['breakdown']['document_type']['result'] = 'clear'
|
|
561
|
+
data_consistency['breakdown']['document_type']['result'] = 'clear'
|
|
894
562
|
|
|
895
|
-
front_id_number = data.get('
|
|
896
|
-
back_id_number = data.get('
|
|
563
|
+
front_id_number = data.get('id_number', '')
|
|
564
|
+
back_id_number = data.get('id_number_mrz', '')
|
|
565
|
+
|
|
566
|
+
logging.info(f'Front ID Number: {front_id_number}')
|
|
567
|
+
logging.info(f'Back ID Number: {back_id_number}')
|
|
897
568
|
|
|
898
569
|
if front_id_number and back_id_number:
|
|
899
570
|
if front_id_number != back_id_number:
|
|
@@ -956,42 +627,38 @@ def data_consistency_check(data, front_id_text, back_id_text, country, back_img)
|
|
|
956
627
|
if country in ['LBN', 'SDN', 'SYR', 'JOR', 'PSE']:
|
|
957
628
|
data_consistency['breakdown']['document_type']['result'] = 'clear'
|
|
958
629
|
|
|
959
|
-
## set default to avoid any problems of cache
|
|
960
630
|
data_consistency['result'] = 'clear'
|
|
961
|
-
|
|
962
631
|
result = create_final_result(data_consistency)
|
|
963
632
|
data_consistency['result'] = result
|
|
964
633
|
|
|
965
634
|
if country == 'QAT' and data_consistency['breakdown']['multiple_data_sources_present']['result'] != 'consider':
|
|
966
635
|
data_consistency['result'] = 'clear'
|
|
967
|
-
|
|
968
|
-
logging.info(f"
|
|
636
|
+
|
|
637
|
+
logging.info(f"---------------------------- DATA CONSISTENCY: {data_consistency}")
|
|
969
638
|
|
|
970
639
|
return data_consistency
|
|
971
640
|
|
|
972
|
-
|
|
973
|
-
|
|
641
|
+
def normalize_name_parts(name_parts):
|
|
642
|
+
cleaned = []
|
|
643
|
+
for part in name_parts:
|
|
644
|
+
# split on any non-letter characters #use . as well
|
|
645
|
+
tokens = re.split(r'[^A-Za-z]+', part)
|
|
646
|
+
cleaned.extend(token for token in tokens if token)
|
|
647
|
+
return cleaned
|
|
974
648
|
|
|
975
649
|
def get_name_match_mrz(data, doc_type):
|
|
976
|
-
|
|
977
|
-
if data['nationality'] == 'SDN' and doc_type != 'passport':
|
|
650
|
+
if (data['nationality'] == 'SDN' or data.get('country') == 'UAE') and doc_type != 'passport':
|
|
978
651
|
name_mrz = []
|
|
979
652
|
try:
|
|
980
653
|
for word in data.get("mrz3", "").split("<"):
|
|
981
654
|
if word and word.isalpha():
|
|
982
655
|
name_mrz.append(word)
|
|
983
|
-
|
|
984
|
-
# data['name_mrz'] = " ".join(name_mrz)
|
|
985
|
-
name = data.get("full_name_generic", "")
|
|
986
|
-
name = name.split(" ")
|
|
987
|
-
|
|
988
656
|
except Exception as e:
|
|
989
|
-
|
|
657
|
+
name_mrz = []
|
|
990
658
|
logging.info(f"Error in extracting name from MRZ for SDN ID: {e}")
|
|
991
659
|
pass
|
|
992
660
|
|
|
993
|
-
elif doc_type == 'passport' and data['nationality'] in ['SDN', 'LBN', 'JOR']:
|
|
994
|
-
|
|
661
|
+
elif doc_type == 'passport' and data['nationality'] in ['SDN', 'LBN', 'JOR', 'IRQ', 'PSE', 'SYR']:
|
|
995
662
|
name_mrz = []
|
|
996
663
|
mrz1 = data.get('mrz1', '')
|
|
997
664
|
logging.info(f"MRZ1 extracted: {mrz1}")
|
|
@@ -1005,10 +672,8 @@ def get_name_match_mrz(data, doc_type):
|
|
|
1005
672
|
|
|
1006
673
|
except Exception as e:
|
|
1007
674
|
logging.info(f"Error in extracting name from MRZ for passport: {e}")
|
|
1008
|
-
name_mrz = []
|
|
1009
675
|
pass
|
|
1010
676
|
|
|
1011
|
-
|
|
1012
677
|
if data['nationality'] == 'SDN':
|
|
1013
678
|
name = data.get("full_name_generic", "")
|
|
1014
679
|
|
|
@@ -1018,24 +683,43 @@ def get_name_match_mrz(data, doc_type):
|
|
|
1018
683
|
elif data['nationality'] == 'JOR':
|
|
1019
684
|
name = data.get("name", "")
|
|
1020
685
|
|
|
686
|
+
elif data['nationality'] == 'IRQ':
|
|
687
|
+
name = data.get("name", "")
|
|
688
|
+
logging.info(f"Name extracted for IRQ: {name}")
|
|
689
|
+
|
|
690
|
+
elif data['nationality'] == 'PSE':
|
|
691
|
+
name = data.get("full_name_openai", "")
|
|
692
|
+
|
|
693
|
+
elif data['nationality'] == 'SYR':
|
|
694
|
+
name = data.get("full_name", "")
|
|
695
|
+
|
|
696
|
+
elif data['country'] == 'UAE':
|
|
697
|
+
name = data.get("name", "")
|
|
698
|
+
|
|
1021
699
|
name = name.split(" ")
|
|
700
|
+
logging.info(f"Name extracted from ID: {name}")
|
|
1022
701
|
try:
|
|
1023
702
|
|
|
1024
703
|
logging.info(f"name on card: {name}, name from mrz: {name_mrz}")
|
|
1025
704
|
|
|
1026
705
|
# sort the name parts to ensure order does not affect comparison
|
|
706
|
+
name = normalize_name_parts(name)
|
|
707
|
+
name_mrz = normalize_name_parts(name_mrz)
|
|
708
|
+
logging.info(f"Name parts after removing special chars - Card: {name}, MRZ: {name_mrz}")
|
|
1027
709
|
name = sorted(name)
|
|
1028
|
-
|
|
1029
|
-
logging.info(f"Sorted name on card: {name}, Sorted name from mrz: {
|
|
1030
|
-
min_length = min(len(name), len(
|
|
710
|
+
sorted_name_mrz = sorted(name_mrz)
|
|
711
|
+
logging.info(f"Sorted name on card: {name}, Sorted name from mrz: {sorted_name_mrz}")
|
|
712
|
+
min_length = min(len(name), len(sorted_name_mrz))
|
|
713
|
+
logging.info(f"Name parts after removing special chars - Card: {name}, MRZ: {sorted_name_mrz}")
|
|
714
|
+
min_length = min(len(name), len(sorted_name_mrz))
|
|
1031
715
|
|
|
1032
716
|
from rapidfuzz import fuzz
|
|
1033
717
|
flag = True
|
|
1034
718
|
|
|
1035
719
|
count = 0
|
|
1036
720
|
for i in range(min_length):
|
|
1037
|
-
ratio = fuzz.ratio(name[i].lower(),
|
|
1038
|
-
logging.info(f"Comparing name parts: {name[i]} and {
|
|
721
|
+
ratio = fuzz.ratio(name[i].lower(), sorted_name_mrz[i].lower())
|
|
722
|
+
logging.info(f"Comparing name parts: {name[i]} and {sorted_name_mrz[i]}, ratio: {ratio}")
|
|
1039
723
|
if ratio < 70:
|
|
1040
724
|
count = count +1
|
|
1041
725
|
|
|
@@ -1069,7 +753,6 @@ def is_age_18_above(dob_str):
|
|
|
1069
753
|
logging.warning(f"Could not parse date: {dob_str}")
|
|
1070
754
|
return False
|
|
1071
755
|
|
|
1072
|
-
|
|
1073
756
|
def is_expired_id(expiry_date):
|
|
1074
757
|
"""
|
|
1075
758
|
Checks if an ID is expired.
|
|
@@ -1120,7 +803,6 @@ def data_validation_check(data, country):
|
|
|
1120
803
|
|
|
1121
804
|
try:
|
|
1122
805
|
dob = data.get('dob')
|
|
1123
|
-
# print(f"DOB: {dob}")
|
|
1124
806
|
dob = get_dates_to_generic_format(dob)
|
|
1125
807
|
parsed_date = datetime.strptime(dob, "%d/%m/%Y")
|
|
1126
808
|
data_validation["breakdown"]['date_of_birth']["result"] = 'clear'
|
|
@@ -1216,7 +898,7 @@ def data_validation_check(data, country):
|
|
|
1216
898
|
data_validation["breakdown"]['expiry_date']["result"] = 'clear'
|
|
1217
899
|
|
|
1218
900
|
if country == 'IRQ' and data.get('doc_type') == 'national_identity_card' and not data.get('card_number'):
|
|
1219
|
-
doc_no = data.get('
|
|
901
|
+
doc_no = data.get('card_number', '')
|
|
1220
902
|
if len(doc_no)==9:
|
|
1221
903
|
data_validation["breakdown"]['document_numbers']["result"] = 'clear'
|
|
1222
904
|
else:
|
|
@@ -1246,7 +928,6 @@ def data_validation_check(data, country):
|
|
|
1246
928
|
else:
|
|
1247
929
|
data_validation['breakdown']['expiry_date']['result'] = 'consider'
|
|
1248
930
|
|
|
1249
|
-
|
|
1250
931
|
result = create_final_result(data_validation)
|
|
1251
932
|
data_validation['result'] = result
|
|
1252
933
|
|
|
@@ -1255,7 +936,6 @@ def data_validation_check(data, country):
|
|
|
1255
936
|
|
|
1256
937
|
## pending
|
|
1257
938
|
def image_integrity_check(data, front_id_text, back_id_text, coloured, blurred, glare, missing_fields, country):
|
|
1258
|
-
from deep_translator import GoogleTranslator
|
|
1259
939
|
image_integrity = IMAGE_INTEGRITY
|
|
1260
940
|
image_integrity = mark_clear(image_integrity, ['breakdown', 'result'])
|
|
1261
941
|
|
|
@@ -1275,14 +955,13 @@ def image_integrity_check(data, front_id_text, back_id_text, coloured, blurred,
|
|
|
1275
955
|
image_quality_result = create_final_result(image_integrity['breakdown']['image_quality'])
|
|
1276
956
|
image_integrity['breakdown']['image_quality']['result'] = image_quality_result
|
|
1277
957
|
|
|
1278
|
-
f_result =
|
|
1279
|
-
if data.get('doc_type') == 'national_identity_card':
|
|
1280
|
-
f_result = identify_front_id(front_id_text)
|
|
1281
|
-
|
|
958
|
+
f_result = True
|
|
1282
959
|
front_doc_on_pp = data.get('front_doc_on_pp')
|
|
1283
960
|
|
|
1284
961
|
if country == 'UAE' and not data.get('uae_pass_data', ''):
|
|
1285
|
-
|
|
962
|
+
logging.info(f"UAE Image integrity check for ID card or passport {back_id_text}")
|
|
963
|
+
b_result = True
|
|
964
|
+
logging.info(f"UAE back id result: {b_result}")
|
|
1286
965
|
|
|
1287
966
|
if back_id_text and b_result:
|
|
1288
967
|
image_integrity['breakdown']['conclusive_document_quality']['properties']['missing_back'] = 'clear'
|
|
@@ -1293,21 +972,11 @@ def image_integrity_check(data, front_id_text, back_id_text, coloured, blurred,
|
|
|
1293
972
|
image_integrity['breakdown']['supported_document']['result'] = 'clear'
|
|
1294
973
|
else:
|
|
1295
974
|
image_integrity['breakdown']['supported_document']['result'] = 'consider'
|
|
1296
|
-
|
|
1297
|
-
if country == 'SAU':
|
|
1298
|
-
if f_result:
|
|
1299
|
-
image_integrity['breakdown']['supported_document']['result'] = 'clear'
|
|
1300
|
-
else:
|
|
1301
|
-
image_integrity['breakdown']['supported_document']['result'] = 'consider'
|
|
1302
|
-
|
|
1303
|
-
image_integrity['breakdown']['conclusive_document_quality']['properties']['digital_document'] = front_doc_on_pp
|
|
1304
975
|
|
|
1305
976
|
if country == 'IRQ' and data.get('doc_type') == 'national_identity_card':
|
|
1306
977
|
image_integrity['breakdown']['conclusive_document_quality']['properties']['missing_back'] = 'clear'
|
|
1307
978
|
image_integrity['breakdown']['supported_document']['result'] = 'clear'
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
979
|
+
|
|
1311
980
|
elif country == 'IRQ' and data.get('doc_type') == 'passport':
|
|
1312
981
|
image_integrity['breakdown']['conclusive_document_quality']['properties']['missing_back'] = 'clear'
|
|
1313
982
|
if 'passport' and ('iraq' or 'republic of iraq') in data.get('passport_data').lower():
|
|
@@ -1383,20 +1052,18 @@ def image_integrity_check(data, front_id_text, back_id_text, coloured, blurred,
|
|
|
1383
1052
|
if country=='IRQ':
|
|
1384
1053
|
image_integrity['result']='clear'
|
|
1385
1054
|
|
|
1386
|
-
|
|
1387
|
-
logging.info(f"\n\n---------------------------- IMAGE INTEGRITY: {image_integrity}")
|
|
1055
|
+
logging.info(f"---------------------------- IMAGE INTEGRITY: {image_integrity}")
|
|
1388
1056
|
|
|
1389
1057
|
return image_integrity
|
|
1390
1058
|
|
|
1391
1059
|
def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_similarity, face_match_threshold, country):
|
|
1392
|
-
from deep_translator import GoogleTranslator
|
|
1393
1060
|
visual_authenticity = VISUAL_AUTHENTICITY
|
|
1394
1061
|
visual_authenticity = mark_clear(visual_authenticity, ['breakdown', 'result'])
|
|
1395
1062
|
|
|
1396
1063
|
if np.any(selfie):
|
|
1397
1064
|
## if facial similarity is matching the threshold or even if facial similarity comes above 40 then we say face was detected - approach can be changed
|
|
1398
1065
|
logging.info(f'Facial similarity: {facial_similarity}, Threshold: {face_match_threshold}\n')
|
|
1399
|
-
if facial_similarity
|
|
1066
|
+
if facial_similarity >= face_match_threshold:
|
|
1400
1067
|
visual_authenticity['breakdown']['face_detection'] = 'clear'
|
|
1401
1068
|
visual_authenticity['breakdown']['security_features'] = 'clear'
|
|
1402
1069
|
else:
|
|
@@ -1406,9 +1073,6 @@ def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_
|
|
|
1406
1073
|
visual_authenticity['breakdown']['face_detection'] = ''
|
|
1407
1074
|
visual_authenticity['breakdown']['security_features'] = ''
|
|
1408
1075
|
|
|
1409
|
-
if data.get('doc_type') == 'national_identity_card':
|
|
1410
|
-
doc_type1 = identify_document_type(front_id_text, country, front_id_text)
|
|
1411
|
-
|
|
1412
1076
|
front_doc_on_pp = data.get('front_doc_on_pp')
|
|
1413
1077
|
front_screenshot = data.get('front_screenshot_result')
|
|
1414
1078
|
front_photo_on_screen_result = data.get('front_photo_on_screen_result')
|
|
@@ -1423,35 +1087,18 @@ def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_
|
|
|
1423
1087
|
visual_authenticity['breakdown']['original_document_present']['properties']['photo_of_screen'] = 'consider'
|
|
1424
1088
|
|
|
1425
1089
|
if country == 'UAE' and not data.get('uae_pass_data', ''):
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'consider'
|
|
1431
|
-
|
|
1432
|
-
if country == 'SAU':
|
|
1433
|
-
if identify_front_id(front_id_text):
|
|
1434
|
-
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1435
|
-
else:
|
|
1436
|
-
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'consider'
|
|
1437
|
-
|
|
1438
|
-
visual_authenticity['breakdown']['original_document_present']['properties']['document_on_printed_paper'] = front_doc_on_pp
|
|
1439
|
-
visual_authenticity['breakdown']['original_document_present']['properties']['screenshot'] = front_screenshot
|
|
1440
|
-
visual_authenticity['breakdown']['original_document_present']['properties']['photo_of_screen'] = front_photo_on_screen_result
|
|
1441
|
-
|
|
1090
|
+
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1091
|
+
visual_authenticity['breakdown']['face_detection'] = 'clear'
|
|
1092
|
+
visual_authenticity['breakdown']['security_features'] = 'clear'
|
|
1093
|
+
|
|
1442
1094
|
if country == 'IRQ':
|
|
1443
1095
|
if data.get('doc_type') == 'passport':
|
|
1444
|
-
|
|
1445
|
-
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1446
|
-
else:
|
|
1447
|
-
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1096
|
+
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1448
1097
|
else:
|
|
1449
|
-
|
|
1450
1098
|
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1451
1099
|
visual_authenticity['breakdown']['template']['result'] = data.get('front_template_result')
|
|
1452
1100
|
visual_authenticity['breakdown']['digital_tampering']['result'] = data.get('tampering_result')
|
|
1453
|
-
|
|
1454
|
-
|
|
1101
|
+
|
|
1455
1102
|
if country == 'LBN':
|
|
1456
1103
|
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1457
1104
|
visual_authenticity['breakdown']['original_document_present']['properties']['screenshot'] = 'clear'
|
|
@@ -1466,7 +1113,6 @@ def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_
|
|
|
1466
1113
|
visual_authenticity['breakdown']['digital_tampering']['result'] = 'clear'
|
|
1467
1114
|
visual_authenticity['breakdown']['template']['result'] = 'clear'
|
|
1468
1115
|
|
|
1469
|
-
|
|
1470
1116
|
if country in ['SDN', 'SYR', 'JOR', 'PSE']:
|
|
1471
1117
|
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1472
1118
|
visual_authenticity['breakdown']['original_document_present']['properties']['screenshot'] = 'clear'
|
|
@@ -1478,12 +1124,9 @@ def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_
|
|
|
1478
1124
|
|
|
1479
1125
|
## set default to avoid any problems of cache
|
|
1480
1126
|
visual_authenticity['result'] = 'clear'
|
|
1481
|
-
|
|
1482
1127
|
final_result = create_final_result(visual_authenticity)
|
|
1483
1128
|
visual_authenticity['result'] = final_result
|
|
1484
1129
|
|
|
1485
|
-
# print(f"\n\n------------------------- VISUAL AUTHENTICITY DOC: {visual_authenticity}")
|
|
1486
|
-
|
|
1487
1130
|
back_doc_on_pp = data.get('doc_on_pp')
|
|
1488
1131
|
if front_doc_on_pp == 'consider' or back_doc_on_pp == 'consider':
|
|
1489
1132
|
visual_authenticity['breakdown']['original_document_present']['properties']['document_on_printed_paper'] = 'consider'
|
|
@@ -1493,7 +1136,7 @@ def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_
|
|
|
1493
1136
|
visual_authenticity['breakdown']['original_document_present']['properties']['document_on_printed_paper'] = 'clear'
|
|
1494
1137
|
visual_authenticity['result'] = 'clear'
|
|
1495
1138
|
|
|
1496
|
-
logging.info(f"
|
|
1139
|
+
logging.info(f"---------------------------- VISUAL AUTHENTICITY: {visual_authenticity}")
|
|
1497
1140
|
return visual_authenticity
|
|
1498
1141
|
|
|
1499
1142
|
def main_details(data, country):
|
|
@@ -1689,15 +1332,30 @@ def main_details(data, country):
|
|
|
1689
1332
|
for key in keys:
|
|
1690
1333
|
main_properties[key] = data.get(key, '')
|
|
1691
1334
|
|
|
1692
|
-
if country in ['IRQ', 'LBN', 'QAT', 'SDN', 'SYR', 'JOR', 'PSE']:
|
|
1335
|
+
if country in ['IRQ', 'LBN', 'QAT', 'SDN', 'SYR', 'JOR', 'PSE', 'UAE']:
|
|
1336
|
+
|
|
1337
|
+
if country == 'UAE':
|
|
1338
|
+
main_prop_data = {}
|
|
1339
|
+
if data.get('doc_type') == 'national_identity_card':
|
|
1340
|
+
keys = ['dob_mrz', 'expiry_date_mrz', 'id_number_mrz', 'name_mrz', 'card_number_mrz','is_name_match_mrz',
|
|
1341
|
+
'id_number_front_back_mrz_match','card_number_back_mrz_match','dob_mrz_match','expiry_date_mrz_match','gender_mrz_match','name_mrz_match'
|
|
1342
|
+
]
|
|
1343
|
+
keys_to_remove = []
|
|
1693
1344
|
if country == 'IRQ':
|
|
1694
1345
|
main_prop_data = {}
|
|
1695
1346
|
if data.get('doc_type') == 'passport':
|
|
1347
|
+
logging.info(f"Extracting main details for IRQ passport")
|
|
1696
1348
|
keys_to_remove = ['issuing_place', 'occupation', 'employer', 'mrz_line3', 'family_sponsor', 'issuing_authority_en', 'place_of_birth_en', 'gender_ar', 'name_en', 'name', 'first_name']
|
|
1697
|
-
keys = ['full_name', 'id_number', 'mrz', 'issue_date','issuing_authority', 'mother_name', 'place_of_birth', 'mother_first_name', 'mother_first_name_en', 'mother_last_name',
|
|
1349
|
+
keys = ['full_name', 'id_number', 'mrz', 'issue_date','issuing_authority', 'mother_name', 'place_of_birth', 'mother_first_name', 'mother_first_name_en', 'mother_last_name',
|
|
1350
|
+
'mother_last_name_en','expiry_date_mrz','dob_mrz', 'gender_mrz','id_number_mrz','name_mrz','is_name_match_mrz',
|
|
1351
|
+
'is_dob_match_mrz', 'is_id_number_match_mrz','is_expiry_date_match_mrz','is_valid_id_duration','is_valid_id_duration_mrz','is_gender_mrz_match']
|
|
1698
1352
|
else:
|
|
1699
1353
|
keys_to_remove = ['occupation', 'employer', 'family_sponsor', 'issuing_place']
|
|
1700
|
-
keys = ['name_en', 'name', 'first_name', 'father_name', 'third_name', 'mother_first_name', 'mother_last_name',
|
|
1354
|
+
keys = ['name_en', 'name', 'first_name', 'father_name', 'third_name', 'mother_first_name', 'mother_last_name',
|
|
1355
|
+
'last_name', 'first_name_en', 'father_name_en', 'last_name_en', 'third_name_en', 'mother_first_name_en',
|
|
1356
|
+
'mother_last_name_en', 'issuing_authority', 'nationality', 'gender', 'issuing_country', 'gender_ar', 'mrz',
|
|
1357
|
+
'place_of_birth', 'issuing_authority_en', 'place_of_birth_en', "issue_date", "id_number", "card_number", 'family_number', 'family_number_en',
|
|
1358
|
+
'card_number_mrz', 'id_number_mrz', 'valid_id_duration_mrz', 'dob_back_and_mrz_match', 'exp_date_back_and_mrz_match', 'gender_front_and_back_match', 'id_number_front_back_match']
|
|
1701
1359
|
|
|
1702
1360
|
if country == 'LBN':
|
|
1703
1361
|
main_prop_data = {}
|
|
@@ -1749,18 +1407,25 @@ def main_details(data, country):
|
|
|
1749
1407
|
main_prop_data = {}
|
|
1750
1408
|
keys_to_remove = ['name', 'issuing_place', 'occupation', 'employer', 'mrz_line3', 'family_sponsor', 'issuing_country']
|
|
1751
1409
|
if data.get('doc_type') == 'passport':
|
|
1752
|
-
keys = ['full_name', 'first_name', 'last_name', 'father_name', 'mother_name', 'place_of_birth', 'place_of_issue', 'dob', 'nationality', 'gender', 'passport_number', 'issue_number',
|
|
1410
|
+
keys = ['full_name', 'first_name', 'last_name', 'father_name', 'mother_name', 'place_of_birth', 'place_of_issue', 'dob', 'nationality', 'gender', 'passport_number', 'issue_number',
|
|
1411
|
+
'issuing_date', 'national_number', 'mrz1', 'mrz2', 'mrz', 'issuing_country',
|
|
1412
|
+
'passport_number_mrz','name_mrz', 'dob_mrz', 'expiry_date_mrz','gender_mrz',
|
|
1413
|
+
'is_valid_id_duration','is_valid_id_duration_mrz','is_passport_number_match_mrz','is_dob_match_mrz','is_gender_mrz_match','is_name_match_mrz']
|
|
1753
1414
|
|
|
1754
1415
|
|
|
1755
1416
|
if country == 'PSE':
|
|
1756
1417
|
main_prop_data = {}
|
|
1757
1418
|
keys_to_remove = ['name', 'issuing_place', 'occupation', 'employer', 'mrz_line3', 'family_sponsor']
|
|
1758
1419
|
if data.get('doc_type') == 'passport':
|
|
1759
|
-
keys = ['full_name', 'first_name', 'last_name', 'mother_name', 'place_of_birth', 'dob', 'issuing_date', 'nationality', 'gender',
|
|
1420
|
+
keys = ['full_name', 'first_name', 'last_name', 'mother_name', 'place_of_birth', 'dob', 'issuing_date', 'nationality', 'gender',
|
|
1421
|
+
'place_of_issue', 'passport_number', 'id_number', 'mrz1', 'mrz2', 'mrz', 'issuing_country',
|
|
1422
|
+
'passport_number_mrz','name_mrz', 'dob_mrz', 'expiry_date_mrz','gender_mrz',
|
|
1423
|
+
'is_valid_id_duration','is_valid_id_duration_mrz','is_passport_number_match_mrz','is_dob_match_mrz','is_gender_mrz_match','is_name_match_mrz']
|
|
1760
1424
|
|
|
1761
1425
|
for key in keys:
|
|
1762
1426
|
main_prop_data[key] = data.get(key, '')
|
|
1763
1427
|
|
|
1428
|
+
logging.info(f"Main properties before removal: {main_prop_data.keys()}")
|
|
1764
1429
|
if keys_to_remove:
|
|
1765
1430
|
for key in keys_to_remove:
|
|
1766
1431
|
if key in main_properties:
|
|
@@ -1771,7 +1436,6 @@ def main_details(data, country):
|
|
|
1771
1436
|
if main_properties.get('issue_date', ''):
|
|
1772
1437
|
main_properties['issue_date'] = onfido_date_format(get_dates_to_generic_format(main_properties['issue_date']))
|
|
1773
1438
|
|
|
1774
|
-
|
|
1775
1439
|
|
|
1776
1440
|
if not data.get('card_number') and data.get('card_number_front'):
|
|
1777
1441
|
card_data_t = {
|
|
@@ -1823,7 +1487,6 @@ def form_final_data_document_report(data, front_id_text, back_id_text, country,
|
|
|
1823
1487
|
dob = data.get('dob', '')
|
|
1824
1488
|
|
|
1825
1489
|
document_report = {
|
|
1826
|
-
## pending - to be filled by dev
|
|
1827
1490
|
"_id": "",
|
|
1828
1491
|
"breakdown": {
|
|
1829
1492
|
"age_validation": age_validation(dob),
|
|
@@ -1847,20 +1510,16 @@ def form_final_data_document_report(data, front_id_text, back_id_text, country,
|
|
|
1847
1510
|
"police_record": {},
|
|
1848
1511
|
"visual_authenticity": visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_similarity, face_match_threshold, country)
|
|
1849
1512
|
},
|
|
1850
|
-
## pending - to be filled by dev
|
|
1851
1513
|
"check_id": "",
|
|
1852
1514
|
"created_at": created_at(),
|
|
1853
1515
|
"documents": [
|
|
1854
1516
|
{
|
|
1855
|
-
## pending - id value in table stored in db for front id - to be filled by dev
|
|
1856
1517
|
"id": ""
|
|
1857
1518
|
},
|
|
1858
1519
|
{
|
|
1859
|
-
## pending - id value in table stored in db for front id - to be filled by dev
|
|
1860
1520
|
"id": ""
|
|
1861
1521
|
}
|
|
1862
1522
|
],
|
|
1863
|
-
# to be filled by dev
|
|
1864
1523
|
"href": "",
|
|
1865
1524
|
"name": "document",
|
|
1866
1525
|
"properties": main_details(data, country),
|
|
@@ -1960,7 +1619,6 @@ def form_final_facial_similarity_report(data, selfie, facial_similarity, livenes
|
|
|
1960
1619
|
facial_report['breakdown']['visual_authenticity']['breakdown']['spoofing_detection']['properties']['score'] = ''
|
|
1961
1620
|
facial_report['breakdown']['visual_authenticity']['breakdown']['spoofing_detection']['result'] = ''
|
|
1962
1621
|
|
|
1963
|
-
# if np.any(selfie) and liveness_result:
|
|
1964
1622
|
visual_authenticity_final_result = create_final_result(facial_report['breakdown']['visual_authenticity'])
|
|
1965
1623
|
facial_report['breakdown']['visual_authenticity']['result'] = visual_authenticity_final_result
|
|
1966
1624
|
|