Spaces:
Running
Running
Upload 2 files
Browse files- app.py +87 -0
- reruirements.txt +4 -0
app.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import pdfplumber
|
| 3 |
+
import torch
|
| 4 |
+
from transformers import AutoModelForQuestionAnswering, AutoTokenizer, pipeline
|
| 5 |
+
|
| 6 |
+
# Load Hugging Face model
|
| 7 |
+
model_name = "deepset/roberta-base-squad2"
|
| 8 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 9 |
+
model = AutoModelForQuestionAnswering.from_pretrained(model_name)
|
| 10 |
+
qa_pipeline = pipeline(
|
| 11 |
+
"question-answering",
|
| 12 |
+
model=model,
|
| 13 |
+
tokenizer=tokenizer,
|
| 14 |
+
truncation=True,
|
| 15 |
+
max_length=1024
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
# Function to extract text from PDF
|
| 19 |
+
def extract_text_from_pdf(pdf_file):
|
| 20 |
+
with pdfplumber.open(pdf_file) as pdf:
|
| 21 |
+
text = "\n".join([page.extract_text() for page in pdf.pages if page.extract_text()])
|
| 22 |
+
return text if text.strip() else "No text found in the document."
|
| 23 |
+
|
| 24 |
+
# Function to extract information using LLM
|
| 25 |
+
def extract_info(text, question):
|
| 26 |
+
if not text or len(text.strip()) < 50:
|
| 27 |
+
return "Insufficient text for analysis."
|
| 28 |
+
if not question or len(question.strip()) == 0:
|
| 29 |
+
return "No valid question provided."
|
| 30 |
+
|
| 31 |
+
try:
|
| 32 |
+
result = qa_pipeline({
|
| 33 |
+
"context": text[:1024],
|
| 34 |
+
"question": question
|
| 35 |
+
})
|
| 36 |
+
return result.get("answer", "No relevant information found.")
|
| 37 |
+
except Exception as e:
|
| 38 |
+
return f"Error processing request: {str(e)}"
|
| 39 |
+
|
| 40 |
+
# Function to analyze resume vs job description
|
| 41 |
+
def analyze_resume_vs_job(resume_text, job_desc):
|
| 42 |
+
job_keywords = set(job_desc.lower().split()) # Extract keywords from JD
|
| 43 |
+
resume_keywords = set(resume_text.lower().split()) # Extract keywords from resume
|
| 44 |
+
|
| 45 |
+
matched_skills = job_keywords.intersection(resume_keywords) # Common words
|
| 46 |
+
missing_skills = job_keywords.difference(resume_keywords) # Missing words
|
| 47 |
+
|
| 48 |
+
return matched_skills, missing_skills
|
| 49 |
+
|
| 50 |
+
# Streamlit UI
|
| 51 |
+
st.title("π AI-Powered ATS Resume Parser")
|
| 52 |
+
st.write("Upload a resume to extract key details automatically!")
|
| 53 |
+
|
| 54 |
+
uploaded_file = st.file_uploader("Upload Resume (PDF or TXT)", type=["pdf", "txt"])
|
| 55 |
+
|
| 56 |
+
if uploaded_file is not None:
|
| 57 |
+
file_extension = uploaded_file.name.split(".")[-1]
|
| 58 |
+
if file_extension == "pdf":
|
| 59 |
+
resume_text = extract_text_from_pdf(uploaded_file)
|
| 60 |
+
else:
|
| 61 |
+
resume_text = uploaded_file.read().decode("utf-8")
|
| 62 |
+
|
| 63 |
+
st.subheader("π Extracted Resume Information")
|
| 64 |
+
name = extract_info(resume_text, "What is the applicant's name?")
|
| 65 |
+
job_title = extract_info(resume_text, "What is the applicant's job title?")
|
| 66 |
+
skills = extract_info(resume_text, "What are the applicant's skills?")
|
| 67 |
+
experience = extract_info(resume_text, "How many years of experience does the applicant have?")
|
| 68 |
+
|
| 69 |
+
st.write(f"**π§ Name:** {name}")
|
| 70 |
+
st.write(f"**πΌ Job Title:** {job_title}")
|
| 71 |
+
st.write(f"**π Skills:** {skills}")
|
| 72 |
+
st.write(f"**π
Experience:** {experience} years")
|
| 73 |
+
|
| 74 |
+
# Job Matching (Enhanced)
|
| 75 |
+
st.subheader("π Match Resume with Job Description")
|
| 76 |
+
job_desc = st.text_area("Paste the Job Description Here:")
|
| 77 |
+
|
| 78 |
+
if st.button("Match Resume"):
|
| 79 |
+
if not job_desc.strip():
|
| 80 |
+
st.warning("β οΈ Please enter a Job Description before matching.")
|
| 81 |
+
else:
|
| 82 |
+
match_score = extract_info(resume_text, f"How well does this resume match the job description: {job_desc}")
|
| 83 |
+
matched_skills, missing_skills = analyze_resume_vs_job(resume_text, job_desc)
|
| 84 |
+
|
| 85 |
+
st.write(f"**β
Match Score:** {match_score}")
|
| 86 |
+
st.write(f"**β Matched Skills:** {', '.join(matched_skills) if matched_skills else 'None'}")
|
| 87 |
+
st.write(f"**β Missing Skills:** {', '.join(missing_skills) if missing_skills else 'None'}")
|
reruirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit
|
| 2 |
+
transformers
|
| 3 |
+
torch
|
| 4 |
+
pdfplumber
|