idvpackage 3.0.11__py3-none-any.whl → 3.0.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,292 +1,7 @@
1
- # import re
2
- # import google.generativeai as genai
3
- # from datetime import datetime
4
- # from googletrans import Translator
5
- # import json
6
- # import logging
7
-
8
- # def configure_genai(api_key):
9
- # try:
10
- # genai.configure(api_key=api_key)
11
- # model = genai.GenerativeModel(model_name = "gemini-2.0-flash-lite")
12
- # logging.info("GenAI model configured successfully.")
13
- # return model
14
- # except Exception as e:
15
- # logging.error(f"Error configuring GenAI: {e}")
16
- # return None
17
-
18
- # def genai_vision_pse(detected_text, model):
19
- # result = model.generate_content(
20
- # [detected_text, "\n\n", "From provided {detected_text} give me all required information in english. full_name, first_name, last_name, mother_name, passport_number(only digits, i.e N° or No), id_number, dob(Date of Birth dd/mm/yy format), Place of Birth, gender(M/F), issuing_date(dd/mm/yy format), expiry_date (dd/mm/yy format), Place of Issue, occupation(profession), nationality and both lines of the MRZ, please give me just dictionary dont write anything else - full_name, first_name, last_name, mother_name, passport_number, id_number, dob, place_of_birth: gender, issuing_date, expiry_date, issuing_place, occupation, mrz1, mrz2. Note that mrz1 is the line that starts with P and mrz2 is the line that starts with passport number"]
21
- # )
22
- # logging.info(f"GenAI Raw Output: {result.text}")
23
- # return result.text
24
-
25
- # def reformat_date(date_str):
26
- # try:
27
- # date_obj = datetime.strptime(date_str, '%d-%m-%Y')
28
-
29
- # return date_obj.strftime('%d/%m/%Y')
30
- # except ValueError:
31
- # return date_str
32
-
33
- # def swap_dates_if_needed(data_dict):
34
- # try:
35
- # # Parse the dates
36
- # issuing_date = datetime.strptime(data_dict['issuing_date'], '%d/%m/%Y')
37
- # expiry_date = datetime.strptime(data_dict['expiry_date'], '%d/%m/%Y')
38
-
39
- # if issuing_date > expiry_date:
40
- # data_dict['issuing_date'], data_dict['expiry_date'] = data_dict['expiry_date'], data_dict['issuing_date']
41
- # logging.info("Dates swapped: Issuing date and expiry date were in the wrong order.")
42
-
43
- # except ValueError as e:
44
- # logging.info(f"Error parsing dates: {e}")
45
-
46
- # return data_dict
47
-
48
- # def mrz_add(mrz_data_dict):
49
- # mrz_2 = mrz_data_dict['mrz2']
50
- # mrz_1 = mrz_data_dict['mrz1']
51
-
52
- # # 1. Extract Passport Number
53
- # try:
54
- # if 'passport_number' not in mrz_data_dict:
55
- # pattern_passport = r'^(\d{7})'
56
- # match_passport = re.search(pattern_passport, mrz_2)
57
- # if match_passport:
58
- # passport_number = match_passport.group(1)
59
- # mrz_data_dict['passport_number'] = passport_number
60
- # except Exception as e:
61
- # print(f"Error extracting passport number for PSE: {e}")
62
-
63
- # # 2. Extract Nationality
64
- # try:
65
- # if 'nationality' not in mrz_data_dict:
66
- # pattern_nationality = r'<\d([A-Z]{3})'
67
- # match_nationality = re.search(pattern_nationality, mrz_2)
68
- # if match_nationality:
69
- # nationality = match_nationality.group(1)
70
- # mrz_data_dict['nationality'] = nationality
71
- # except Exception as e:
72
- # logging.info(f"Error extracting nationality for PSE: {e}")
73
-
74
- # # 3. Extract Date of Birth (DD/MM/YYYY format)
75
- # try:
76
- # if 'dob' not in mrz_data_dict:
77
- # pattern_birth_date = r'\d{7}<\d[A-Z]{3}(\d{6})'
78
- # match_birth_date = re.search(pattern_birth_date, mrz_2)
79
- # if match_birth_date:
80
- # birth_date_raw = match_birth_date.group(1)
81
- # year_prefix = '19' if int(birth_date_raw[:2]) > 23 else '20'
82
- # birth_date = f"{birth_date_raw[4:]}/{birth_date_raw[2:4]}/{year_prefix}{birth_date_raw[:2]}"
83
- # mrz_data_dict['dob'] = birth_date
84
- # except Exception as e:
85
- # logging.info(f"Error extracting date of birth for PSE: {e}")
86
-
87
- # # 4. Extract Gender
88
- # try:
89
- # if 'gender' not in mrz_data_dict:
90
- # pattern_gender = r'[A-Z]{3}\d{6}([MF])'
91
- # match_gender = re.search(pattern_gender, mrz_2)
92
- # if match_gender:
93
- # gender = match_gender.group(1)
94
- # mrz_data_dict['gender'] = gender
95
- # except Exception as e:
96
- # print(f"Error extracting gender for PSE: {e}")
97
-
98
- # # 5. Extract Expiration Date (DD/MM/YYYY format)
99
- # try:
100
- # if 'expiry_date' not in mrz_data_dict:
101
- # pattern_expiration_date = r'[MF](\d{6})'
102
- # match_expiration_date = re.search(pattern_expiration_date, mrz_2)
103
- # if match_expiration_date:
104
- # expiration_date_raw = match_expiration_date.group(1)
105
- # year_prefix = '19' if int(expiration_date_raw[:2]) > 50 else '20'
106
- # expiration_date = f"{expiration_date_raw[4:]}/{expiration_date_raw[2:4]}/{year_prefix}{expiration_date_raw[:2]}"
107
- # mrz_data_dict['expiry_date'] = expiration_date
108
- # except Exception as e:
109
- # logging.info(f"Error extracting expiration date for PSE: {e}")
110
-
111
- # # 6. Extract Surname from MRZ_1
112
- # # Updated to handle multiple variations of MRZ structures.
113
- # try:
114
- # if 'last_name' not in mrz_data_dict:
115
- # pattern_surname = r'P<PSE([A-Z]+)<'
116
- # match_surname = re.search(pattern_surname, mrz_1)
117
- # if match_surname:
118
- # surname = match_surname.group(1)
119
- # mrz_data_dict['last_name'] = surname
120
- # except Exception as e:
121
- # print(f"Error extracting surname for PSE: {e}")
122
-
123
- # # 7. Extract Given Name (First Name) from MRZ_1
124
- # # Modified pattern to not rely on `<F`, as MRZ_1 structure can vary.
125
- # try:
126
- # if 'first_name' not in mrz_data_dict:
127
- # pattern_given_name = r'<([A-Z]+)<[A-Z]<'
128
- # match_given_name = re.search(pattern_given_name, mrz_1)
129
- # if match_given_name:
130
- # given_name = match_given_name.group(1)
131
- # mrz_data_dict['first_name'] = given_name
132
- # except Exception as e:
133
- # print(f"Error extracting first name for PSE: {e}")
134
-
135
- # # 8. If the surname or name isn't filled, use a fallback approach
136
- # # If MRZ_1 structure varies, you can adjust these patterns.
137
- # try:
138
- # if 'last_name' not in mrz_data_dict:
139
- # # Fallback to capture everything after the country code
140
- # fallback_pattern_surname = r'P<PSE([A-Z]+)'
141
- # match_surname = re.search(fallback_pattern_surname, mrz_1)
142
- # if match_surname:
143
- # mrz_data_dict['last_name'] = match_surname.group(1)
144
- # except Exception as e:
145
- # print(f"Error extracting surname for PSE: {e}")
146
-
147
- # try:
148
- # if 'first_name' not in mrz_data_dict:
149
- # # Fallback to capture first name in different structures
150
- # fallback_pattern_given_name = r'<([A-Z]+)<'
151
- # match_given_name = re.search(fallback_pattern_given_name, mrz_1)
152
- # if match_given_name:
153
- # mrz_data_dict['first_name'] = match_given_name.group(1)
154
- # except Exception as e:
155
- # print(f"Error extracting first name for PSE: {e}")
156
-
157
- # return mrz_data_dict
158
-
159
- # def translate_arabic_words(dictionary):
160
- # translator = Translator()
161
- # translated_dict = {}
162
- # for key, value in dictionary.items():
163
- # if key not in ['mrz1', 'mrz2']:
164
- # if isinstance(value, str):
165
-
166
- # detected_lang = translator.detect(value).lang
167
- # if detected_lang == 'ar':
168
- # translated_text = translator.translate(value, src='ar', dest='en').text
169
- # translated_dict[key] = translated_text
170
- # else:
171
- # translated_dict[key] = value
172
- # else:
173
- # translated_dict[key] = value
174
- # else:
175
-
176
- # translated_dict[key] = value
177
- # return translated_dict
178
-
179
- # def extract_nationality(mrz_line):
180
- # match = re.match(r"^.{10}([A-Z]{3})", mrz_line)
181
- # if match:
182
- # return match.group(1)
183
- # else:
184
- # return None
185
-
186
- # def palestine_passport_extraction(passport_text, api_key):
187
- # try:
188
- # logging.info(f"Starting Palestine Passport Extraction using api_key.{api_key[:4]}")
189
- # model = configure_genai(api_key)
190
- # jor_passport_result_ai = genai_vision_pse(passport_text, model)
191
-
192
- # logging.info(f"GenAI Raw Output: {jor_passport_result_ai}")
193
- # json_match = re.search(r'```(json|python|plaintext)?\s*(.*?)\s*```', jor_passport_result_ai, re.DOTALL)
194
- # if json_match:
195
- # json_str = json_match.group(2)
196
- # passport_final_result = json.loads(json_str)
197
-
198
- # else:
199
- # json_str = jor_passport_result_ai.replace('```json', '').replace('```', '').strip()
200
- # json_str = json_str.replace('null', 'None')
201
- # passport_final_result = eval(json_str)
202
-
203
- # try:
204
- # passport_final_result = mrz_add(passport_final_result)
205
- # except Exception as e:
206
- # print(f"Error adding MRZ data: {e}")
207
-
208
- # try:
209
- # passport_final_result = swap_dates_if_needed(passport_final_result)
210
- # except Exception as e:
211
- # print(f"Error swapping dates: {e}")
212
-
213
- # try:
214
- # passport_final_result = translate_arabic_words(passport_final_result)
215
- # except Exception as e:
216
- # print(f"Error translating: {e}")
217
-
218
-
219
- # if passport_final_result and not passport_final_result.get('passport_number', ''):
220
- # ## Passport Number Pattern
221
- # passport_number_pattern = r"(\d{8}|\d{7}|\d{6})"
222
- # passport_number_match = re.search(passport_number_pattern, passport_text)
223
- # if passport_number_match:
224
- # passport_number = passport_number_match.group(0)
225
-
226
- # if passport_number:
227
- # passport_final_result['passport_number'] = passport_number
228
- # else:
229
- # passport_number_match = re.search(passport_number_pattern, passport_final_result.get('mrz2', ''))
230
- # if passport_number_match:
231
- # passport_number = passport_number_match.group(0)
232
- # passport_final_result['passport_number'] = passport_number
233
-
234
- # ## Nationality Pattern
235
- # if 'nationality' not in passport_final_result:
236
- # try:
237
- # nationality = extract_nationality(passport_final_result.get('mrz2', ''))
238
- # passport_final_result['nationality'] = nationality
239
- # except:
240
- # mrz2 = passport_final_result.get('mrz2', '')
241
- # nationality_pattern = r'[A-Z]{3}'
242
- # nationality_match = re.search(nationality_pattern, mrz2)
243
- # if nationality_match:
244
- # nationality = nationality_match.group(0)
245
- # passport_final_result['nationality'] = nationality
246
- # else:
247
- # mrz2 = passport_final_result.get('mrz2', '')
248
- # if mrz2:
249
- # nationality = mrz2.split('<')[0][-3:]
250
- # passport_final_result['nationality'] = nationality
251
-
252
- # mrz1 = passport_final_result.get('mrz1', '')
253
- # mrz2 = passport_final_result.get('mrz2', '')
254
- # if mrz1 and mrz2:
255
- # passport_final_result['mrz'] = f"{mrz1} {mrz2}"
256
-
257
- # if "gender" in passport_final_result:
258
- # gender = passport_final_result["gender"].strip().upper()
259
- # if gender == "F":
260
- # passport_final_result["gender"] = "FEMALE"
261
- # elif gender == "M":
262
- # passport_final_result["gender"] = "MALE"
263
-
264
- # if 'gender' in passport_final_result:
265
- # passport_final_result["gender"] = passport_final_result["gender"].strip().upper()
266
-
267
- # if 'issuing_place' in passport_final_result:
268
- # passport_final_result['place_of_issue'] = passport_final_result['issuing_place'].strip().upper()
269
-
270
- # if passport_final_result.get('nationality', '') and len(passport_final_result['nationality']) > 3:
271
- # passport_final_result['nationality'] = 'PSE'
272
-
273
- # if not passport_final_result.get('nationality', ''):
274
- # passport_final_result['nationality'] = 'PSE'
275
-
276
- # passport_final_result['issuing_country'] = 'PSE'
277
-
278
- # return passport_final_result
279
-
280
- # except Exception as e:
281
- # logging.error(f"Error occurred in GenAI: {e}")
282
- # print(f"Error occured in GenAI {e}")
283
- # return {}
284
-
285
1
 
286
2
  import base64
287
3
  import time
288
4
  from io import BytesIO
289
- from typing import Optional
290
5
  import cv2
291
6
 
292
7
  from openai import OpenAI
@@ -305,21 +20,26 @@ Extract ALL fields from this Palestine Passport **front side** image with high a
305
20
 
306
21
  Return a JSON object with the following fields (use the exact field names):
307
22
 
308
- - dob: Date of birth exactly as shown on the card (strictly preserve DD/MM/YYYY format)
309
- - expiry_date: Date of expiry exactly as shown on the card (strictly preserve DD/MM/YYYY format)
23
+ - dob: Date of birth exactly as shown on the card, strictly convert to accurate DD/MM/YYYY format
24
+ - expiry_date: Date of expiry exactly as shown on the card, strictly convert to accurate DD/MM/YYYY format
310
25
  - mrz1: First line of the MRZ,
311
26
  - mrz2: Second line of the MRZ,
312
27
  - full_name: Full name as printed on the card (extract exactly as written)
313
28
  - gender: Gender as either MALE or FEMALE (extract exactly as printed)
314
29
  - mother_name: Mother's Name (extract exactly as printed)
315
30
  - place_of_birth: Place of birth in English (extract exactly as printed)
316
- - issuing_date: Date of issue exactly as shown on the card (preserve original format)
31
+ - issuing_date: Date of issue exactly as shown on the card, strictly convert to accurate DD/MM/YYYY format
317
32
  - place_of_issue: Place of issue as printed on the card
318
33
  - id_number: ID number as printed on the card (exactly 9 characters)
319
34
  - passport_number: Passport number as printed beside N° or No (exactly 7 characters)
320
35
  - header_verified: Return True if any of these texts are present in the image: P<PSE, PSE, PALESTINIAN AUTHORITY, or PALESTINE; otherwise False.
321
36
  - first_name: First name extracted from full_name (if full_name contains multiple words, use the first word)
322
37
  - last_name: Last name extracted from full_name (if full_name contains multiple words, use the last word)
38
+ - gender_mrz: Gender extracted from MRZ line 2: 'M' for Male, 'F' for Female.
39
+ - expiry_date_mrz: Expiry date extracted from MRZ line 2 in DD/MM/YYYY format.
40
+ - dob_mrz: Date of birth extracted from MRZ line 2 in DD/MM/YYYY format.
41
+ - id_number_mrz: ID number extracted from MRZ line 2.
42
+ - passport_number_mrz: Passport number extracted from MRZ line 2 which has only digits.
323
43
 
324
44
 
325
45
  Instructions:
@@ -331,10 +51,10 @@ class PalestinePassportFront(BaseModel):
331
51
 
332
52
 
333
53
  dob: str = Field(...,
334
- description = "The date of birth exactly as shown on the card (strictly preserve DD/MM/YYYY format)",
54
+ description = "The date of birth exactly as shown on the card,convert to accurate DD/MM/YYYY format",
335
55
  )
336
56
  expiry_date: str = Field(...,
337
- description = "The date of expiry exactly as shown on the card (strictly preserve DD/MM/YYYY format)",
57
+ description = "The date of expiry exactly as shown on the card ,convert to accurate DD/MM/YYYY format",
338
58
  )
339
59
 
340
60
  mrz1: str = Field(...,
@@ -365,7 +85,7 @@ class PalestinePassportFront(BaseModel):
365
85
 
366
86
 
367
87
  issuing_date: str = Field(...,
368
- description = "The date of issue exactly as shown on the card (preserve DD/MM/YYYY format)",
88
+ description = "The date of issue exactly as shown on the card,convert to accurate DD/MM/YYYY format" ,
369
89
  )
370
90
 
371
91
  place_of_issue: str = Field(...,
@@ -373,7 +93,7 @@ class PalestinePassportFront(BaseModel):
373
93
  )
374
94
 
375
95
  id_number: str = Field(..., min_length=9, max_length=9,
376
- description = "ID number as printed on the card, extract exactly as written on the card"
96
+ description = "ID number as printed on the card, extract exactly as written on the card "
377
97
  )
378
98
 
379
99
  passport_number: str = Field(..., min_length=7, max_length=7,
@@ -394,6 +114,12 @@ class PalestinePassportFront(BaseModel):
394
114
  description="Last name extracted from full_name",
395
115
  )
396
116
 
117
+ gender_mrz: str = Field(...,description="Gender extracted from MRZ line 2:Return 'M' for Male, 'F' for female.")
118
+ expiry_date_mrz: str = Field(...,description="Expiry date extracted from MRZ line 2 in DD/MM/YYYY format.")
119
+ dob_mrz: str = Field(...,description="Date of birth extracted from MRZ line 2 in DD/MM/YYYY format.")
120
+ passport_number_mrz: str = Field(..., min_length = 7, max_length= 7,description="Passport number extracted from MRZ line 2 which has only digits.")
121
+ id_number_mrz: str = Field(...,min_length= 9, max_length =9, description="ID number extracted from MRZ line 2.")
122
+
397
123
  def process_image(side):
398
124
 
399
125
  if side == "first" or side=='page1':