|
import spacy |
|
import logging |
|
import json |
|
from utils.fileTotext import extract_text_based_on_format |
|
import re |
|
|
|
def is_valid_email(email): |
|
email_regex = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$' |
|
return re.match(email_regex, email) is not None |
|
|
|
def is_valid_contact(contact): |
|
patterns = [ |
|
r'^\+91[\s\.\-\/]?\(?0?\)?[\s\-\.\/]?\d{5}[\s\-\.\/]?\d{5}$', |
|
r'^\+91[\s\.\-\/]?\d{5}[\s\-\.\/]?\d{5}$', |
|
r'^\d{5}[\s\-\.\/]?\d{5}$', |
|
r'^\+91[\s\.\-\/]?\d{10}$', |
|
r'^\d{10}$', |
|
r'^\+91[\s\.\-\/]?\(?\d{5}\)?[\s\-\.\/]?\d{5}[\s\-\.\/]?\d{5}$' |
|
r'\+1\s\(\d{3}\)\s\d{3}-\d{4} ', |
|
r'\(\d{3}\)\s\d{3}-\d{4} ', |
|
r'\(\d{3}\)\s\d{3}\s\d{4} ', |
|
r'\(\d{3}\)\s\d{3}\s\d{3} ', |
|
r'\+1\d{10} ', |
|
r'\d{10} ', |
|
r'\+44\s\d{4}\s\d{6} ', |
|
r'\+44\s\d{3}\s\d{3}\s\d{4} ', |
|
r'0\d{4}\s\d{6} ', |
|
r'0\d{3}\s\d{3}\s\d{4} ', |
|
r'\+44\d{10} ', |
|
r'0\d{10} ', |
|
r'\+61\s\d\s\d{4}\s\d{4} ', |
|
r'0\d\s\d{4}\s\d{4} ', |
|
r'\+61\d{9} ', |
|
r'0\d{9} ', |
|
r'\+91\s\d{5}-\d{5} ', |
|
r'\+91\s\d{4}-\d{6} ', |
|
r'\+91\s\d{10} ', |
|
r'0\d{2}-\d{7} ', |
|
r'\+91\d{10} ', |
|
r'\+49\s\d{4}\s\d{8} ', |
|
r'\+49\s\d{3}\s\d{7} ', |
|
r'0\d{3}\s\d{8} ', |
|
r'\+49\d{12} ', |
|
r'\+49\d{10} ', |
|
r'0\d{11} ', |
|
r'\+86\s\d{3}\s\d{4}\s\d{4} ', |
|
r'0\d{3}\s\d{4}\s\d{4} ', |
|
r'\+86\d{11} ', |
|
r'\+81\s\d\s\d{4}\s\d{4} ', |
|
r'\+81\s\d{2}\s\d{4}\s\d{4} ', |
|
r'0\d\s\d{4}\s\d{4} ', |
|
r'\+81\d{10} ', |
|
r'\+81\d{9} ', |
|
r'0\d{9} ', |
|
r'\+55\s\d{2}\s\d{5}-\d{4} ', |
|
r'\+55\s\d{2}\s\d{4}-\d{4} ', |
|
r'0\d{2}\s\d{4}\s\d{4} ', |
|
r'\+55\d{11} ', |
|
r'\+55\d{10} ', |
|
r'0\d{10} ', |
|
r'\+33\s\d\s\d{2}\s\d{2}\s\d{2}\s\d{2} ', |
|
r'0\d\s\d{2}\s\d{2}\s\d{2}\s\d{2} ', |
|
r'\+33\d{9} ', |
|
r'0\d{9} ', |
|
r'\+7\s\d{3}\s\d{3}-\d{2}-\d{2} ', |
|
r'8\s\d{3}\s\d{3}-\d{2}-\d{2} ', |
|
r'\+7\d{10} ', |
|
r'8\d{10} ', |
|
r'\+27\s\d{2}\s\d{3}\s\d{4} ', |
|
r'0\d{2}\s\d{3}\s\d{4} ', |
|
r'\+27\d{9} ', |
|
r'0\d{9} ', |
|
r'\+52\s\d{3}\s\d{3}\s\d{4} ', |
|
r'\+52\s\d{2}\s\d{4}\s\d{4} ', |
|
r'01\s\d{3}\s\d{4} ', |
|
r'\+52\d{10} ', |
|
r'01\d{7} ', |
|
r'\+234\s\d{3}\s\d{3}\s\d{4} ', |
|
r'0\d{3}\s\d{3}\s\d{4} ', |
|
r'\+234\d{10} ', |
|
r'0\d{10} ', |
|
r'\+971\s\d\s\d{3}\s\d{4} ', |
|
r'0\d\s\d{3}\s\d{4} ', |
|
r'\+971\d{8} ', |
|
r'0\d{8} ', |
|
r'\+54\s9\s\d{3}\s\d{3}\s\d{4} ', |
|
r'\+54\s\d{1}\s\d{4}\s\d{4} ', |
|
r'0\d{3}\s\d{4} ', |
|
r'\+54\d{10} ', |
|
r'\+54\d{9} ', |
|
r'0\d{7} ', |
|
r'\+966\s\d\s\d{3}\s\d{4} ', |
|
r'0\d\s\d{3}\s\d{4} ', |
|
r'\+966\d{8} ', |
|
r'0\d{8} ', |
|
r'\+1\d{10} ', |
|
r'\+1\s\d{3}\s\d{3}\s\d{4} ', |
|
r'\d{5}\s\d{5} ', |
|
r'\d{10} ', |
|
r'\+44\d{10} ', |
|
r'0\d{10} ', |
|
r'\+61\d{9} ', |
|
r'0\d{9} ', |
|
r'\+91\d{10} ', |
|
r'\+49\d{12} ', |
|
r'\+49\d{10} ', |
|
r'0\d{11} ', |
|
r'\+86\d{11} ', |
|
r'\+81\d{10} ', |
|
r'\+81\d{9} ', |
|
r'0\d{9} ', |
|
r'\+55\d{11} ', |
|
r'\+55\d{10} ', |
|
r'0\d{10} ', |
|
r'\+33\d{9} ', |
|
r'0\d{9} ', |
|
r'\+7\d{10} ', |
|
r'8\d{10} ', |
|
r'\+27\d{9} ', |
|
r'0\d{9} ', |
|
r'\+52\d{10} ', |
|
r'01\d{7} ', |
|
r'\+234\d{10} ', |
|
r'0\d{10} ', |
|
r'\+971\d{8} ', |
|
r'0\d{8} ', |
|
r'\+54\s9\s\d{10} ', |
|
r'\+54\d{9} ', |
|
r'0\d{7} ', |
|
r'\+966\d{8} ', |
|
r'0\d{8}' |
|
] |
|
|
|
|
|
return any(re.match(pattern, contact) for pattern in patterns) is not None |
|
|
|
|
|
def extract_contact_details(text): |
|
|
|
|
|
combined_phone_regex = re.compile(r''' |
|
(?: |
|
#(?:(?:\+91[-.\s]?)?\d{5}[-.\s]?\d{5})|(?:\+?\d{1,3})?[-.\s()]?\d{5,}[-.\s()]?\d{5,}[-.\s()]?\d{1,9} | /^[\.-)( ]*([0-9]{3})[\.-)( ]*([0-9]{3})[\.-)( ]*([0-9]{4})$/ | |
|
\+1\s\(\d{3}\)\s\d{3}-\d{4} | # USA/Canada Intl +1 (XXX) XXX-XXXX |
|
\(\d{3}\)\s\d{3}-\d{4} | # USA/Canada STD (XXX) XXX-XXXX |
|
\(\d{3}\)\s\d{3}\s\d{4} | # USA/Canada (XXX) XXX XXXX |
|
\(\d{3}\)\s\d{3}\s\d{3} | # USA/Canada (XXX) XXX XXX |
|
\+1\d{10} | # +1 XXXXXXXXXX |
|
\d{10} | # XXXXXXXXXX |
|
\+44\s\d{4}\s\d{6} | # UK Intl +44 XXXX XXXXXX |
|
\+44\s\d{3}\s\d{3}\s\d{4} | # UK Intl +44 XXX XXX XXXX |
|
0\d{4}\s\d{6} | # UK STD 0XXXX XXXXXX |
|
0\d{3}\s\d{3}\s\d{4} | # UK STD 0XXX XXX XXXX |
|
\+44\d{10} | # +44 XXXXXXXXXX |
|
0\d{10} | # 0XXXXXXXXXX |
|
\+61\s\d\s\d{4}\s\d{4} | # Australia Intl +61 X XXXX XXXX |
|
0\d\s\d{4}\s\d{4} | # Australia STD 0X XXXX XXXX |
|
\+61\d{9} | # +61 XXXXXXXXX |
|
0\d{9} | # 0XXXXXXXXX |
|
\+91\s\d{5}-\d{5} | # India Intl +91 XXXXX-XXXXX |
|
\+91\s\d{4}-\d{6} | # India Intl +91 XXXX-XXXXXX |
|
\+91\s\d{10} | # India Intl +91 XXXXXXXXXX |
|
\+91\s\d{3}\s\d{3}\s\d{4} | # India Intl +91 XXX XXX XXXX |
|
\+91\s\d{3}-\d{3}-\d{4} | # India Intl +91 XXX-XXX-XXXX |
|
\+91\s\d{2}\s\d{4}\s\d{4} | # India Intl +91 XX XXXX XXXX |
|
\+91\s\d{2}-\d{4}-\d{4} | # India Intl +91 XX-XXXX-XXXX |
|
\+91\s\d{5}\s\d{5} | # India Intl +91 XXXXX XXXXX |
|
\d{5}\s\d{5} | # India XXXXX XXXXX |
|
\d{5}-\d{5} | # India XXXXX-XXXXX |
|
0\d{2}-\d{7} | # India STD 0XX-XXXXXXX |
|
\+91\d{10} | # +91 XXXXXXXXXX |
|
\d{10} | # XXXXXXXXXX # Here is the regex to handle all possible combination of the contact |
|
\d{6}-\d{4} | # XXXXXX-XXXX |
|
\d{4}-\d{6} | # XXXX-XXXXXX |
|
\d{3}\s\d{3}\s\d{4} | # XXX XXX XXXX |
|
\d{3}-\d{3}-\d{4} | # XXX-XXX-XXXX |
|
\d{4}\s\d{3}\s\d{3} | # XXXX XXX XXX |
|
\d{4}-\d{3}-\d{3} | # XXXX-XXX-XXX #----- |
|
\+49\s\d{4}\s\d{8} | # Germany Intl +49 XXXX XXXXXXXX |
|
\+49\s\d{3}\s\d{7} | # Germany Intl +49 XXX XXXXXXX |
|
0\d{3}\s\d{8} | # Germany STD 0XXX XXXXXXXX |
|
\+49\d{12} | # +49 XXXXXXXXXXXX |
|
\+49\d{10} | # +49 XXXXXXXXXX |
|
0\d{11} | # 0XXXXXXXXXXX |
|
\+86\s\d{3}\s\d{4}\s\d{4} | # China Intl +86 XXX XXXX XXXX |
|
0\d{3}\s\d{4}\s\d{4} | # China STD 0XXX XXXX XXXX |
|
\+86\d{11} | # +86 XXXXXXXXXXX |
|
\+81\s\d\s\d{4}\s\d{4} | # Japan Intl +81 X XXXX XXXX |
|
\+81\s\d{2}\s\d{4}\s\d{4} | # Japan Intl +81 XX XXXX XXXX |
|
0\d\s\d{4}\s\d{4} | # Japan STD 0X XXXX XXXX |
|
\+81\d{10} | # +81 XXXXXXXXXX |
|
\+81\d{9} | # +81 XXXXXXXXX |
|
0\d{9} | # 0XXXXXXXXX |
|
\+55\s\d{2}\s\d{5}-\d{4} | # Brazil Intl +55 XX XXXXX-XXXX |
|
\+55\s\d{2}\s\d{4}-\d{4} | # Brazil Intl +55 XX XXXX-XXXX |
|
0\d{2}\s\d{4}\s\d{4} | # Brazil STD 0XX XXXX XXXX |
|
\+55\d{11} | # +55 XXXXXXXXXXX |
|
\+55\d{10} | # +55 XXXXXXXXXX |
|
0\d{10} | # 0XXXXXXXXXX |
|
\+33\s\d\s\d{2}\s\d{2}\s\d{2}\s\d{2} | # France Intl +33 X XX XX XX XX |
|
0\d\s\d{2}\s\d{2}\s\d{2}\s\d{2} | # France STD 0X XX XX XX XX |
|
\+33\d{9} | # +33 XXXXXXXXX |
|
0\d{9} | # 0XXXXXXXXX |
|
\+7\s\d{3}\s\d{3}-\d{2}-\d{2} | # Russia Intl +7 XXX XXX-XX-XX |
|
8\s\d{3}\s\d{3}-\d{2}-\d{2} | # Russia STD 8 XXX XXX-XX-XX |
|
\+7\d{10} | # +7 XXXXXXXXXX |
|
8\d{10} | # 8 XXXXXXXXXX |
|
\+27\s\d{2}\s\d{3}\s\d{4} | # South Africa Intl +27 XX XXX XXXX |
|
0\d{2}\s\d{3}\s\d{4} | # South Africa STD 0XX XXX XXXX |
|
\+27\d{9} | # +27 XXXXXXXXX |
|
0\d{9} | # 0XXXXXXXXX |
|
\+52\s\d{3}\s\d{3}\s\d{4} | # Mexico Intl +52 XXX XXX XXXX |
|
\+52\s\d{2}\s\d{4}\s\d{4} | # Mexico Intl +52 XX XXXX XXXX |
|
01\s\d{3}\s\d{4} | # Mexico STD 01 XXX XXXX |
|
\+52\d{10} | # +52 XXXXXXXXXX |
|
01\d{7} | # 01 XXXXXXX |
|
\+234\s\d{3}\s\d{3}\s\d{4} | # Nigeria Intl +234 XXX XXX XXXX |
|
0\d{3}\s\d{3}\s\d{4} | # Nigeria STD 0XXX XXX XXXX |
|
\+234\d{10} | # +234 XXXXXXXXXX |
|
0\d{10} | # 0XXXXXXXXXX |
|
\+971\s\d\s\d{3}\s\d{4} | # UAE Intl +971 X XXX XXXX |
|
0\d\s\d{3}\s\d{4} | # UAE STD 0X XXX XXXX |
|
\+971\d{8} | # +971 XXXXXXXX |
|
0\d{8} | # 0XXXXXXXX |
|
\+54\s9\s\d{3}\s\d{3}\s\d{4} | # Argentina Intl +54 9 XXX XXX XXXX |
|
\+54\s\d{1}\s\d{4}\s\d{4} | # Argentina Intl +54 X XXXX XXXX |
|
0\d{3}\s\d{4} | # Argentina STD 0XXX XXXX |
|
\+54\d{10} | # +54 9 XXXXXXXXXX |
|
\+54\d{9} | # +54 XXXXXXXXX |
|
0\d{7} | # 0XXXXXXX |
|
\+966\s\d\s\d{3}\s\d{4} | # Saudi Intl +966 X XXX XXXX |
|
0\d\s\d{3}\s\d{4} | # Saudi STD 0X XXX XXXX |
|
\+966\d{8} | # +966 XXXXXXXX |
|
0\d{8} | # 0XXXXXXXX |
|
\+1\d{10} | # +1 XXXXXXXXXX |
|
\+1\s\d{3}\s\d{3}\s\d{4} | # +1 XXX XXX XXXX |
|
\d{5}\s\d{5} | # XXXXX XXXXX |
|
\d{10} | # XXXXXXXXXX |
|
\+44\d{10} | # +44 XXXXXXXXXX |
|
0\d{10} | # 0XXXXXXXXXX |
|
\+61\d{9} | # +61 XXXXXXXXX |
|
0\d{9} | # 0XXXXXXXXX |
|
\+91\d{10} | # +91 XXXXXXXXXX |
|
\+49\d{12} | # +49 XXXXXXXXXXXX |
|
\+49\d{10} | # +49 XXXXXXXXXX |
|
0\d{11} | # 0XXXXXXXXXXX |
|
\+86\d{11} | # +86 XXXXXXXXXXX |
|
\+81\d{10} | # +81 XXXXXXXXXX |
|
\+81\d{9} | # +81 XXXXXXXXX |
|
0\d{9} | # 0XXXXXXXXX |
|
\+55\d{11} | # +55 XXXXXXXXXXX |
|
\+55\d{10} | # +55 XXXXXXXXXX |
|
0\d{10} | # 0XXXXXXXXXX |
|
\+33\d{9} | # +33 XXXXXXXXX |
|
0\d{9} | # 0XXXXXXXXX |
|
\+7\d{10} | # +7 XXXXXXXXXX |
|
8\d{10} | # 8 XXXXXXXXXX |
|
\+27\d{9} | # +27 XXXXXXXXX |
|
0\d{9} | # 0XXXXXXXXX (South Africa STD) |
|
\+52\d{10} | # +52 XXXXXXXXXX |
|
01\d{7} | # 01 XXXXXXX |
|
\+234\d{10} | # +234 XXXXXXXXXX |
|
0\d{10} | # 0XXXXXXXXXX |
|
\+971\d{8} | # +971 XXXXXXXX |
|
0\d{8} | # 0XXXXXXXX |
|
\+54\s9\s\d{10} | # +54 9 XXXXXXXXXX |
|
\+54\d{9} | # +54 XXXXXXXXX |
|
0\d{7} | # 0XXXXXXX |
|
\+966\d{8} | # +966 XXXXXXXX |
|
0\d{8} # 0XXXXXXXX |
|
\+\d{3}-\d{3}-\d{4} |
|
) |
|
''',re.VERBOSE) |
|
|
|
|
|
email_regex = re.compile(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b') |
|
|
|
|
|
link_regex = re.compile(r'\b(?:https?:\/\/)?(?:www\.)[a-zA-Z0-9-]+\.(?:com|co\.in|co|io|org|net|edu|gov|mil|int|uk|us|in|de|au|app|tech|xyz|info|biz|fr|dev)\b') |
|
|
|
|
|
phone_numbers = [num for num in combined_phone_regex.findall(text) if len(num) >= 5] |
|
|
|
emails = email_regex.findall(text) |
|
|
|
links_RE = [link for link in link_regex.findall(text) if len(link)>=11] |
|
|
|
|
|
links_RE = [link for link in links_RE if not any(email in link for email in emails)] |
|
|
|
return { |
|
"phone_numbers": phone_numbers, |
|
"emails": emails, |
|
"links_RE": links_RE |
|
} |
|
|
|
|
|
def process_extracted_text(extracted_text): |
|
|
|
data = json.dumps(extracted_text, indent=4) |
|
data = json.loads(data) |
|
|
|
|
|
combined_results = { |
|
"phone_numbers": [], |
|
"emails": [], |
|
"links_RE": [] |
|
} |
|
|
|
|
|
for filename, text in data.items(): |
|
contact_details = extract_contact_details(text) |
|
|
|
combined_results["phone_numbers"].extend(contact_details["phone_numbers"]) |
|
combined_results["emails"].extend(contact_details["emails"]) |
|
combined_results["links_RE"].extend(contact_details["links_RE"]) |
|
|
|
|
|
|
|
combined_results_json = combined_results |
|
|
|
|
|
print("Combined contact details in JSON format:") |
|
print(combined_results_json) |
|
|
|
return combined_results_json |
|
|
|
|
|
|
|
def Parser_from_model(file_path): |
|
|
|
result = { |
|
"personal": { |
|
"name": [], |
|
"contact": [], |
|
"email": [], |
|
"location": [], |
|
"link": [], |
|
"invalid_email": [], |
|
"invalid_contact": [] |
|
}, |
|
"professional": { |
|
"technical_skills": [], |
|
"non_technical_skills": [], |
|
"tools": [], |
|
"experience": [ |
|
{ |
|
"company": [], |
|
"projects": [], |
|
"role": [], |
|
"years": [], |
|
"project_experience": [] |
|
} |
|
], |
|
"education": [ |
|
{ |
|
"qualification": [], |
|
"university": [], |
|
"course": [], |
|
"certificate": [] |
|
} |
|
] |
|
} |
|
} |
|
|
|
try: |
|
nlp = spacy.load("Spacy_Models/ner_model_05_3") |
|
logging.debug("Model loaded successfully.") |
|
except Exception as e: |
|
logging.error(f"Error loading model: {e}") |
|
return {"error": "Model loading failed"} |
|
|
|
try: |
|
cleaned_text, hyperlinks = extract_text_based_on_format(file_path) |
|
if not cleaned_text.strip(): |
|
logging.error("No text extracted from the file.") |
|
return {"error": "Text extraction failed"} |
|
except Exception as e: |
|
logging.error(f"Error extracting text from file: {e}") |
|
return {"error": "Text extraction failed"} |
|
|
|
try: |
|
doc = nlp(cleaned_text) |
|
except Exception as e: |
|
logging.error(f"Error processing text with SpaCy: {e}") |
|
return {"error": "Text processing failed"} |
|
|
|
|
|
cont_data = process_extracted_text(cleaned_text) |
|
|
|
|
|
entities = {label: [] for label in [ |
|
'PERSON', 'EMAIL', 'CONTACT', 'LOCATION', 'SKILL', 'SOFT_SKILL', |
|
'COMPANY', 'PROJECTS', 'JOB_TITLE', 'YEARS_EXPERIENCE', 'EXPERIENCE', |
|
'QUALIFICATION', 'UNIVERSITY', 'COURSE', 'CERTIFICATE' |
|
]} |
|
|
|
|
|
for ent in doc.ents: |
|
if ent.label_ in entities and ent.text not in entities[ent.label_]: |
|
entities[ent.label_].append(ent.text) |
|
|
|
|
|
def normalize_to_list(value): |
|
if value is []: |
|
return None |
|
elif isinstance(value, (str, int, float)): |
|
return [str(value)] |
|
elif isinstance(value, list): |
|
return value |
|
else: |
|
return [str(value)] |
|
|
|
|
|
result['personal']['name'] = normalize_to_list(entities.get('PERSON')) |
|
result['personal']['email'] += cont_data['emails'] |
|
result['personal']['invalid_email'] = [] |
|
|
|
|
|
for email in entities.get('EMAIL', []): |
|
if is_valid_email(email): |
|
result['personal']['email'].append(email) |
|
else: |
|
result['personal']['invalid_email'].append(email) |
|
|
|
|
|
result['personal']['contact'] += cont_data['phone_numbers'] |
|
result['personal']['invalid_contact'] = [] |
|
for contact in entities.get('CONTACT', []): |
|
if is_valid_contact(contact): |
|
result['personal']['contact'].append(contact) |
|
else: |
|
result['personal']['invalid_contact'].append(contact) |
|
|
|
result['personal']['location'] = normalize_to_list(entities.get('LOCATION')) |
|
result['personal']['link'] = normalize_to_list(hyperlinks) |
|
result['personal']['link'] += cont_data['links_RE'] |
|
|
|
e |
|
|
|
result['professional']['technical_skills'] = normalize_to_list(entities.get('SKILL')) |
|
result['professional']['non_technical_skills'] = normalize_to_list(entities.get('SOFT_SKILL')) |
|
result['professional']['tools'] = None |
|
|
|
experience = result['professional']['experience'][0] |
|
experience['company'] = normalize_to_list(entities.get('COMPANY')) |
|
experience['projects'] = normalize_to_list(entities.get('PROJECTS')) |
|
experience['role'] = normalize_to_list(entities.get('JOB_TITLE')) |
|
experience['years'] = normalize_to_list(entities.get('YEARS_EXPERIENCE')) |
|
experience['project_experience'] = normalize_to_list(entities.get('EXPERIENCE')) |
|
|
|
education = result['professional']['education'][0] |
|
education['qualification'] = normalize_to_list(entities.get('QUALIFICATION')) |
|
education['university'] = normalize_to_list(entities.get('UNIVERSITY')) |
|
education['course'] = normalize_to_list(entities.get('COURSE')) |
|
education['certificate'] = normalize_to_list(entities.get('CERTIFICATE')) |
|
|
|
print(result) |
|
return result |
|
|
|
|
|
|