| | import streamlit as st |
| | import pdfplumber |
| | import docx2txt |
| | import spacy |
| | from sklearn.feature_extraction.text import TfidfVectorizer |
| | from sklearn.metrics.pairwise import cosine_similarity |
| |
|
| |
|
| | |
| | @st.cache_resource |
| | def load_spacy_model(): |
| | return spacy.load('en_core_web_sm') |
| |
|
| | nlp = load_spacy_model() |
| |
|
| | |
| | def extract_text_from_pdf(pdf_file): |
| | text = '' |
| | with pdfplumber.open(pdf_file) as pdf: |
| | for page in pdf.pages: |
| | page_text = page.extract_text() |
| | if page_text: |
| | text += page_text |
| | return text |
| |
|
| | |
| | def extract_text_from_docx(docx_file): |
| | return docx2txt.process(docx_file) |
| |
|
| | |
| | def extract_skills(text, user_skills): |
| | text = text.lower() |
| | extracted = [skill.strip().lower() for skill in user_skills if skill.strip().lower() in text] |
| | return list(set(extracted)) |
| |
|
| | |
| | def extract_experience(text): |
| | doc = nlp(text) |
| | years = [] |
| | for ent in doc.ents: |
| | if ent.label_ == 'DATE': |
| | try: |
| | if 'year' in ent.text.lower(): |
| | num = int(ent.text.split()[0]) |
| | years.append(num) |
| | except: |
| | continue |
| | return max(years, default=0) |
| |
|
| | |
| | def match_score(resume_text, job_description): |
| | documents = [resume_text, job_description] |
| | tfidf = TfidfVectorizer(stop_words='english') |
| | tfidf_matrix = tfidf.fit_transform(documents) |
| | score = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2]) |
| | return round(float(score[0][0]) * 100, 2) |
| |
|
| | |
| |
|
| | st.title("π AI Resume Screening App") |
| |
|
| | |
| | job_description = st.text_area("π Paste the Job Description Below:", height=200) |
| |
|
| | |
| | skills_input = st.text_input("π οΈ Enter Required Skills (comma-separated):", placeholder="e.g., Python, SQL, Machine Learning") |
| |
|
| | |
| | uploaded_files = st.file_uploader("π Upload Resume Files (PDF/DOCX)", type=['pdf', 'docx'], accept_multiple_files=True) |
| |
|
| | |
| | if uploaded_files and job_description and skills_input: |
| | |
| | user_skills = [skill.strip() for skill in skills_input.split(',') if skill.strip()] |
| | |
| | if not user_skills: |
| | st.warning("β οΈ Please enter at least one skill.") |
| | else: |
| | st.markdown("### π Screening Results") |
| |
|
| | for resume in uploaded_files: |
| | |
| | if resume.name.endswith('.pdf'): |
| | resume_text = extract_text_from_pdf(resume) |
| | elif resume.name.endswith('.docx'): |
| | resume_text = extract_text_from_docx(resume) |
| | else: |
| | st.warning(f"Unsupported file type: {resume.name}") |
| | continue |
| |
|
| | |
| | skills = extract_skills(resume_text, user_skills) |
| | experience = extract_experience(resume_text) |
| | score = match_score(resume_text, job_description) |
| |
|
| | |
| | st.subheader(f"π€ Candidate: {resume.name}") |
| | st.write(f"β
**Skills Matched**: {', '.join(skills) if skills else 'None'}") |
| | st.write(f"π§ **Estimated Experience**: {experience} year(s)") |
| | st.write(f"π **Match Score**: {score}%") |
| | st.markdown("---") |