Spaces:
Sleeping
Sleeping
File size: 6,188 Bytes
7548e1c b8e45d1 7548e1c b8e45d1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
import streamlit as st
import pdfplumber
import json
import os
import smtplib
from email.message import EmailMessage
from langchain_google_genai import GoogleGenerativeAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from dotenv import load_dotenv
import re
# Load environment variables
load_dotenv()
GOOGLE_API_KEY = os.getenv("GEMINI_API_KEY")
EMAIL_USER = os.getenv("EMAIL_USER")
EMAIL_PASS = os.getenv("EMAIL_PASS")
HR_EMAIL = os.getenv("HR_EMAIL") # HR Email Address
# Initialize LLM
llm = GoogleGenerativeAI(
model="gemini-1.5-flash",
google_api_key=GOOGLE_API_KEY,
temperature=0.7
)
# Extract text from PDF
def extract_text_from_pdf(uploaded_file):
with pdfplumber.open(uploaded_file) as pdf:
text = "\n".join([page.extract_text() for page in pdf.pages if page.extract_text()])
return text
# Prompt for Resume Screening
prompt = PromptTemplate(
input_variables=["resume_text", "job_description"],
template="""
You are an expert resume screener. Extract key details from the following resume text:
Resume:
{resume_text}
Compare it with the given job description:
{job_description}
Provide a structured JSON response with skills, experience, education, score, and missing skills.
"""
)
# Resume Screening Chain
resume_screener_chain = LLMChain(llm=llm, prompt=prompt)
def calculate_similarity(resume_text, job_desc):
response = resume_screener_chain.invoke({"resume_text": resume_text, "job_description": job_desc})
response_text = response.get("text", "{}")
response_text = response_text.replace("```json", "").replace("```", "").strip()
try:
return json.loads(response_text)
except json.JSONDecodeError:
return {"score": 0, "missing_skills": []}
# Email Function (Updated with Debugging & Validation)
def is_valid_email(email):
return re.match(r"^[\w\.-]+@[\w\.-]+\.[a-zA-Z]{2,}$", email)
def send_email(to_email, subject, body, attachment=None, attachment_name=None):
if not is_valid_email(to_email):
print("β Invalid email format")
return False
msg = EmailMessage()
msg.set_content(body)
msg["Subject"] = subject
msg["From"] = EMAIL_USER
msg["To"] = to_email
if attachment and attachment_name:
msg.add_attachment(attachment, maintype='application', subtype='pdf', filename=attachment_name)
try:
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
server.login(EMAIL_USER, EMAIL_PASS)
server.send_message(msg)
return True
except Exception as e:
print(f"β Email Error: {e}")
return False
# Function to Notify HR
def notify_hr(candidate_name, resume_file):
hr_subject = f"π {candidate_name} shortlisted for Interview"
hr_body = f"The candidate {candidate_name} has been shortlisted for an interview. Please review their application."
resume_bytes = resume_file.getvalue()
notify_success = send_email(HR_EMAIL, hr_subject, hr_body, attachment=resume_bytes, attachment_name=f"{candidate_name}_Resume.pdf")
return notify_success
# Streamlit UI (Enhanced)
st.set_page_config(page_title="Resume Screening System", page_icon="π", layout="centered")
st.markdown(
"""
<style>
.main {
background-color: #f9f9f9;
}
.stButton>button {
background-color: #4CAF50;
color: white;
font-weight: bold;
border-radius: 8px;
padding: 10px 24px;
}
.stTextInput>div>div>input {
border-radius: 8px;
}
</style>
""", unsafe_allow_html=True
)
st.title("π Smart Resume Screening System")
st.markdown("Welcome! Upload your resume to see if you're a match for our job opening.")
st.markdown("---")
# Input Fields in Columns
col1, col2 = st.columns(2)
with col1:
name = st.text_input("π€ Candidate Name")
with col2:
email = st.text_input("π§ Candidate Email")
resume_file = st.file_uploader("π Upload Your Resume (PDF Only)", type=["pdf"])
st.markdown("---")
if st.button("π Submit for Screening"):
if name and email and resume_file:
st.info("β³ Screening your resume... please wait.")
resume_text = extract_text_from_pdf(resume_file)
job_description = "Looking for a Python Developer with AI expertise."
response_data = calculate_similarity(resume_text, job_description)
match_score = response_data.get("score", 0)
missing_skills = response_data.get("missing_skills", [])
st.markdown("### π Screening Result")
st.progress(int(match_score))
st.write(f"**Match Score:** `{match_score}`")
st.write(f"**Missing Skills:** {', '.join(missing_skills) if missing_skills else 'β
None'}")
if match_score > 80:
decision = "π Congratulations! You have been shortlisted for an interview."
subject = "Interview Invitation"
notify_hr(name, resume_file)
elif 50 <= match_score <= 79:
decision = "β
You have been shortlisted for future opportunities."
subject = "Shortlist Notification"
else:
decision = "β Thank you for applying. Weβve decided to move forward with other candidates."
subject = "Rejection Email"
# AI Feedback
feedback_prompt = f"Suggest skills to improve for this candidate based on missing skills: {missing_skills}"
feedback_response = llm.invoke(feedback_prompt)
feedback = feedback_response.get("text", "No feedback available.") if isinstance(feedback_response, dict) else feedback_response
decision += f"\n\nπ§ **AI Feedback:**\n{feedback}"
st.markdown("---")
st.markdown(f"### βοΈ Decision Email Content")
st.success(decision)
if send_email(email, subject, decision):
st.success(f"π§ Email successfully sent to `{email}`")
else:
st.error("β Failed to send email. Please check your credentials and try again.")
else:
st.warning("β οΈ Please fill in all the fields and upload your resume.")
|