CoolFace
Apppublic

Akshayram1/Resume_Matching_Tool

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
app.py238 linesDownload Raw Back to root
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.")