idvpackage 3.0.12__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 CHANGED
@@ -284,10 +284,10 @@ def load_and_process_image_deepface(image_input, country=None):
284
284
  if w < 40 or h < 50:
285
285
  logging.info(f"Face too small for SDN: w={w}, h={h}")
286
286
  return None, None, 0.0
287
- else:
288
- if w < 80 or h < 90:
289
- logging.info(f"Face too small: w={w}, h={h}")
290
- return None, None, 0.0
287
+ # else:
288
+ # if w < 80 or h < 90:
289
+ # logging.info(f"Face too small: w={w}, h={h}")
290
+ # return None, None, 0.0
291
291
 
292
292
  # All checks passed
293
293
  return biggest_face, img_to_process, confidence
@@ -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
- if best_face_objs is None or best_confidence < CONFIDENCE_THRESHOLD:
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
 
@@ -146,7 +146,7 @@ class IraqiPassport(BaseModel):
146
146
  ..., description="Date of birth as extracted from MRZ (in DD/MM/YYYY format)"
147
147
  )
148
148
  id_number_mrz: str = Field(
149
- ..., description="ID number as extracted from MRZ"
149
+ ..., min_length=9, max_length=9, description="ID number as extracted from MRZ"
150
150
  )
151
151
  expiry_date_mrz: str = Field(
152
152
  ..., description="Expiry date as extracted from MRZ (in DD/MM/YYYY format)"
idvpackage/ocr.py CHANGED
@@ -896,34 +896,37 @@ 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
- front_data = {"error": "", "doc_type": "national_identity_card"}
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
- front_data_fields = get_response_from_openai_qat(
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"front_data_fields: {json.dumps(front_data_fields, indent=2, ensure_ascii=False)}")
909
+ logging.info(f"front_data: {json.dumps(front_data, indent=2, ensure_ascii=False)}")
909
910
 
910
- front_data_fields['issuing_country'] = 'QAT'
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 = front_data_fields.get("expiry_date", "")
919
- if expiry_date:
920
- try:
921
- dt_obj = datetime.strptime(expiry_date, "%d/%m/%Y")
922
- tomorrow = datetime.today() + timedelta(days=1)
923
- if dt_obj < tomorrow:
924
- front_data["error"] = "expired_id"
925
- except:
926
- pass
919
+ expiry_date = front_data.get("expiry_date", "")
920
+ try:
921
+ if expiry_date:
922
+ logging.info(f"Extracted Expiry Date for expiry verification: {expiry_date}")
923
+ from idvpackage.ocr_utils import is_expired_id
924
+ if is_expired_id(expiry_date):
925
+ result['error'] = 'expired_id'
926
+ logging.info(f"ID is expired with expiry date: {expiry_date}")
927
+ return result
928
+ except Exception as e:
929
+ logging.info(f"Error in expiry date calculation: {e}")
927
930
 
928
931
  image = np.array(processed_front_id)
929
932
  doc_on_pp_result = document_on_printed_paper(image)
@@ -935,9 +938,9 @@ class IdentityVerification:
935
938
 
936
939
 
937
940
  if front_face_encodings is None or len(front_face_encodings) == 0:
938
- front_data['error'] = 'face_not_detected'
941
+ result['error'] = 'face_not_detected'
939
942
  logging.info("No face detected in front image")
940
- return front_data
943
+ return result
941
944
 
942
945
  logging.info(f"----------------Time taken for face extraction front: {time.time() - st} seconds\n")
943
946
 
@@ -962,8 +965,8 @@ class IdentityVerification:
962
965
  "front_face_encodings": front_face_encodings_str,
963
966
  }
964
967
 
965
- front_data_fields.update(front_data_temp)
966
- front_data.update(front_data_fields)
968
+ front_data.update(front_data_temp)
969
+ result.update(front_data)
967
970
 
968
971
  required_keys = ["expiry_date", "name", "id_number"]
969
972
  empty_string_keys = [
@@ -973,18 +976,18 @@ class IdentityVerification:
973
976
  ]
974
977
 
975
978
  if empty_string_keys:
976
- front_data["error"] = "missing_key_fields"
979
+ result["error"] = "missing_key_fields"
977
980
 
978
981
  if front_data.get("error"):
979
- return front_data
982
+ return result
980
983
 
981
984
 
982
985
  except Exception as e:
983
986
  logging.info(f"exception in QAT front ID extraction: {e}")
984
- front_data["error"] = "bad_image"
985
- front_data["error_details"] = e
987
+ result["error"] = "bad_image"
988
+ result["error_details"] = e
986
989
 
987
- return front_data
990
+ return result
988
991
 
989
992
  if country == "LBN":
990
993
  logging.info("----------------Working on LBN\n")
@@ -1032,9 +1035,10 @@ class IdentityVerification:
1032
1035
  logging.info(f"----------------Time taken for OpenAI and final extraction front: {time.time() - st} seconds\n")
1033
1036
  logging.info(f"Extracted LBN front data fields: {json.dumps(front_data_fields, indent=2, ensure_ascii=False)}")
1034
1037
 
1035
- if front_data_fields.get('header_verified') is not True:
1038
+ if not front_data_fields.get("header_verified", False):
1036
1039
  front_data["error"] = "not_front_id"
1037
1040
  return front_data
1041
+
1038
1042
  if 'id_number' in front_data_fields:
1039
1043
  id_number = front_data_fields['id_number']
1040
1044
  if id_number and len(id_number) < 12:
@@ -1198,7 +1202,7 @@ class IdentityVerification:
1198
1202
  logging.info(f"Extracted SDN front data fields: {json.dumps(front_data_fields, indent=2, ensure_ascii=False)}")
1199
1203
  logging.info(f"----------------Time taken for OpenAI and final extraction front: {time.time() - st} seconds\n")
1200
1204
 
1201
- if not front_data_fields['header_verified']:
1205
+ if not front_data_fields.get("header_verified", False):
1202
1206
  front_data_fields['error'] = 'not_front_id'
1203
1207
  logging.error(f"ID not verified in the document data: {front_data_fields['header_verified']}")
1204
1208
  return front_data_fields
@@ -1787,7 +1791,7 @@ class IdentityVerification:
1787
1791
 
1788
1792
  if country == "QAT":
1789
1793
  from idvpackage.qatar_id_extraction import get_response_from_openai_qat
1790
- back_data = {"error": "", "doc_type": "national_identity_card"}
1794
+ result = {"error": "", "doc_type": "national_identity_card"}
1791
1795
  try:
1792
1796
  processed_back_id = self.image_conversion(back_id)
1793
1797
  compressed_image = BytesIO()
@@ -1797,11 +1801,15 @@ class IdentityVerification:
1797
1801
  compressed_image_data = compressed_image.getvalue()
1798
1802
 
1799
1803
  st = time.time()
1800
- back_extraction_result = get_response_from_openai_qat(compressed_image_data, "back", country, self.openai_key)
1804
+ back_data = get_response_from_openai_qat(compressed_image_data, "back", country, self.openai_key)
1801
1805
  logging.info(f"----------------Time taken for OpenAI and final extraction back: {time.time() - st} seconds\n")
1802
- logging.info(f"back_extraction_result: {json.dumps(back_extraction_result, ensure_ascii=False, indent=2)}")
1803
-
1804
- back_data.update(back_extraction_result)
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)
1805
1813
  back_data_update = {
1806
1814
  "back_extracted_data": "",
1807
1815
  "back_coloured": True,
@@ -1812,13 +1820,13 @@ class IdentityVerification:
1812
1820
  "back_glare": "clear",
1813
1821
  }
1814
1822
 
1815
- back_data.update(back_data_update)
1823
+ result.update(back_data_update)
1816
1824
 
1817
1825
  except Exception as e:
1818
- back_data["error"] = "bad_image"
1819
- back_data["error_details"] = e
1826
+ result["error"] = "bad_image"
1827
+ result["error_details"] = e
1820
1828
 
1821
- return back_data
1829
+ return result
1822
1830
 
1823
1831
  if country == "LBN":
1824
1832
  from idvpackage.blur_detection import is_image_blur
@@ -2339,7 +2347,7 @@ class IdentityVerification:
2339
2347
  )
2340
2348
  logging.info(f"passport_details: {json.dumps(passport_details, ensure_ascii=False, indent=2)}")
2341
2349
 
2342
- if not passport_details['header_verified'] :
2350
+ if not passport_details.get('header_verified', False):
2343
2351
  passport_data["error"] = "not_passport"
2344
2352
  return passport_data
2345
2353
 
@@ -2497,7 +2505,7 @@ class IdentityVerification:
2497
2505
  logging.info(f"Passport details extracted: {json.dumps(passport_details, ensure_ascii=False, indent=2)}")
2498
2506
  logging.info(f"----------------Time taken for OpenAI and final extraction passport: {time.time() - st} seconds\n")
2499
2507
 
2500
- if not passport_details['header_verified']:
2508
+ if not passport_details.get('header_verified', False):
2501
2509
  passport_data["error"] = "not_passport"
2502
2510
  return passport_data
2503
2511
 
@@ -2637,7 +2645,7 @@ class IdentityVerification:
2637
2645
  )
2638
2646
  logging.info(f"passport_details: {json.dumps(passport_details, ensure_ascii=False, indent=2)}")
2639
2647
 
2640
- if not passport_details['header_verified']:
2648
+ if not passport_details.get('header_verified', False):
2641
2649
  passport_data["error"] = "not_passport"
2642
2650
  return passport_data
2643
2651
 
@@ -2777,10 +2785,7 @@ class IdentityVerification:
2777
2785
  logging.info(f"----------------Passport details: {json.dumps(passport_details, indent=4, ensure_ascii=False)}\n")
2778
2786
  logging.info(f"----------------Time taken for openai final extraction passport: {time.time() - st} seconds\n")
2779
2787
 
2780
- if (
2781
- passport_details.get("header_verified", "")
2782
- and passport_details["header_verified"] == "False"
2783
- ):
2788
+ if not passport_details.get("header_verified", False):
2784
2789
  passport_data["error"] = "not_passport"
2785
2790
  return passport_data
2786
2791
 
@@ -2909,7 +2914,7 @@ class IdentityVerification:
2909
2914
  f"----------------Time taken for OpenAI and final extraction passport: {time.time() - st} seconds\n"
2910
2915
  )
2911
2916
 
2912
- if passport_details.get("header_verified", "") == "False":
2917
+ if not passport_details.get("header_verified", False):
2913
2918
  passport_data["error"] = "not_passport"
2914
2919
  return passport_data
2915
2920
 
idvpackage/ocr_utils.py CHANGED
@@ -560,15 +560,16 @@ def data_consistency_check(data, front_id_text, back_id_text, country, back_img)
560
560
  if country == 'IRQ':
561
561
  data_consistency['breakdown']['document_type']['result'] = 'clear'
562
562
 
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}')
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}')
568
569
 
569
- if front_id_number and back_id_number:
570
- if front_id_number != back_id_number:
571
- data_consistency['breakdown']['multiple_data_sources_present']['result'] = 'consider'
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'
572
573
 
573
574
  if country == 'QAT':
574
575
  data_consistency['breakdown']['gender']['result'] = 'clear'
@@ -684,7 +685,7 @@ def get_name_match_mrz(data, doc_type):
684
685
  name = data.get("name", "")
685
686
 
686
687
  elif data['nationality'] == 'IRQ':
687
- name = data.get("name", "")
688
+ name = data.get("full_name", "")
688
689
  logging.info(f"Name extracted for IRQ: {name}")
689
690
 
690
691
  elif data['nationality'] == 'PSE':
@@ -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 (e.g., شركة → Company, مؤسسة → Establishment)
53
- - passport_number: Passport number as printed on the card (extract exactly as written, e.g., EA0605652)
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=9, max_length=11,
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 (e.g., شركة Company, مؤسسة Establishment)",
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 ex: EA0605652."
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.12
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=xhDBZqjIlzhNqIkHzH3Hy7Sdr0ncD9-BdSE091MDbA4,15243
3
+ idvpackage/common.py,sha256=YT4MgdUhGCo2yKYZ0ojP0czeXyX1VYDUnCF1qgooXIM,15318
4
4
  idvpackage/constants.py,sha256=XvQy5ORGsXoQGcXcvUBC17vpFMzgzleS9S_mDN72G4c,7212
5
- idvpackage/iraq_id_extraction_withopenai.py,sha256=r72M3osCDqYjctqTuhPvkTxxjIST5ZpBFHVUDPzUqOo,21884
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=03sIUsWnMsoGp9dQ5eu0VKmPrHxjZuDqSqj107Y-OKk,156980
10
- idvpackage/ocr_utils.py,sha256=ro028PvFUdZjzlOFqOijyRI2VvAGGAypAzyU_Xp6Ucs,77285
9
+ idvpackage/ocr.py,sha256=0ZH2Q1DGWyeJQ1najTyd4nJH1amfiO2J8wS_UvUx1Bk,157163
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=iTGB7j8b7aHi69ZlH4pekPD9klavqXxOSZvzwSZBL2M,9044
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.12.dist-info/licenses/LICENSE,sha256=JTmNGOPPvG2XBgkW2R2xwzJeR_OEjaFKeePN1jGYVt8,1068
31
- idvpackage-3.0.12.dist-info/METADATA,sha256=21m7s8UBQxFK5Ohy9xeS4vJdiJb9We75qjujFrurzwg,4800
32
- idvpackage-3.0.12.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
33
- idvpackage-3.0.12.dist-info/top_level.txt,sha256=8jL1PsYvKBIWWLGe8jEm7kU5yZ5sld_OCaz0Dzvi6qY,11
34
- idvpackage-3.0.12.dist-info/RECORD,,
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,,