import streamlit as st import PyPDF2 import spacy import pandas as pd import json from collections import Counter # Custom CSS to enhance UI def set_custom_css(): st.markdown(""" """, unsafe_allow_html=True) @st.cache_resource def load_spacy(): try: return spacy.load("en_core_web_sm") except: st.warning("Downloading language model...") import subprocess subprocess.run(["python", "-m", "spacy", "download", "en_core_web_sm"]) return spacy.load("en_core_web_sm") def extract_text_from_pdf(pdf_file): try: pdf_reader = PyPDF2.PdfReader(pdf_file) text = "" for page in pdf_reader.pages: text += page.extract_text() + " " return text.strip() except Exception as e: st.error(f"Error extracting text from PDF: {str(e)}") return "" def extract_skills(text, nlp): doc = nlp(text.lower()) technical_patterns = { # Programming Languages "python", "java", "javascript", "c++", "ruby", "php", "swift", "kotlin", "go", # Web Technologies "html", "css", "react", "angular", "vue.js", "node.js", "express.js", "django", "flask", "spring boot", "asp.net","ReactJS","React.js","NodeJS","Node.js" # Databases "sql", "mysql", "postgresql", "mongodb", "oracle", "redis", "elasticsearch", # Cloud & DevOps "aws", "azure", "gcp", "docker", "kubernetes", "jenkins", "gitlab", "terraform", "ansible", "devops", "ci/cd", # Data Science & AI "machine learning", "deep learning", "artificial intelligence", "data analysis", "pandas", "numpy", "scikit-learn", "tensorflow", "pytorch", "nlp", # Other Technical Skills "git", "rest api", "graphql", "microservices", "linux", "agile", "scrum" } soft_patterns = { # Communication "communication", "presentation", "public speaking", "writing", "listening", # Leadership "leadership", "team management", "mentoring", "coaching", "strategic thinking", # Collaboration "teamwork", "collaboration", "interpersonal", "relationship building", # Problem Solving "problem solving", "analytical", "critical thinking", "decision making", "troubleshooting", # Project Management "project management", "time management", "organization", "planning", "risk management", # Other Soft Skills "adaptability", "creativity", "innovation", "attention to detail", "multitasking", "negotiation", "conflict resolution", "customer service" } found_technical_skills = set() found_soft_skills = set() text_lower = text.lower() for skill in technical_patterns: if skill in text_lower: found_technical_skills.add(skill) for skill in soft_patterns: if skill in text_lower: found_soft_skills.add(skill) return list(found_technical_skills), list(found_soft_skills) def boost_score(original_score, boost_factor=1.2): """Boost the score while keeping it within reasonable bounds""" boosted = original_score * boost_factor return min(100, max(boosted, original_score)) def calculate_match_score(resume_skills, jd_skills, weight): if not jd_skills: return 0.0 matched_skills = set(resume_skills) & set(jd_skills) base_score = (len(matched_skills) / len(set(jd_skills))) * 100 * weight # Apply boosting to the base score boosted_score = boost_score(base_score) return min(100 * weight, boosted_score) def analyze_resume(resume_text, job_description, nlp): try: resume_tech_skills, resume_soft_skills = extract_skills(resume_text, nlp) jd_tech_skills, jd_soft_skills = extract_skills(job_description, nlp) weights = { 'technical': 0.8, 'soft': 0.2 } tech_score = calculate_match_score(resume_tech_skills, jd_tech_skills, weights['technical']) soft_score = calculate_match_score(resume_soft_skills, jd_soft_skills, weights['soft']) # Apply additional boosting for overall score overall_score = min(100, boost_score(tech_score + soft_score, 1.15)) tech_match_percent = boost_score((len(set(resume_tech_skills) & set(jd_tech_skills)) / max(len(set(jd_tech_skills)), 1)) * 100) soft_match_percent = boost_score((len(set(resume_soft_skills) & set(jd_soft_skills)) / max(len(set(jd_soft_skills)), 1)) * 100) missing_tech_skills = list(set(jd_tech_skills) - set(resume_tech_skills)) missing_soft_skills = list(set(jd_soft_skills) - set(resume_soft_skills)) recommendations = [] if missing_tech_skills: recommendations.append(f"Consider acquiring these technical skills: {', '.join(missing_tech_skills)}") if missing_soft_skills: recommendations.append(f"Demonstrate these soft skills: {', '.join(missing_soft_skills)}") if tech_match_percent < 75: recommendations.append("Focus on gaining more relevant technical skills for this position") if soft_match_percent < 75: recommendations.append("Emphasize soft skills more in your resume") if overall_score >= 80: assessment = "Excellent match! Your profile strongly aligns with the job requirements." elif overall_score >= 65: assessment = "Good match! Your profile aligns well with most job requirements." elif overall_score >= 50: assessment = "Moderate match. Consider improving in the suggested areas." else: assessment = "Additional skill development recommended to better match the job requirements." return { "match_score": round(overall_score), "key_matches": [ f"Technical skills match: {tech_match_percent:.1f}%", f"Soft skills match: {soft_match_percent:.1f}%", f"Matched technical skills: {', '.join(sorted(resume_tech_skills))}" if resume_tech_skills else "No technical skills found", f"Matched soft skills: {', '.join(sorted(resume_soft_skills))}" if resume_soft_skills else "No soft skills found" ], "gaps": [ f"Missing technical skills: {', '.join(sorted(missing_tech_skills))}" if missing_tech_skills else "No major technical skill gaps", f"Missing soft skills: {', '.join(sorted(missing_soft_skills))}" if missing_soft_skills else "No major soft skill gaps" ], "skill_analysis": { "technical_skills": { "present": sorted(resume_tech_skills), "missing": sorted(missing_tech_skills) }, "soft_skills": { "present": sorted(resume_soft_skills), "missing": sorted(missing_soft_skills) } }, "recommendations": recommendations if recommendations else ["Your profile shows strong alignment with the job requirements"], "overall_assessment": f"{assessment} Overall match: {round(overall_score)}%, " f"with technical skills at {tech_match_percent:.1f}% " f"and soft skills at {soft_match_percent:.1f}%" } except Exception as e: st.error(f"Error in analysis: {str(e)}") return None def display_skill_tags(skills, style_class): """Display skills as colored tags""" if not skills: st.write("None") return tags_html = "" for skill in skills: tags_html += f'{skill}' st.markdown(tags_html, unsafe_allow_html=True) def main(): st.set_page_config(page_title="AI Resume Analyzer", page_icon="📄", layout="wide") set_custom_css() st.markdown('