Spaces:
Build error
Build error
| 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}$', # +91 with optional 0 and separators | |
| r'^\+91[\s\.\-\/]?\d{5}[\s\-\.\/]?\d{5}$', # +91 with 10 digits separated | |
| r'^\d{5}[\s\-\.\/]?\d{5}$', # Local format without country code | |
| r'^\+91[\s\.\-\/]?\d{10}$', # +91 with 10 digits together | |
| r'^\d{10}$', # 10 digits together | |
| r'^\+91[\s\.\-\/]?\(?\d{5}\)?[\s\-\.\/]?\d{5}[\s\-\.\/]?\d{5}$' # +91 with varying separators | |
| r'\+1\s\(\d{3}\)\s\d{3}-\d{4} ', # USA/Canada Intl +1 (XXX) XXX-XXXX | |
| r'\(\d{3}\)\s\d{3}-\d{4} ', # USA/Canada STD (XXX) XXX-XXXX | |
| r'\(\d{3}\)\s\d{3}\s\d{4} ', # USA/Canada (XXX) XXX XXXX | |
| r'\(\d{3}\)\s\d{3}\s\d{3} ', # USA/Canada (XXX) XXX XXX | |
| r'\+1\d{10} ', # +1 XXXXXXXXXX | |
| r'\d{10} ', # XXXXXXXXXX | |
| r'\+44\s\d{4}\s\d{6} ', # UK Intl +44 XXXX XXXXXX | |
| r'\+44\s\d{3}\s\d{3}\s\d{4} ', # UK Intl +44 XXX XXX XXXX | |
| r'0\d{4}\s\d{6} ', # UK STD 0XXXX XXXXXX | |
| r'0\d{3}\s\d{3}\s\d{4} ', # UK STD 0XXX XXX XXXX | |
| r'\+44\d{10} ', # +44 XXXXXXXXXX | |
| r'0\d{10} ', # 0XXXXXXXXXX | |
| r'\+61\s\d\s\d{4}\s\d{4} ', # Australia Intl +61 X XXXX XXXX | |
| r'0\d\s\d{4}\s\d{4} ', # Australia STD 0X XXXX XXXX | |
| r'\+61\d{9} ', # +61 XXXXXXXXX | |
| r'0\d{9} ', # 0XXXXXXXXX | |
| r'\+91\s\d{5}-\d{5} ', # India Intl +91 XXXXX-XXXXX | |
| r'\+91\s\d{4}-\d{6} ', # India Intl +91 XXXX-XXXXXX | |
| r'\+91\s\d{10} ', # India Intl +91 XXXXXXXXXX | |
| r'0\d{2}-\d{7} ', # India STD 0XX-XXXXXXX | |
| r'\+91\d{10} ', # +91 XXXXXXXXXX | |
| r'\+49\s\d{4}\s\d{8} ', # Germany Intl +49 XXXX XXXXXXXX | |
| r'\+49\s\d{3}\s\d{7} ', # Germany Intl +49 XXX XXXXXXX | |
| r'0\d{3}\s\d{8} ', # Germany STD 0XXX XXXXXXXX | |
| r'\+49\d{12} ', # +49 XXXXXXXXXXXX | |
| r'\+49\d{10} ', # +49 XXXXXXXXXX | |
| r'0\d{11} ', # 0XXXXXXXXXXX | |
| r'\+86\s\d{3}\s\d{4}\s\d{4} ', # China Intl +86 XXX XXXX XXXX | |
| r'0\d{3}\s\d{4}\s\d{4} ', # China STD 0XXX XXXX XXXX | |
| r'\+86\d{11} ', # +86 XXXXXXXXXXX | |
| r'\+81\s\d\s\d{4}\s\d{4} ', # Japan Intl +81 X XXXX XXXX | |
| r'\+81\s\d{2}\s\d{4}\s\d{4} ', # Japan Intl +81 XX XXXX XXXX | |
| r'0\d\s\d{4}\s\d{4} ', # Japan STD 0X XXXX XXXX | |
| r'\+81\d{10} ', # +81 XXXXXXXXXX | |
| r'\+81\d{9} ', # +81 XXXXXXXXX | |
| r'0\d{9} ', # 0XXXXXXXXX | |
| r'\+55\s\d{2}\s\d{5}-\d{4} ', # Brazil Intl +55 XX XXXXX-XXXX | |
| r'\+55\s\d{2}\s\d{4}-\d{4} ', # Brazil Intl +55 XX XXXX-XXXX | |
| r'0\d{2}\s\d{4}\s\d{4} ', # Brazil STD 0XX XXXX XXXX | |
| r'\+55\d{11} ', # +55 XXXXXXXXXXX | |
| r'\+55\d{10} ', # +55 XXXXXXXXXX | |
| r'0\d{10} ', # 0XXXXXXXXXX | |
| r'\+33\s\d\s\d{2}\s\d{2}\s\d{2}\s\d{2} ', # France Intl +33 X XX XX XX XX | |
| r'0\d\s\d{2}\s\d{2}\s\d{2}\s\d{2} ', # France STD 0X XX XX XX XX | |
| r'\+33\d{9} ', # +33 XXXXXXXXX | |
| r'0\d{9} ', # 0XXXXXXXXX | |
| r'\+7\s\d{3}\s\d{3}-\d{2}-\d{2} ', # Russia Intl +7 XXX XXX-XX-XX | |
| r'8\s\d{3}\s\d{3}-\d{2}-\d{2} ', # Russia STD 8 XXX XXX-XX-XX | |
| r'\+7\d{10} ', # +7 XXXXXXXXXX | |
| r'8\d{10} ', # 8 XXXXXXXXXX | |
| r'\+27\s\d{2}\s\d{3}\s\d{4} ', # South Africa Intl +27 XX XXX XXXX | |
| r'0\d{2}\s\d{3}\s\d{4} ', # South Africa STD 0XX XXX XXXX | |
| r'\+27\d{9} ', # +27 XXXXXXXXX | |
| r'0\d{9} ', # 0XXXXXXXXX | |
| r'\+52\s\d{3}\s\d{3}\s\d{4} ', # Mexico Intl +52 XXX XXX XXXX | |
| r'\+52\s\d{2}\s\d{4}\s\d{4} ', # Mexico Intl +52 XX XXXX XXXX | |
| r'01\s\d{3}\s\d{4} ', # Mexico STD 01 XXX XXXX | |
| r'\+52\d{10} ', # +52 XXXXXXXXXX | |
| r'01\d{7} ', # 01 XXXXXXX | |
| r'\+234\s\d{3}\s\d{3}\s\d{4} ', # Nigeria Intl +234 XXX XXX XXXX | |
| r'0\d{3}\s\d{3}\s\d{4} ', # Nigeria STD 0XXX XXX XXXX | |
| r'\+234\d{10} ', # +234 XXXXXXXXXX | |
| r'0\d{10} ', # 0XXXXXXXXXX | |
| r'\+971\s\d\s\d{3}\s\d{4} ', # UAE Intl +971 X XXX XXXX | |
| r'0\d\s\d{3}\s\d{4} ', # UAE STD 0X XXX XXXX | |
| r'\+971\d{8} ', # +971 XXXXXXXX | |
| r'0\d{8} ', # 0XXXXXXXX | |
| r'\+54\s9\s\d{3}\s\d{3}\s\d{4} ', # Argentina Intl +54 9 XXX XXX XXXX | |
| r'\+54\s\d{1}\s\d{4}\s\d{4} ', # Argentina Intl +54 X XXXX XXXX | |
| r'0\d{3}\s\d{4} ', # Argentina STD 0XXX XXXX | |
| r'\+54\d{10} ', # +54 9 XXXXXXXXXX | |
| r'\+54\d{9} ', # +54 XXXXXXXXX | |
| r'0\d{7} ', # 0XXXXXXX | |
| r'\+966\s\d\s\d{3}\s\d{4} ', # Saudi Intl +966 X XXX XXXX | |
| r'0\d\s\d{3}\s\d{4} ', # Saudi STD 0X XXX XXXX | |
| r'\+966\d{8} ', # +966 XXXXXXXX | |
| r'0\d{8} ', # 0XXXXXXXX | |
| r'\+1\d{10} ', # +1 XXXXXXXXXX | |
| r'\+1\s\d{3}\s\d{3}\s\d{4} ', # +1 XXX XXX XXXX | |
| r'\d{5}\s\d{5} ', # XXXXX XXXXX | |
| r'\d{10} ', # XXXXXXXXXX | |
| r'\+44\d{10} ', # +44 XXXXXXXXXX | |
| r'0\d{10} ', # 0XXXXXXXXXX | |
| r'\+61\d{9} ', # +61 XXXXXXXXX | |
| r'0\d{9} ', # 0XXXXXXXXX | |
| r'\+91\d{10} ', # +91 XXXXXXXXXX | |
| r'\+49\d{12} ', # +49 XXXXXXXXXXXX | |
| r'\+49\d{10} ', # +49 XXXXXXXXXX | |
| r'0\d{11} ', # 0XXXXXXXXXXX | |
| r'\+86\d{11} ', # +86 XXXXXXXXXXX | |
| r'\+81\d{10} ', # +81 XXXXXXXXXX | |
| r'\+81\d{9} ', # +81 XXXXXXXXX | |
| r'0\d{9} ', # 0XXXXXXXXX | |
| r'\+55\d{11} ', # +55 XXXXXXXXXXX | |
| r'\+55\d{10} ', # +55 XXXXXXXXXX | |
| r'0\d{10} ', # 0XXXXXXXXXX | |
| r'\+33\d{9} ', # +33 XXXXXXXXX | |
| r'0\d{9} ', # 0XXXXXXXXX | |
| r'\+7\d{10} ', # +7 XXXXXXXXXX | |
| r'8\d{10} ', # 8 XXXXXXXXXX | |
| r'\+27\d{9} ', # +27 XXXXXXXXX | |
| r'0\d{9} ', # 0XXXXXXXXX (South Africa STD) | |
| r'\+52\d{10} ', # +52 XXXXXXXXXX | |
| r'01\d{7} ', # 01 XXXXXXX | |
| r'\+234\d{10} ', # +234 XXXXXXXXXX | |
| r'0\d{10} ', # 0XXXXXXXXXX | |
| r'\+971\d{8} ', # +971 XXXXXXXX | |
| r'0\d{8} ', # 0XXXXXXXX | |
| r'\+54\s9\s\d{10} ', # +54 9 XXXXXXXXXX | |
| r'\+54\d{9} ', # +54 XXXXXXXXX | |
| r'0\d{7} ', # 0XXXXXXX | |
| r'\+966\d{8} ', # +966 XXXXXXXX | |
| r'0\d{8}' # 0XXXXXXXX | |
| ] | |
| # Check if the contact matches any of the patterns | |
| return any(re.match(pattern, contact) for pattern in patterns) is not None | |
| # Function to parse resume with SpaCy | |
| # Function to parse resume with SpaCy | |
| 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"} | |
| # Initialize entities as a dictionary with lists | |
| entities = {label: [] for label in ['PERSON', 'EMAIL', 'CONTACT', 'LOCATION', 'SKILL', 'SOFT_SKILL', 'COMPANY', 'PROJECTS', 'JOB_TITLE', 'YEARS_EXPERIENCE', 'EXPERIENCE', 'QUALIFICATION', 'UNIVERSITY', 'COURSE', 'CERTIFICATE']} | |
| # Process entities | |
| for ent in doc.ents: | |
| if ent.label_ in entities: | |
| if ent.text not in entities[ent.label_]: # Avoid duplicates | |
| entities[ent.label_].append(ent.text) | |
| # Map entities to the result JSON | |
| result['personal']['name'] = entities.get('PERSON', [''])[0] if entities.get('PERSON', []) else '' | |
| # Validate email | |
| extracted_email = entities.get('EMAIL', [''])[0] if entities.get('EMAIL', []) else '' | |
| if is_valid_email(extracted_email): | |
| result['personal']['email'] = extracted_email | |
| else: | |
| logging.warning(f"Invalid email detected: {extracted_email}") | |
| result['personal']['email'] = "Invalid email" | |
| result['personal']['invalid_email'] = extracted_email | |
| # Validate contact | |
| extracted_contact = entities.get('CONTACT', [''])[0] if entities.get('CONTACT', []) else '' | |
| if is_valid_contact(extracted_contact): | |
| result['personal']['contact'] = extracted_contact | |
| else: | |
| logging.warning(f"Invalid contact detected: {extracted_contact}") | |
| result['personal']['contact'] = "Invalid contact" | |
| result['personal']['invalid_contact'] = extracted_contact | |
| result['personal']['location'] = entities.get('LOCATION', [''])[0] if entities.get('LOCATION', []) else '' | |
| result['personal']['link'] = hyperlinks # Hyperlinks from extracted text | |
| result['professional']['technical_skills'] = entities.get('SKILL', []) | |
| result['professional']['non_technical_skills'] = entities.get('SOFT_SKILL', []) | |
| result['professional']['tools'] = [] # Add logic if tools extraction is needed | |
| result['professional']['experience'][0]['company'] = entities.get('COMPANY', [''])[0] if entities.get('COMPANY', []) else '' | |
| result['professional']['experience'][0]['projects'] = entities.get('PROJECTS', [''])[0] if entities.get('PROJECTS', []) else '' | |
| result['professional']['experience'][0]['role'] = entities.get('JOB_TITLE', [''])[0] if entities.get('JOB_TITLE', []) else '' | |
| result['professional']['experience'][0]['years'] = entities.get('YEARS_EXPERIENCE', [''])[0] if entities.get('YEARS_EXPERIENCE', []) else '' | |
| result['professional']['experience'][0]['project_experience'] = entities.get('EXPERIENCE', []) | |
| result['professional']['education'][0]['qualification'] = entities.get('QUALIFICATION', [''])[0] if entities.get('QUALIFICATION', []) else '' | |
| result['professional']['education'][0]['university'] = entities.get('UNIVERSITY', [''])[0] if entities.get('UNIVERSITY', []) else '' | |
| result['professional']['education'][0]['course'] = entities.get('COURSE', [''])[0] if entities.get('COURSE', []) else '' | |
| result['professional']['education'][0]['certificate'] = entities.get('CERTIFICATE', [''])[0] if entities.get('CERTIFICATE', []) else '' | |
| print(result) | |
| return result | |