idvpackage 3.0.11__py3-none-any.whl → 3.0.13__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 +8 -966
- 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 +1016 -2430
- idvpackage/ocr_utils.py +148 -489
- 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.11.dist-info → idvpackage-3.0.13.dist-info}/METADATA +1 -1
- idvpackage-3.0.13.dist-info/RECORD +34 -0
- {idvpackage-3.0.11.dist-info → idvpackage-3.0.13.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.11.dist-info/RECORD +0 -42
- {idvpackage-3.0.11.dist-info → idvpackage-3.0.13.dist-info}/licenses/LICENSE +0 -0
- {idvpackage-3.0.11.dist-info → idvpackage-3.0.13.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,46 +550,26 @@ 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
|
-
|
|
896
|
-
|
|
563
|
+
if data.get('doc_type') == 'national_identity_card':
|
|
564
|
+
front_id_number = data.get('id_number', '')
|
|
565
|
+
back_id_number = data.get('id_number_mrz', '')
|
|
566
|
+
|
|
567
|
+
logging.info(f'Front ID Number: {front_id_number}')
|
|
568
|
+
logging.info(f'Back ID Number: {back_id_number}')
|
|
897
569
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
570
|
+
if front_id_number and back_id_number:
|
|
571
|
+
if front_id_number != back_id_number:
|
|
572
|
+
data_consistency['breakdown']['multiple_data_sources_present']['result'] = 'consider'
|
|
901
573
|
|
|
902
574
|
if country == 'QAT':
|
|
903
575
|
data_consistency['breakdown']['gender']['result'] = 'clear'
|
|
@@ -956,42 +628,38 @@ def data_consistency_check(data, front_id_text, back_id_text, country, back_img)
|
|
|
956
628
|
if country in ['LBN', 'SDN', 'SYR', 'JOR', 'PSE']:
|
|
957
629
|
data_consistency['breakdown']['document_type']['result'] = 'clear'
|
|
958
630
|
|
|
959
|
-
## set default to avoid any problems of cache
|
|
960
631
|
data_consistency['result'] = 'clear'
|
|
961
|
-
|
|
962
632
|
result = create_final_result(data_consistency)
|
|
963
633
|
data_consistency['result'] = result
|
|
964
634
|
|
|
965
635
|
if country == 'QAT' and data_consistency['breakdown']['multiple_data_sources_present']['result'] != 'consider':
|
|
966
636
|
data_consistency['result'] = 'clear'
|
|
967
|
-
|
|
968
|
-
logging.info(f"
|
|
637
|
+
|
|
638
|
+
logging.info(f"---------------------------- DATA CONSISTENCY: {data_consistency}")
|
|
969
639
|
|
|
970
640
|
return data_consistency
|
|
971
641
|
|
|
972
|
-
|
|
973
|
-
|
|
642
|
+
def normalize_name_parts(name_parts):
|
|
643
|
+
cleaned = []
|
|
644
|
+
for part in name_parts:
|
|
645
|
+
# split on any non-letter characters #use . as well
|
|
646
|
+
tokens = re.split(r'[^A-Za-z]+', part)
|
|
647
|
+
cleaned.extend(token for token in tokens if token)
|
|
648
|
+
return cleaned
|
|
974
649
|
|
|
975
650
|
def get_name_match_mrz(data, doc_type):
|
|
976
|
-
|
|
977
|
-
if data['nationality'] == 'SDN' and doc_type != 'passport':
|
|
651
|
+
if (data['nationality'] == 'SDN' or data.get('country') == 'UAE') and doc_type != 'passport':
|
|
978
652
|
name_mrz = []
|
|
979
653
|
try:
|
|
980
654
|
for word in data.get("mrz3", "").split("<"):
|
|
981
655
|
if word and word.isalpha():
|
|
982
656
|
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
657
|
except Exception as e:
|
|
989
|
-
|
|
658
|
+
name_mrz = []
|
|
990
659
|
logging.info(f"Error in extracting name from MRZ for SDN ID: {e}")
|
|
991
660
|
pass
|
|
992
661
|
|
|
993
|
-
elif doc_type == 'passport' and data['nationality'] in ['SDN', 'LBN', 'JOR']:
|
|
994
|
-
|
|
662
|
+
elif doc_type == 'passport' and data['nationality'] in ['SDN', 'LBN', 'JOR', 'IRQ', 'PSE', 'SYR']:
|
|
995
663
|
name_mrz = []
|
|
996
664
|
mrz1 = data.get('mrz1', '')
|
|
997
665
|
logging.info(f"MRZ1 extracted: {mrz1}")
|
|
@@ -1005,10 +673,8 @@ def get_name_match_mrz(data, doc_type):
|
|
|
1005
673
|
|
|
1006
674
|
except Exception as e:
|
|
1007
675
|
logging.info(f"Error in extracting name from MRZ for passport: {e}")
|
|
1008
|
-
name_mrz = []
|
|
1009
676
|
pass
|
|
1010
677
|
|
|
1011
|
-
|
|
1012
678
|
if data['nationality'] == 'SDN':
|
|
1013
679
|
name = data.get("full_name_generic", "")
|
|
1014
680
|
|
|
@@ -1018,24 +684,43 @@ def get_name_match_mrz(data, doc_type):
|
|
|
1018
684
|
elif data['nationality'] == 'JOR':
|
|
1019
685
|
name = data.get("name", "")
|
|
1020
686
|
|
|
687
|
+
elif data['nationality'] == 'IRQ':
|
|
688
|
+
name = data.get("full_name", "")
|
|
689
|
+
logging.info(f"Name extracted for IRQ: {name}")
|
|
690
|
+
|
|
691
|
+
elif data['nationality'] == 'PSE':
|
|
692
|
+
name = data.get("full_name_openai", "")
|
|
693
|
+
|
|
694
|
+
elif data['nationality'] == 'SYR':
|
|
695
|
+
name = data.get("full_name", "")
|
|
696
|
+
|
|
697
|
+
elif data['country'] == 'UAE':
|
|
698
|
+
name = data.get("name", "")
|
|
699
|
+
|
|
1021
700
|
name = name.split(" ")
|
|
701
|
+
logging.info(f"Name extracted from ID: {name}")
|
|
1022
702
|
try:
|
|
1023
703
|
|
|
1024
704
|
logging.info(f"name on card: {name}, name from mrz: {name_mrz}")
|
|
1025
705
|
|
|
1026
706
|
# sort the name parts to ensure order does not affect comparison
|
|
707
|
+
name = normalize_name_parts(name)
|
|
708
|
+
name_mrz = normalize_name_parts(name_mrz)
|
|
709
|
+
logging.info(f"Name parts after removing special chars - Card: {name}, MRZ: {name_mrz}")
|
|
1027
710
|
name = sorted(name)
|
|
1028
|
-
|
|
1029
|
-
logging.info(f"Sorted name on card: {name}, Sorted name from mrz: {
|
|
1030
|
-
min_length = min(len(name), len(
|
|
711
|
+
sorted_name_mrz = sorted(name_mrz)
|
|
712
|
+
logging.info(f"Sorted name on card: {name}, Sorted name from mrz: {sorted_name_mrz}")
|
|
713
|
+
min_length = min(len(name), len(sorted_name_mrz))
|
|
714
|
+
logging.info(f"Name parts after removing special chars - Card: {name}, MRZ: {sorted_name_mrz}")
|
|
715
|
+
min_length = min(len(name), len(sorted_name_mrz))
|
|
1031
716
|
|
|
1032
717
|
from rapidfuzz import fuzz
|
|
1033
718
|
flag = True
|
|
1034
719
|
|
|
1035
720
|
count = 0
|
|
1036
721
|
for i in range(min_length):
|
|
1037
|
-
ratio = fuzz.ratio(name[i].lower(),
|
|
1038
|
-
logging.info(f"Comparing name parts: {name[i]} and {
|
|
722
|
+
ratio = fuzz.ratio(name[i].lower(), sorted_name_mrz[i].lower())
|
|
723
|
+
logging.info(f"Comparing name parts: {name[i]} and {sorted_name_mrz[i]}, ratio: {ratio}")
|
|
1039
724
|
if ratio < 70:
|
|
1040
725
|
count = count +1
|
|
1041
726
|
|
|
@@ -1069,7 +754,6 @@ def is_age_18_above(dob_str):
|
|
|
1069
754
|
logging.warning(f"Could not parse date: {dob_str}")
|
|
1070
755
|
return False
|
|
1071
756
|
|
|
1072
|
-
|
|
1073
757
|
def is_expired_id(expiry_date):
|
|
1074
758
|
"""
|
|
1075
759
|
Checks if an ID is expired.
|
|
@@ -1120,7 +804,6 @@ def data_validation_check(data, country):
|
|
|
1120
804
|
|
|
1121
805
|
try:
|
|
1122
806
|
dob = data.get('dob')
|
|
1123
|
-
# print(f"DOB: {dob}")
|
|
1124
807
|
dob = get_dates_to_generic_format(dob)
|
|
1125
808
|
parsed_date = datetime.strptime(dob, "%d/%m/%Y")
|
|
1126
809
|
data_validation["breakdown"]['date_of_birth']["result"] = 'clear'
|
|
@@ -1216,7 +899,7 @@ def data_validation_check(data, country):
|
|
|
1216
899
|
data_validation["breakdown"]['expiry_date']["result"] = 'clear'
|
|
1217
900
|
|
|
1218
901
|
if country == 'IRQ' and data.get('doc_type') == 'national_identity_card' and not data.get('card_number'):
|
|
1219
|
-
doc_no = data.get('
|
|
902
|
+
doc_no = data.get('card_number', '')
|
|
1220
903
|
if len(doc_no)==9:
|
|
1221
904
|
data_validation["breakdown"]['document_numbers']["result"] = 'clear'
|
|
1222
905
|
else:
|
|
@@ -1246,7 +929,6 @@ def data_validation_check(data, country):
|
|
|
1246
929
|
else:
|
|
1247
930
|
data_validation['breakdown']['expiry_date']['result'] = 'consider'
|
|
1248
931
|
|
|
1249
|
-
|
|
1250
932
|
result = create_final_result(data_validation)
|
|
1251
933
|
data_validation['result'] = result
|
|
1252
934
|
|
|
@@ -1255,7 +937,6 @@ def data_validation_check(data, country):
|
|
|
1255
937
|
|
|
1256
938
|
## pending
|
|
1257
939
|
def image_integrity_check(data, front_id_text, back_id_text, coloured, blurred, glare, missing_fields, country):
|
|
1258
|
-
from deep_translator import GoogleTranslator
|
|
1259
940
|
image_integrity = IMAGE_INTEGRITY
|
|
1260
941
|
image_integrity = mark_clear(image_integrity, ['breakdown', 'result'])
|
|
1261
942
|
|
|
@@ -1275,14 +956,13 @@ def image_integrity_check(data, front_id_text, back_id_text, coloured, blurred,
|
|
|
1275
956
|
image_quality_result = create_final_result(image_integrity['breakdown']['image_quality'])
|
|
1276
957
|
image_integrity['breakdown']['image_quality']['result'] = image_quality_result
|
|
1277
958
|
|
|
1278
|
-
f_result =
|
|
1279
|
-
if data.get('doc_type') == 'national_identity_card':
|
|
1280
|
-
f_result = identify_front_id(front_id_text)
|
|
1281
|
-
|
|
959
|
+
f_result = True
|
|
1282
960
|
front_doc_on_pp = data.get('front_doc_on_pp')
|
|
1283
961
|
|
|
1284
962
|
if country == 'UAE' and not data.get('uae_pass_data', ''):
|
|
1285
|
-
|
|
963
|
+
logging.info(f"UAE Image integrity check for ID card or passport {back_id_text}")
|
|
964
|
+
b_result = True
|
|
965
|
+
logging.info(f"UAE back id result: {b_result}")
|
|
1286
966
|
|
|
1287
967
|
if back_id_text and b_result:
|
|
1288
968
|
image_integrity['breakdown']['conclusive_document_quality']['properties']['missing_back'] = 'clear'
|
|
@@ -1293,21 +973,11 @@ def image_integrity_check(data, front_id_text, back_id_text, coloured, blurred,
|
|
|
1293
973
|
image_integrity['breakdown']['supported_document']['result'] = 'clear'
|
|
1294
974
|
else:
|
|
1295
975
|
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
976
|
|
|
1305
977
|
if country == 'IRQ' and data.get('doc_type') == 'national_identity_card':
|
|
1306
978
|
image_integrity['breakdown']['conclusive_document_quality']['properties']['missing_back'] = 'clear'
|
|
1307
979
|
image_integrity['breakdown']['supported_document']['result'] = 'clear'
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
980
|
+
|
|
1311
981
|
elif country == 'IRQ' and data.get('doc_type') == 'passport':
|
|
1312
982
|
image_integrity['breakdown']['conclusive_document_quality']['properties']['missing_back'] = 'clear'
|
|
1313
983
|
if 'passport' and ('iraq' or 'republic of iraq') in data.get('passport_data').lower():
|
|
@@ -1383,20 +1053,18 @@ def image_integrity_check(data, front_id_text, back_id_text, coloured, blurred,
|
|
|
1383
1053
|
if country=='IRQ':
|
|
1384
1054
|
image_integrity['result']='clear'
|
|
1385
1055
|
|
|
1386
|
-
|
|
1387
|
-
logging.info(f"\n\n---------------------------- IMAGE INTEGRITY: {image_integrity}")
|
|
1056
|
+
logging.info(f"---------------------------- IMAGE INTEGRITY: {image_integrity}")
|
|
1388
1057
|
|
|
1389
1058
|
return image_integrity
|
|
1390
1059
|
|
|
1391
1060
|
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
1061
|
visual_authenticity = VISUAL_AUTHENTICITY
|
|
1394
1062
|
visual_authenticity = mark_clear(visual_authenticity, ['breakdown', 'result'])
|
|
1395
1063
|
|
|
1396
1064
|
if np.any(selfie):
|
|
1397
1065
|
## 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
1066
|
logging.info(f'Facial similarity: {facial_similarity}, Threshold: {face_match_threshold}\n')
|
|
1399
|
-
if facial_similarity
|
|
1067
|
+
if facial_similarity >= face_match_threshold:
|
|
1400
1068
|
visual_authenticity['breakdown']['face_detection'] = 'clear'
|
|
1401
1069
|
visual_authenticity['breakdown']['security_features'] = 'clear'
|
|
1402
1070
|
else:
|
|
@@ -1406,9 +1074,6 @@ def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_
|
|
|
1406
1074
|
visual_authenticity['breakdown']['face_detection'] = ''
|
|
1407
1075
|
visual_authenticity['breakdown']['security_features'] = ''
|
|
1408
1076
|
|
|
1409
|
-
if data.get('doc_type') == 'national_identity_card':
|
|
1410
|
-
doc_type1 = identify_document_type(front_id_text, country, front_id_text)
|
|
1411
|
-
|
|
1412
1077
|
front_doc_on_pp = data.get('front_doc_on_pp')
|
|
1413
1078
|
front_screenshot = data.get('front_screenshot_result')
|
|
1414
1079
|
front_photo_on_screen_result = data.get('front_photo_on_screen_result')
|
|
@@ -1423,35 +1088,18 @@ def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_
|
|
|
1423
1088
|
visual_authenticity['breakdown']['original_document_present']['properties']['photo_of_screen'] = 'consider'
|
|
1424
1089
|
|
|
1425
1090
|
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
|
-
|
|
1091
|
+
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1092
|
+
visual_authenticity['breakdown']['face_detection'] = 'clear'
|
|
1093
|
+
visual_authenticity['breakdown']['security_features'] = 'clear'
|
|
1094
|
+
|
|
1442
1095
|
if country == 'IRQ':
|
|
1443
1096
|
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'
|
|
1097
|
+
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1448
1098
|
else:
|
|
1449
|
-
|
|
1450
1099
|
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1451
1100
|
visual_authenticity['breakdown']['template']['result'] = data.get('front_template_result')
|
|
1452
1101
|
visual_authenticity['breakdown']['digital_tampering']['result'] = data.get('tampering_result')
|
|
1453
|
-
|
|
1454
|
-
|
|
1102
|
+
|
|
1455
1103
|
if country == 'LBN':
|
|
1456
1104
|
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1457
1105
|
visual_authenticity['breakdown']['original_document_present']['properties']['screenshot'] = 'clear'
|
|
@@ -1466,7 +1114,6 @@ def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_
|
|
|
1466
1114
|
visual_authenticity['breakdown']['digital_tampering']['result'] = 'clear'
|
|
1467
1115
|
visual_authenticity['breakdown']['template']['result'] = 'clear'
|
|
1468
1116
|
|
|
1469
|
-
|
|
1470
1117
|
if country in ['SDN', 'SYR', 'JOR', 'PSE']:
|
|
1471
1118
|
visual_authenticity['breakdown']['original_document_present']['properties']['scan'] = 'clear'
|
|
1472
1119
|
visual_authenticity['breakdown']['original_document_present']['properties']['screenshot'] = 'clear'
|
|
@@ -1478,12 +1125,9 @@ def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_
|
|
|
1478
1125
|
|
|
1479
1126
|
## set default to avoid any problems of cache
|
|
1480
1127
|
visual_authenticity['result'] = 'clear'
|
|
1481
|
-
|
|
1482
1128
|
final_result = create_final_result(visual_authenticity)
|
|
1483
1129
|
visual_authenticity['result'] = final_result
|
|
1484
1130
|
|
|
1485
|
-
# print(f"\n\n------------------------- VISUAL AUTHENTICITY DOC: {visual_authenticity}")
|
|
1486
|
-
|
|
1487
1131
|
back_doc_on_pp = data.get('doc_on_pp')
|
|
1488
1132
|
if front_doc_on_pp == 'consider' or back_doc_on_pp == 'consider':
|
|
1489
1133
|
visual_authenticity['breakdown']['original_document_present']['properties']['document_on_printed_paper'] = 'consider'
|
|
@@ -1493,7 +1137,7 @@ def visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_
|
|
|
1493
1137
|
visual_authenticity['breakdown']['original_document_present']['properties']['document_on_printed_paper'] = 'clear'
|
|
1494
1138
|
visual_authenticity['result'] = 'clear'
|
|
1495
1139
|
|
|
1496
|
-
logging.info(f"
|
|
1140
|
+
logging.info(f"---------------------------- VISUAL AUTHENTICITY: {visual_authenticity}")
|
|
1497
1141
|
return visual_authenticity
|
|
1498
1142
|
|
|
1499
1143
|
def main_details(data, country):
|
|
@@ -1689,15 +1333,30 @@ def main_details(data, country):
|
|
|
1689
1333
|
for key in keys:
|
|
1690
1334
|
main_properties[key] = data.get(key, '')
|
|
1691
1335
|
|
|
1692
|
-
if country in ['IRQ', 'LBN', 'QAT', 'SDN', 'SYR', 'JOR', 'PSE']:
|
|
1336
|
+
if country in ['IRQ', 'LBN', 'QAT', 'SDN', 'SYR', 'JOR', 'PSE', 'UAE']:
|
|
1337
|
+
|
|
1338
|
+
if country == 'UAE':
|
|
1339
|
+
main_prop_data = {}
|
|
1340
|
+
if data.get('doc_type') == 'national_identity_card':
|
|
1341
|
+
keys = ['dob_mrz', 'expiry_date_mrz', 'id_number_mrz', 'name_mrz', 'card_number_mrz','is_name_match_mrz',
|
|
1342
|
+
'id_number_front_back_mrz_match','card_number_back_mrz_match','dob_mrz_match','expiry_date_mrz_match','gender_mrz_match','name_mrz_match'
|
|
1343
|
+
]
|
|
1344
|
+
keys_to_remove = []
|
|
1693
1345
|
if country == 'IRQ':
|
|
1694
1346
|
main_prop_data = {}
|
|
1695
1347
|
if data.get('doc_type') == 'passport':
|
|
1348
|
+
logging.info(f"Extracting main details for IRQ passport")
|
|
1696
1349
|
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',
|
|
1350
|
+
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',
|
|
1351
|
+
'mother_last_name_en','expiry_date_mrz','dob_mrz', 'gender_mrz','id_number_mrz','name_mrz','is_name_match_mrz',
|
|
1352
|
+
'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
1353
|
else:
|
|
1699
1354
|
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',
|
|
1355
|
+
keys = ['name_en', 'name', 'first_name', 'father_name', 'third_name', 'mother_first_name', 'mother_last_name',
|
|
1356
|
+
'last_name', 'first_name_en', 'father_name_en', 'last_name_en', 'third_name_en', 'mother_first_name_en',
|
|
1357
|
+
'mother_last_name_en', 'issuing_authority', 'nationality', 'gender', 'issuing_country', 'gender_ar', 'mrz',
|
|
1358
|
+
'place_of_birth', 'issuing_authority_en', 'place_of_birth_en', "issue_date", "id_number", "card_number", 'family_number', 'family_number_en',
|
|
1359
|
+
'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
1360
|
|
|
1702
1361
|
if country == 'LBN':
|
|
1703
1362
|
main_prop_data = {}
|
|
@@ -1749,18 +1408,25 @@ def main_details(data, country):
|
|
|
1749
1408
|
main_prop_data = {}
|
|
1750
1409
|
keys_to_remove = ['name', 'issuing_place', 'occupation', 'employer', 'mrz_line3', 'family_sponsor', 'issuing_country']
|
|
1751
1410
|
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',
|
|
1411
|
+
keys = ['full_name', 'first_name', 'last_name', 'father_name', 'mother_name', 'place_of_birth', 'place_of_issue', 'dob', 'nationality', 'gender', 'passport_number', 'issue_number',
|
|
1412
|
+
'issuing_date', 'national_number', 'mrz1', 'mrz2', 'mrz', 'issuing_country',
|
|
1413
|
+
'passport_number_mrz','name_mrz', 'dob_mrz', 'expiry_date_mrz','gender_mrz',
|
|
1414
|
+
'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
1415
|
|
|
1754
1416
|
|
|
1755
1417
|
if country == 'PSE':
|
|
1756
1418
|
main_prop_data = {}
|
|
1757
1419
|
keys_to_remove = ['name', 'issuing_place', 'occupation', 'employer', 'mrz_line3', 'family_sponsor']
|
|
1758
1420
|
if data.get('doc_type') == 'passport':
|
|
1759
|
-
keys = ['full_name', 'first_name', 'last_name', 'mother_name', 'place_of_birth', 'dob', 'issuing_date', 'nationality', 'gender',
|
|
1421
|
+
keys = ['full_name', 'first_name', 'last_name', 'mother_name', 'place_of_birth', 'dob', 'issuing_date', 'nationality', 'gender',
|
|
1422
|
+
'place_of_issue', 'passport_number', 'id_number', 'mrz1', 'mrz2', 'mrz', 'issuing_country',
|
|
1423
|
+
'passport_number_mrz','name_mrz', 'dob_mrz', 'expiry_date_mrz','gender_mrz',
|
|
1424
|
+
'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
1425
|
|
|
1761
1426
|
for key in keys:
|
|
1762
1427
|
main_prop_data[key] = data.get(key, '')
|
|
1763
1428
|
|
|
1429
|
+
logging.info(f"Main properties before removal: {main_prop_data.keys()}")
|
|
1764
1430
|
if keys_to_remove:
|
|
1765
1431
|
for key in keys_to_remove:
|
|
1766
1432
|
if key in main_properties:
|
|
@@ -1771,7 +1437,6 @@ def main_details(data, country):
|
|
|
1771
1437
|
if main_properties.get('issue_date', ''):
|
|
1772
1438
|
main_properties['issue_date'] = onfido_date_format(get_dates_to_generic_format(main_properties['issue_date']))
|
|
1773
1439
|
|
|
1774
|
-
|
|
1775
1440
|
|
|
1776
1441
|
if not data.get('card_number') and data.get('card_number_front'):
|
|
1777
1442
|
card_data_t = {
|
|
@@ -1823,7 +1488,6 @@ def form_final_data_document_report(data, front_id_text, back_id_text, country,
|
|
|
1823
1488
|
dob = data.get('dob', '')
|
|
1824
1489
|
|
|
1825
1490
|
document_report = {
|
|
1826
|
-
## pending - to be filled by dev
|
|
1827
1491
|
"_id": "",
|
|
1828
1492
|
"breakdown": {
|
|
1829
1493
|
"age_validation": age_validation(dob),
|
|
@@ -1847,20 +1511,16 @@ def form_final_data_document_report(data, front_id_text, back_id_text, country,
|
|
|
1847
1511
|
"police_record": {},
|
|
1848
1512
|
"visual_authenticity": visual_authenticity_check(data, front_id_text, back_id_text, selfie, facial_similarity, face_match_threshold, country)
|
|
1849
1513
|
},
|
|
1850
|
-
## pending - to be filled by dev
|
|
1851
1514
|
"check_id": "",
|
|
1852
1515
|
"created_at": created_at(),
|
|
1853
1516
|
"documents": [
|
|
1854
1517
|
{
|
|
1855
|
-
## pending - id value in table stored in db for front id - to be filled by dev
|
|
1856
1518
|
"id": ""
|
|
1857
1519
|
},
|
|
1858
1520
|
{
|
|
1859
|
-
## pending - id value in table stored in db for front id - to be filled by dev
|
|
1860
1521
|
"id": ""
|
|
1861
1522
|
}
|
|
1862
1523
|
],
|
|
1863
|
-
# to be filled by dev
|
|
1864
1524
|
"href": "",
|
|
1865
1525
|
"name": "document",
|
|
1866
1526
|
"properties": main_details(data, country),
|
|
@@ -1960,7 +1620,6 @@ def form_final_facial_similarity_report(data, selfie, facial_similarity, livenes
|
|
|
1960
1620
|
facial_report['breakdown']['visual_authenticity']['breakdown']['spoofing_detection']['properties']['score'] = ''
|
|
1961
1621
|
facial_report['breakdown']['visual_authenticity']['breakdown']['spoofing_detection']['result'] = ''
|
|
1962
1622
|
|
|
1963
|
-
# if np.any(selfie) and liveness_result:
|
|
1964
1623
|
visual_authenticity_final_result = create_final_result(facial_report['breakdown']['visual_authenticity'])
|
|
1965
1624
|
facial_report['breakdown']['visual_authenticity']['result'] = visual_authenticity_final_result
|
|
1966
1625
|
|