import streamlit as st from docx import Document import pdfplumber import re from collections import Counter # Custom CSS for UI enhancements def apply_custom_css(): st.markdown(""" """, unsafe_allow_html=True) # Function to extract text from PDF def extract_text_from_pdf(pdf_file): with pdfplumber.open(pdf_file) as pdf: text = "" for page in pdf.pages: text += page.extract_text() + "\n" return text # Function to extract text from Word Document def extract_text_from_docx(docx_file): doc = Document(docx_file) text = "" for paragraph in doc.paragraphs: text += paragraph.text + "\n" return text # Function to check ATS-friendliness def check_ats_friendly(text): score = 100 suggestions = [] # Keywords check keywords = ["experience", "skills", "education", "certification", "achievements"] for keyword in keywords: if keyword not in text.lower(): score -= 10 suggestions.append(f"Add more emphasis on '{keyword}' in your resume.") # Formatting check if re.search(r"[\t]", text): # Tabs are not ATS-friendly score -= 10 suggestions.append("Avoid using tabs for formatting; use spaces or standard bullet points.") # Font styles check if re.search(r"[{}<>]", text): # Symbols like curly braces and angled brackets can confuse ATS score -= 10 suggestions.append("Remove any special symbols like {}, <>, etc., which might confuse ATS.") # Contact info check if not re.search(r"\b\d{10}\b", text): # Check for a 10-digit phone number score -= 10 suggestions.append("Ensure your resume includes a valid phone number.") if not re.search(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", text): # Check for an email score -= 10 suggestions.append("Include a valid professional email address.") # Suggestion for simplicity if len(text.split()) > 1000: # Resume too long score -= 10 suggestions.append("Try to keep your resume concise and limit it to one or two pages.") return score, suggestions # Function to calculate job fit score and recommend missing keywords def calculate_job_fit_score(resume_text, job_description): resume_words = Counter(resume_text.lower().split()) job_words = Counter(job_description.lower().split()) # Find overlap between resume and job description keywords common_words = resume_words & job_words total_job_words = sum(job_words.values()) missing_keywords = set(job_words.keys()) - set(resume_words.keys()) # Calculate match percentage if total_job_words == 0: match_percentage = 0 else: match_percentage = sum(common_words.values()) / total_job_words * 100 suggestions = [] if match_percentage < 100: suggestions.append( "Consider including the missing keywords in your resume to improve matching." ) return match_percentage, suggestions, missing_keywords # Main App def main(): apply_custom_css() st.markdown("
ATS Resume Checker
", unsafe_allow_html=True) st.write( "Upload your resume to check its ATS-friendliness and compare it with a job description for keyword matching." ) st.markdown("
", unsafe_allow_html=True) uploaded_resume = st.file_uploader( "📂 Upload your Resume (PDF or Word):", type=["pdf", "docx"] ) job_description = st.text_area("📋 Paste the Job Description:") if uploaded_resume: # Extract text based on file type if uploaded_resume.name.endswith(".pdf"): resume_text = extract_text_from_pdf(uploaded_resume) elif uploaded_resume.name.endswith(".docx"): resume_text = extract_text_from_docx(uploaded_resume) else: st.error("Unsupported file format. Please upload a PDF or Word document.") return # Analyze ATS-friendliness st.markdown("
🛠️ ATS Analysis
", unsafe_allow_html=True) ats_score, ats_suggestions = check_ats_friendly(resume_text) st.metric("ATS Score", f"{ats_score}/100") if ats_score >= 80: st.success("✅ Your resume is ATS-friendly!") else: st.warning("⚠️ Your resume needs improvement to be ATS-friendly.") # Display ATS suggestions st.markdown("
📝 Suggestions for ATS Improvement
", unsafe_allow_html=True) if ats_suggestions: for idx, suggestion in enumerate(ats_suggestions, 1): st.markdown(f"
{idx}. {suggestion}
", unsafe_allow_html=True) else: st.write("Your resume is well-optimized for ATS!") st.markdown("
", unsafe_allow_html=True) # Analyze Job Fit if job_description.strip(): st.markdown("
🔍 Job Description Matching
", unsafe_allow_html=True) job_fit_score, job_fit_suggestions, missing_keywords = calculate_job_fit_score( resume_text, job_description ) st.metric("Job Fit Score", f"{job_fit_score:.2f}%") if job_fit_score >= 70: st.success("✅ Your resume matches well with the job description!") else: st.warning("⚠️ Your resume could be tailored better to match the job description.") # Display job fit suggestions st.markdown("
🔑 Missing Keywords
", unsafe_allow_html=True) if missing_keywords: st.write("To improve matching, consider including these keywords:") st.markdown(f"
{', '.join(missing_keywords)}
", unsafe_allow_html=True) else: st.write("Your resume already includes all the required keywords!") if __name__ == "__main__": main()