Akshayram1/Resume_Matching_Tool
0
1# Import necessary libraries2import streamlit as st3import nltk4from gensim.models.doc2vec import Doc2Vec, TaggedDocument5from nltk.tokenize import word_tokenize6import PyPDF27import pandas as pd8import re9import matplotlib.pyplot as plt10import seaborn as sns11import spacy12 13# Download necessary NLTK data14nltk.download('punkt')15 16# Define regular expressions for pattern matching17float_regex = re.compile(r'^\d{1,2}(\.\d{1,2})?$')18email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'19float_digit_regex = re.compile(r'^\d{10}$')20email_with_phone_regex = re.compile(r'(\d{10}).|.(\d{10})')21 22# Function to extract text from a PDF file23def extract_text_from_pdf(pdf_file):24 pdf_reader = PyPDF2.PdfReader(pdf_file)25 text = ""26 for page_num in range(len(pdf_reader.pages)):27 text += pdf_reader.pages[page_num].extract_text()28 return text29 30# Function to tokenize text using the NLP model31def tokenize_text(text, nlp_model):32 doc = nlp_model(text, disable=["tagger", "parser"])33 tokens = [(token.text.lower(), token.label_) for token in doc.ents]34 return tokens35 36# Function to extract CGPA from a resume37def extract_cgpa(resume_text):38 cgpa_pattern = r'\b(?:CGPA|GPA|C\.G\.PA|Cumulative GPA)\s*:?[\s-]([0-9]+(?:\.[0-9]+)?)\b|\b([0-9]+(?:\.[0-9]+)?)\s(?:CGPA|GPA)\b'39 match = re.search(cgpa_pattern, resume_text, re.IGNORECASE)40 if match:41 cgpa = match.group(1) if match.group(1) else match.group(2)42 return float(cgpa)43 else:44 return None45 46# Function to extract skills from a resume47def extract_skills(text, skills_keywords):48 skills = [skill.lower() for skill in skills_keywords if re.search(r'\b' + re.escape(skill.lower()) + r'\b', text.lower())]49 return skills50 51# Function to preprocess text52def preprocess_text(text):53 return word_tokenize(text.lower())54 55# Function to train a Doc2Vec model56def train_doc2vec_model(documents):57 model = Doc2Vec(vector_size=20, min_count=2, epochs=50)58 model.build_vocab(documents)59 model.train(documents, total_examples=model.corpus_count, epochs=model.epochs)60 return model61 62# Function to calculate similarity between two texts63def calculate_similarity(model, text1, text2):64 vector1 = model.infer_vector(preprocess_text(text1))65 vector2 = model.infer_vector(preprocess_text(text2))66 return model.dv.cosine_similarities(vector1, [vector2])[0]67 68# Function to calculate accuracy69def accuracy_calculation(true_positives, false_positives, false_negatives):70 total = true_positives + false_positives + false_negatives71 accuracy = true_positives / total if total != 0 else 072 return accuracy73 74# Streamlit Frontend75st.markdown("# Resume Matching Tool ๐๐")76st.markdown("An application to match resumes with a job description.")77 78# Sidebar - File Upload for Resumes79st.sidebar.markdown("## Upload Resumes PDF")80resumes_files = st.sidebar.file_uploader("Upload Resumes PDF", type=["pdf"], accept_multiple_files=True)81 82if resumes_files:83 # Sidebar - File Upload for Job Descriptions84 st.sidebar.markdown("## Upload Job Description PDF")85 job_descriptions_file = st.sidebar.file_uploader("Upload Job Description PDF", type=["pdf"])86 87 if job_descriptions_file:88 # Load the pre-trained NLP model89 nlp_model_path = "en_Resume_Matching_Keywords"90 nlp = spacy.load(nlp_model_path)91 92 # Backend Processing93 job_description_text = extract_text_from_pdf(job_descriptions_file)94 resumes_texts = [extract_text_from_pdf(resume_file) for resume_file in resumes_files]95 job_description_text = extract_text_from_pdf(job_descriptions_file)96 job_description_tokens = tokenize_text(job_description_text, nlp)97 98 # Initialize counters99 overall_skill_matches = 0100 overall_qualification_matches = 0101 102 # Create a list to store individual results103 results_list = []104 job_skills = set()105 job_qualifications = set()106 107 for job_token, job_label in job_description_tokens:108 if job_label == 'QUALIFICATION':109 job_qualifications.add(job_token.replace('\n', ' '))110 elif job_label == 'SKILLS':111 job_skills.add(job_token.replace('\n', ' '))112 113 job_skills_number = len(job_skills)114 job_qualifications_number = len(job_qualifications)115 116 # Lists to store counts of matched skills for all resumes117 skills_counts_all_resumes = []118 119 # Iterate over all uploaded resumes120 for uploaded_resume in resumes_files:121 resume_text = extract_text_from_pdf(uploaded_resume)122 resume_tokens = tokenize_text(resume_text, nlp)123 124 # Initialize counters for individual resume125 skillMatch = 0126 qualificationMatch = 0127 cgpa = ""128 129 # Lists to store matched skills and qualifications for each resume130 matched_skills = set()131 matched_qualifications = set()132 email = set()133 phone = set()134 name = set()135 136 # Compare the tokens in the resume with the job description137 for resume_token, resume_label in resume_tokens:138 for job_token, job_label in job_description_tokens:139 if resume_token.lower().replace('\n', ' ') == job_token.lower().replace('\n', ' '):140 if resume_label == 'SKILLS':141 matched_skills.add(resume_token.replace('\n', ' '))142 elif resume_label == 'QUALIFICATION':143 matched_qualifications.add(resume_token.replace('\n', ' '))144 elif resume_label == 'PHONE' and bool(float_digit_regex.match(resume_token)):145 phone.add(resume_token) 146 elif resume_label == 'QUALIFICATION':147 matched_qualifications.add(resume_token.replace('\n', ' '))148 149 skillMatch = len(matched_skills)150 qualificationMatch = len(matched_qualifications)151 152 # Convert the list of emails to a set153 email_set = set(re.findall(email_pattern, resume_text.replace('\n', ' ')))154 email.update(email_set)155 156 numberphone=""157 for email_str in email:158 numberphone = email_with_phone_regex.search(email_str)159 if numberphone:160 email.remove(email_str)161 val=numberphone.group(1) or numberphone.group(2)162 phone.add(val)163 email.add(email_str.strip(val))164 165 # Increment overall counters based on matches166 overall_skill_matches += skillMatch167 overall_qualification_matches += qualificationMatch168 169 # Add count of matched skills for this resume to the list170 skills_counts_all_resumes.append([resume_text.count(skill.lower()) for skill in job_skills])171 172 # Create a dictionary for the current resume and append to the results list173 result_dict = {174 "Resume": uploaded_resume.name,175 "Similarity Score": (skillMatch/job_skills_number)*100,176 "Skill Matches": skillMatch,177 "Matched Skills": matched_skills,178 "CGPA": extract_cgpa(resume_text),179 "Email": email,180 "Phone": phone,181 "Qualification Matches": qualificationMatch,182 "Matched Qualifications": matched_qualifications183 }184 185 results_list.append(result_dict)186 187 # Display overall matches188 st.subheader("Overall Matches")189 st.write(f"Total Skill Matches: {overall_skill_matches}")190 st.write(f"Total Qualification Matches: {overall_qualification_matches}")191 st.write(f"Job Qualifications: {job_qualifications}")192 st.write(f"Job Skills: {job_skills}")193 194 # Display individual results in a table195 results_df = pd.DataFrame(results_list)196 st.subheader("Individual Results")197 st.dataframe(results_df)198 tagged_resumes = [TaggedDocument(words=preprocess_text(text), tags=[str(i)]) for i, text in enumerate(resumes_texts)]199 model_resumes = train_doc2vec_model(tagged_resumes)200 201 st.subheader("\nHeatmap:")202 203 # Get skills keywords from user input204 skills_keywords_input = st.text_input("Enter skills keywords separated by commas (e.g., python, java, machine learning):")205 skills_keywords = [skill.strip() for skill in skills_keywords_input.split(',') if skill.strip()]206 207 if skills_keywords:208 # Calculate the similarity score between each skill keyword and the resume text209 skills_similarity_scores = []210 for resume_text in resumes_texts:211 resume_text_similarity_scores = []212 for skill in skills_keywords:213 similarity_score = calculate_similarity(model_resumes, resume_text, skill)214 resume_text_similarity_scores.append(similarity_score)215 skills_similarity_scores.append(resume_text_similarity_scores)216 217 # Create a DataFrame with the similarity scores and set the index to the names of the PDFs218 skills_similarity_df = pd.DataFrame(skills_similarity_scores, columns=skills_keywords, index=[resume_file.name for resume_file in resumes_files])219 220 # Plot the heatmap221 fig, ax = plt.subplots(figsize=(12, 8))222 sns.heatmap(skills_similarity_df, cmap='YlGnBu', annot=True, fmt=".2f", ax=ax)223 ax.set_title('Heatmap for Skills Similarity')224 ax.set_xlabel('Skills')225 ax.set_ylabel('Resumes')226 227 # Rotate the y-axis labels for better readability228 plt.yticks(rotation=0)229 230 # Display the Matplotlib figure using st.pyplot()231 st.pyplot(fig)232 else:233 st.write("Please enter at least one skill keyword.")234 235 else:236 st.warning("Please upload the Job Description PDF to proceed.")237else:238 st.warning("Please upload Resumes PDF to proceed.")