idvpackage 3.0.13__py3-none-any.whl → 3.0.14__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 +3 -2
- idvpackage/ocr.py +42 -39
- idvpackage/qatar_id_extraction.py +10 -10
- {idvpackage-3.0.13.dist-info → idvpackage-3.0.14.dist-info}/METADATA +1 -1
- {idvpackage-3.0.13.dist-info → idvpackage-3.0.14.dist-info}/RECORD +8 -8
- {idvpackage-3.0.13.dist-info → idvpackage-3.0.14.dist-info}/WHEEL +0 -0
- {idvpackage-3.0.13.dist-info → idvpackage-3.0.14.dist-info}/licenses/LICENSE +0 -0
- {idvpackage-3.0.13.dist-info → idvpackage-3.0.14.dist-info}/top_level.txt +0 -0
idvpackage/common.py
CHANGED
|
@@ -346,13 +346,14 @@ def load_and_process_image_deepface(image_input, country=None):
|
|
|
346
346
|
|
|
347
347
|
if face_objs is None:
|
|
348
348
|
continue
|
|
349
|
-
|
|
350
349
|
else:
|
|
351
350
|
break # Exit loop on first valid detection
|
|
352
351
|
|
|
353
352
|
# Keep best fallback (just in case)
|
|
354
353
|
|
|
355
|
-
|
|
354
|
+
|
|
355
|
+
#remove best_confidence < CONFIDENCE_THRESHOLD to take best of all angles when confidence is less than threshold
|
|
356
|
+
if best_face_objs is None:
|
|
356
357
|
print(f"No valid face found (threshold={CONFIDENCE_THRESHOLD})")
|
|
357
358
|
return [], []
|
|
358
359
|
|
idvpackage/ocr.py
CHANGED
|
@@ -896,34 +896,35 @@ class IdentityVerification:
|
|
|
896
896
|
from idvpackage.ocr_utils import document_on_printed_paper
|
|
897
897
|
from idvpackage.qatar_id_extraction import get_response_from_openai_qat
|
|
898
898
|
|
|
899
|
-
|
|
899
|
+
result = {"error": "", "doc_type": "national_identity_card"}
|
|
900
900
|
|
|
901
901
|
try:
|
|
902
902
|
processed_front_id ,compressed_image_data= self.image_conversion_and_compression(front_id)
|
|
903
903
|
st = time.time()
|
|
904
|
-
|
|
904
|
+
|
|
905
|
+
front_data = get_response_from_openai_qat(
|
|
905
906
|
compressed_image_data, "front", country, self.openai_key
|
|
906
907
|
)
|
|
907
908
|
logging.info(f"----------------Time taken for vision front: {time.time() - st} seconds\n")
|
|
908
|
-
logging.info(f"
|
|
909
|
+
logging.info(f"front_data: {json.dumps(front_data, indent=2, ensure_ascii=False)}")
|
|
909
910
|
|
|
910
|
-
|
|
911
|
+
front_data['issuing_country'] = 'QAT'
|
|
912
|
+
|
|
913
|
+
if not front_data.get("header_verified", False):
|
|
914
|
+
result["error"] = "not_front_id"
|
|
915
|
+
return result
|
|
911
916
|
|
|
912
|
-
if not front_data_fields["header_verified"]:
|
|
913
|
-
front_data["error"] = "not_front_id"
|
|
914
|
-
return front_data
|
|
915
|
-
|
|
916
917
|
logging.info( f"----------------Time taken for qatar OpenAI and final extraction front: {time.time() - st} seconds\n")
|
|
917
918
|
|
|
918
|
-
expiry_date =
|
|
919
|
+
expiry_date = front_data.get("expiry_date", "")
|
|
919
920
|
try:
|
|
920
921
|
if expiry_date:
|
|
921
922
|
logging.info(f"Extracted Expiry Date for expiry verification: {expiry_date}")
|
|
922
923
|
from idvpackage.ocr_utils import is_expired_id
|
|
923
924
|
if is_expired_id(expiry_date):
|
|
924
|
-
|
|
925
|
+
result['error'] = 'expired_id'
|
|
925
926
|
logging.info(f"ID is expired with expiry date: {expiry_date}")
|
|
926
|
-
return
|
|
927
|
+
return result
|
|
927
928
|
except Exception as e:
|
|
928
929
|
logging.info(f"Error in expiry date calculation: {e}")
|
|
929
930
|
|
|
@@ -937,9 +938,9 @@ class IdentityVerification:
|
|
|
937
938
|
|
|
938
939
|
|
|
939
940
|
if front_face_encodings is None or len(front_face_encodings) == 0:
|
|
940
|
-
|
|
941
|
+
result['error'] = 'face_not_detected'
|
|
941
942
|
logging.info("No face detected in front image")
|
|
942
|
-
return
|
|
943
|
+
return result
|
|
943
944
|
|
|
944
945
|
logging.info(f"----------------Time taken for face extraction front: {time.time() - st} seconds\n")
|
|
945
946
|
|
|
@@ -964,8 +965,8 @@ class IdentityVerification:
|
|
|
964
965
|
"front_face_encodings": front_face_encodings_str,
|
|
965
966
|
}
|
|
966
967
|
|
|
967
|
-
|
|
968
|
-
|
|
968
|
+
front_data.update(front_data_temp)
|
|
969
|
+
result.update(front_data)
|
|
969
970
|
|
|
970
971
|
required_keys = ["expiry_date", "name", "id_number"]
|
|
971
972
|
empty_string_keys = [
|
|
@@ -975,18 +976,18 @@ class IdentityVerification:
|
|
|
975
976
|
]
|
|
976
977
|
|
|
977
978
|
if empty_string_keys:
|
|
978
|
-
|
|
979
|
+
result["error"] = "missing_key_fields"
|
|
979
980
|
|
|
980
981
|
if front_data.get("error"):
|
|
981
|
-
return
|
|
982
|
+
return result
|
|
982
983
|
|
|
983
984
|
|
|
984
985
|
except Exception as e:
|
|
985
986
|
logging.info(f"exception in QAT front ID extraction: {e}")
|
|
986
|
-
|
|
987
|
-
|
|
987
|
+
result["error"] = "bad_image"
|
|
988
|
+
result["error_details"] = e
|
|
988
989
|
|
|
989
|
-
return
|
|
990
|
+
return result
|
|
990
991
|
|
|
991
992
|
if country == "LBN":
|
|
992
993
|
logging.info("----------------Working on LBN\n")
|
|
@@ -1034,9 +1035,10 @@ class IdentityVerification:
|
|
|
1034
1035
|
logging.info(f"----------------Time taken for OpenAI and final extraction front: {time.time() - st} seconds\n")
|
|
1035
1036
|
logging.info(f"Extracted LBN front data fields: {json.dumps(front_data_fields, indent=2, ensure_ascii=False)}")
|
|
1036
1037
|
|
|
1037
|
-
if front_data_fields.get(
|
|
1038
|
+
if not front_data_fields.get("header_verified", False):
|
|
1038
1039
|
front_data["error"] = "not_front_id"
|
|
1039
1040
|
return front_data
|
|
1041
|
+
|
|
1040
1042
|
if 'id_number' in front_data_fields:
|
|
1041
1043
|
id_number = front_data_fields['id_number']
|
|
1042
1044
|
if id_number and len(id_number) < 12:
|
|
@@ -1200,7 +1202,7 @@ class IdentityVerification:
|
|
|
1200
1202
|
logging.info(f"Extracted SDN front data fields: {json.dumps(front_data_fields, indent=2, ensure_ascii=False)}")
|
|
1201
1203
|
logging.info(f"----------------Time taken for OpenAI and final extraction front: {time.time() - st} seconds\n")
|
|
1202
1204
|
|
|
1203
|
-
if not front_data_fields
|
|
1205
|
+
if not front_data_fields.get("header_verified", False):
|
|
1204
1206
|
front_data_fields['error'] = 'not_front_id'
|
|
1205
1207
|
logging.error(f"ID not verified in the document data: {front_data_fields['header_verified']}")
|
|
1206
1208
|
return front_data_fields
|
|
@@ -1789,7 +1791,7 @@ class IdentityVerification:
|
|
|
1789
1791
|
|
|
1790
1792
|
if country == "QAT":
|
|
1791
1793
|
from idvpackage.qatar_id_extraction import get_response_from_openai_qat
|
|
1792
|
-
|
|
1794
|
+
result = {"error": "", "doc_type": "national_identity_card"}
|
|
1793
1795
|
try:
|
|
1794
1796
|
processed_back_id = self.image_conversion(back_id)
|
|
1795
1797
|
compressed_image = BytesIO()
|
|
@@ -1799,11 +1801,15 @@ class IdentityVerification:
|
|
|
1799
1801
|
compressed_image_data = compressed_image.getvalue()
|
|
1800
1802
|
|
|
1801
1803
|
st = time.time()
|
|
1802
|
-
|
|
1804
|
+
back_data = get_response_from_openai_qat(compressed_image_data, "back", country, self.openai_key)
|
|
1803
1805
|
logging.info(f"----------------Time taken for OpenAI and final extraction back: {time.time() - st} seconds\n")
|
|
1804
|
-
logging.info(f"back_extraction_result: {json.dumps(
|
|
1805
|
-
|
|
1806
|
-
back_data.
|
|
1806
|
+
logging.info(f"back_extraction_result: {json.dumps(back_data, ensure_ascii=False, indent=2)}")
|
|
1807
|
+
|
|
1808
|
+
if not back_data.get('back_header_verified', False):
|
|
1809
|
+
result["error"] = "not_back_id"
|
|
1810
|
+
return result
|
|
1811
|
+
|
|
1812
|
+
result.update(back_data)
|
|
1807
1813
|
back_data_update = {
|
|
1808
1814
|
"back_extracted_data": "",
|
|
1809
1815
|
"back_coloured": True,
|
|
@@ -1814,13 +1820,13 @@ class IdentityVerification:
|
|
|
1814
1820
|
"back_glare": "clear",
|
|
1815
1821
|
}
|
|
1816
1822
|
|
|
1817
|
-
|
|
1823
|
+
result.update(back_data_update)
|
|
1818
1824
|
|
|
1819
1825
|
except Exception as e:
|
|
1820
|
-
|
|
1821
|
-
|
|
1826
|
+
result["error"] = "bad_image"
|
|
1827
|
+
result["error_details"] = e
|
|
1822
1828
|
|
|
1823
|
-
return
|
|
1829
|
+
return result
|
|
1824
1830
|
|
|
1825
1831
|
if country == "LBN":
|
|
1826
1832
|
from idvpackage.blur_detection import is_image_blur
|
|
@@ -2341,7 +2347,7 @@ class IdentityVerification:
|
|
|
2341
2347
|
)
|
|
2342
2348
|
logging.info(f"passport_details: {json.dumps(passport_details, ensure_ascii=False, indent=2)}")
|
|
2343
2349
|
|
|
2344
|
-
if not passport_details
|
|
2350
|
+
if not passport_details.get('header_verified', False):
|
|
2345
2351
|
passport_data["error"] = "not_passport"
|
|
2346
2352
|
return passport_data
|
|
2347
2353
|
|
|
@@ -2499,7 +2505,7 @@ class IdentityVerification:
|
|
|
2499
2505
|
logging.info(f"Passport details extracted: {json.dumps(passport_details, ensure_ascii=False, indent=2)}")
|
|
2500
2506
|
logging.info(f"----------------Time taken for OpenAI and final extraction passport: {time.time() - st} seconds\n")
|
|
2501
2507
|
|
|
2502
|
-
if not passport_details
|
|
2508
|
+
if not passport_details.get('header_verified', False):
|
|
2503
2509
|
passport_data["error"] = "not_passport"
|
|
2504
2510
|
return passport_data
|
|
2505
2511
|
|
|
@@ -2639,7 +2645,7 @@ class IdentityVerification:
|
|
|
2639
2645
|
)
|
|
2640
2646
|
logging.info(f"passport_details: {json.dumps(passport_details, ensure_ascii=False, indent=2)}")
|
|
2641
2647
|
|
|
2642
|
-
if not passport_details
|
|
2648
|
+
if not passport_details.get('header_verified', False):
|
|
2643
2649
|
passport_data["error"] = "not_passport"
|
|
2644
2650
|
return passport_data
|
|
2645
2651
|
|
|
@@ -2779,10 +2785,7 @@ class IdentityVerification:
|
|
|
2779
2785
|
logging.info(f"----------------Passport details: {json.dumps(passport_details, indent=4, ensure_ascii=False)}\n")
|
|
2780
2786
|
logging.info(f"----------------Time taken for openai final extraction passport: {time.time() - st} seconds\n")
|
|
2781
2787
|
|
|
2782
|
-
if (
|
|
2783
|
-
passport_details.get("header_verified", "")
|
|
2784
|
-
and passport_details["header_verified"] == "False"
|
|
2785
|
-
):
|
|
2788
|
+
if not passport_details.get("header_verified", False):
|
|
2786
2789
|
passport_data["error"] = "not_passport"
|
|
2787
2790
|
return passport_data
|
|
2788
2791
|
|
|
@@ -2911,7 +2914,7 @@ class IdentityVerification:
|
|
|
2911
2914
|
f"----------------Time taken for OpenAI and final extraction passport: {time.time() - st} seconds\n"
|
|
2912
2915
|
)
|
|
2913
2916
|
|
|
2914
|
-
if passport_details.get("header_verified",
|
|
2917
|
+
if not passport_details.get("header_verified", False):
|
|
2915
2918
|
passport_data["error"] = "not_passport"
|
|
2916
2919
|
return passport_data
|
|
2917
2920
|
|
|
@@ -23,7 +23,7 @@ Extract ALL fields from this Qatar National ID **front side** image with high ac
|
|
|
23
23
|
|
|
24
24
|
Return a JSON object with the following fields (use the exact field names):
|
|
25
25
|
|
|
26
|
-
-id_number: The ID number exactly as shown on the card (preserve original format)
|
|
26
|
+
- id_number: The ID number exactly as shown on the card (preserve original format)
|
|
27
27
|
- dob: Date of birth exactly as shown on the card, but always return in DD/MM/YYYY format (e.g., '15/06/1990'). If the card shows a different format, convert it to DD/MM/YYYY.
|
|
28
28
|
- expiry_date: Date of expiry exactly as shown on the card, but always return in DD/MM/YYYY format (e.g., '15/06/1990'). If the card shows a different format, convert it to DD/MM/YYYY.
|
|
29
29
|
- name: Full name in English as printed on the card (extract exactly as written)
|
|
@@ -49,8 +49,8 @@ Extract ALL fields from this Qatar National ID **back side** image with high acc
|
|
|
49
49
|
Return a JSON object with the following fields (use the exact field names):
|
|
50
50
|
|
|
51
51
|
- employer: Employer name in Arabic as printed on the card (extract exactly as written)
|
|
52
|
-
- employer_en: Translate the Arabic employer name to English
|
|
53
|
-
- passport_number: Passport number as printed on the card (extract exactly as written
|
|
52
|
+
- employer_en: Translate the Arabic employer name to English
|
|
53
|
+
- passport_number: Passport number as printed on the card (extract exactly as written)
|
|
54
54
|
- passport_expiry: Passport expiry date always in DD/MM/YYYY format.
|
|
55
55
|
- back_header_verified: Return True if one of the texts present in the image is "Director General of the General Department" or "Directorate of Passports" or "Passport number" or "Serial"; otherwise False.
|
|
56
56
|
- card_number: Serial number exactly as shown on the card (preserve original format)
|
|
@@ -64,7 +64,7 @@ Instructions:
|
|
|
64
64
|
|
|
65
65
|
class QatarFront(BaseModel):
|
|
66
66
|
|
|
67
|
-
id_number: str = Field(...,min_length=
|
|
67
|
+
id_number: str = Field(...,min_length=11, max_length=11,
|
|
68
68
|
description = "The ID number exactly as shown on the card (preserve original format)",
|
|
69
69
|
)
|
|
70
70
|
|
|
@@ -114,29 +114,29 @@ class QatarFront(BaseModel):
|
|
|
114
114
|
)
|
|
115
115
|
class QatarBack(BaseModel):
|
|
116
116
|
employer: str = Field(...,
|
|
117
|
-
description = "Employer name in Arabic (extract exactly as written on the card)",
|
|
117
|
+
description = "Employer name in Arabic (extract exactly as written on the card) return empty string if not present",
|
|
118
118
|
)
|
|
119
119
|
|
|
120
120
|
employer_en: str = Field(...,
|
|
121
|
-
description = "TRANSLATE the Arabic employer name to English
|
|
121
|
+
description = "TRANSLATE the Arabic employer name to English, if employer is not present return empty string",
|
|
122
122
|
|
|
123
123
|
)
|
|
124
124
|
|
|
125
125
|
passport_number: str = Field(...,
|
|
126
|
-
description = "Passport number extract exactly as written on the card
|
|
126
|
+
description = "Passport number extract exactly as written on the card, return empty string if not present",
|
|
127
127
|
)
|
|
128
128
|
|
|
129
129
|
passport_expiry: str = Field(...,
|
|
130
|
-
description = "Passport expiry date exactly as shown on the card (preserve (dd/mm/yyyy) format)",
|
|
130
|
+
description = "Passport expiry date exactly as shown on the card (preserve (dd/mm/yyyy) format), return empty string if not present",
|
|
131
131
|
)
|
|
132
132
|
|
|
133
133
|
back_header_verified: bool = Field(
|
|
134
134
|
...,
|
|
135
|
-
description=" Return True if one of the texts present in the image Director General of the General Department or Directorate of Passports or Passport number or Serial",
|
|
135
|
+
description=" Return True if one of the texts present in the image Director General of the General Department or Directorate of Passports or Passport number or Serial else return False",
|
|
136
136
|
)
|
|
137
137
|
|
|
138
138
|
card_number: str = Field(...,
|
|
139
|
-
description = "Serial number exactly as shown on the card (preserve original format)",
|
|
139
|
+
description = "Serial number exactly as shown on the card (preserve original format), return empty string if not present",
|
|
140
140
|
)
|
|
141
141
|
|
|
142
142
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: idvpackage
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.14
|
|
4
4
|
Summary: This repository contains a Python program designed to execute Optical Character Recognition (OCR) and Facial Recognition on images.
|
|
5
5
|
Home-page: https://github.com/NymCard-Payments/project_idv_package
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
idvpackage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
idvpackage/blur_detection.py,sha256=CtLqTtg2azE4YCM8AT1jYJq6QxGoniMO0VkQYIcMtRI,1883
|
|
3
|
-
idvpackage/common.py,sha256=
|
|
3
|
+
idvpackage/common.py,sha256=YT4MgdUhGCo2yKYZ0ojP0czeXyX1VYDUnCF1qgooXIM,15318
|
|
4
4
|
idvpackage/constants.py,sha256=XvQy5ORGsXoQGcXcvUBC17vpFMzgzleS9S_mDN72G4c,7212
|
|
5
5
|
idvpackage/iraq_id_extraction_withopenai.py,sha256=j7O94q7tpn1Dq_edicsO6ItWcVuRRvuZHBf-CfSc3Vg,21912
|
|
6
6
|
idvpackage/jor_passport_extraction.py,sha256=O3qzYCbgm_tWzPKJc3b9qrH0VrefCQVPKNJdOHYku84,9214
|
|
7
7
|
idvpackage/lebanon_id_extraction.py,sha256=eqWSpfb83RRk5TEhJNOuiPLt-wCLY5L4TvrpkOckSPs,21192
|
|
8
8
|
idvpackage/liveness_spoofing_v2.py,sha256=G3sCu4LkzhJvL33S75sI_QTpc1nA3wo9SqG1elkaIwg,7409
|
|
9
|
-
idvpackage/ocr.py,sha256=
|
|
9
|
+
idvpackage/ocr.py,sha256=0ZH2Q1DGWyeJQ1najTyd4nJH1amfiO2J8wS_UvUx1Bk,157163
|
|
10
10
|
idvpackage/ocr_utils.py,sha256=2dXYE8rFl-TnTkNcjqfp5I1MQDvjsvWgrNwwrO18dGA,77383
|
|
11
11
|
idvpackage/pse_passport_extraction.py,sha256=fDrvCzN9PWhqYYvULVD89EYeBWrcMazpzY02uSlus-0,8627
|
|
12
|
-
idvpackage/qatar_id_extraction.py,sha256=
|
|
12
|
+
idvpackage/qatar_id_extraction.py,sha256=uoIXVIKDngZzGH-hiUANDxuzw7KlDsZ7O6TkoOPOpT0,9107
|
|
13
13
|
idvpackage/sudan_passport_extraction.py,sha256=fgmRLB5WdA9RqQOkP_J2lDMcgDbdKh9L9XQaWC5UQPY,17504
|
|
14
14
|
idvpackage/syr_passport_extraction.py,sha256=ga7wSLi3ydDxHo0GNwCf3-XLg5PqcTW40SS7F8XjLN8,9297
|
|
15
15
|
idvpackage/uae_id_extraction.py,sha256=_kp1FgzEoxvMTCzqXJ5Lej3rlkK6lGPKZCPyQWrscoI,11338
|
|
@@ -27,8 +27,8 @@ idvpackage/spoof_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
|
27
27
|
idvpackage/spoof_resources/functional.py,sha256=164aGMvBDHU6HWRyDBr-2EUPeJ4rc4cXl10NJyGB7eE,20138
|
|
28
28
|
idvpackage/spoof_resources/generate_patches.py,sha256=ANvJ5rDl-SXARchS8JwOxuKLhUuabbxLwvz4zsYbADE,1722
|
|
29
29
|
idvpackage/spoof_resources/transform.py,sha256=3Ft9S6g6N0SU24f3feHXquh5qRc85JFt2gNKnCYQwjo,11311
|
|
30
|
-
idvpackage-3.0.
|
|
31
|
-
idvpackage-3.0.
|
|
32
|
-
idvpackage-3.0.
|
|
33
|
-
idvpackage-3.0.
|
|
34
|
-
idvpackage-3.0.
|
|
30
|
+
idvpackage-3.0.14.dist-info/licenses/LICENSE,sha256=JTmNGOPPvG2XBgkW2R2xwzJeR_OEjaFKeePN1jGYVt8,1068
|
|
31
|
+
idvpackage-3.0.14.dist-info/METADATA,sha256=LHEzNnQfH_C0tCgBJLfog_NFRgBUqxMmHuvcJgaeX9g,4800
|
|
32
|
+
idvpackage-3.0.14.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
33
|
+
idvpackage-3.0.14.dist-info/top_level.txt,sha256=8jL1PsYvKBIWWLGe8jEm7kU5yZ5sld_OCaz0Dzvi6qY,11
|
|
34
|
+
idvpackage-3.0.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|