datasciencedojo's picture
Update app.py
6698479 verified
import streamlit as st
from utils.utils import *
from agents import prompts
import pyperclip
from dotenv import load_dotenv
import pandas as pd
import hashlib
load_dotenv()
def hash_inputs(resume_text, job_title, must_have, job_pref):
# Generate a hash based on the inputs
input_str = resume_text + job_title + must_have + job_pref
return hashlib.md5(input_str.encode()).hexdigest()
def hash_sel_inputs(resume_text, job_title, must_have, job_pref):
# Generate a hash based on the inputs
input_str = str(resume_text) + job_title + must_have + job_pref
return hashlib.md5(input_str.encode()).hexdigest()
def table_resp(lists):
d={}
sc=[[],[],[],[],[],[],[]]
for i in lists:
sc[0].append(i['candidate_name'])
sc[1].append(str(i['overall_match_score'])+'%')
sc[2].append(str(i['skills_keywords_score'])+'%')
sc[3].append(str(i['experience_score'])+'%')
sc[4].append(str(i['education_certifications_score'])+'%')
sc[5].append(str(i['preferred_qualifications_score'])+'%')
sc[6].append(i['score_interpretation'])
cols=['Candidate Name','Match Score','Skills & Keywords (40%)','Experience & Responsibilities (30%)','Education & Certifications (20%)','Preferred Qualifications (10%)','Score Interpretation']
for i in range(len(sc)):
d[cols[i]]=sc[i]
df = pd.DataFrame(d)
return df
def table_resp_exp(lists):
d={}
sc=[[],[],[],[],[],[],[]]
for i in lists:
sc[0].append(i['candidate_name'])
sc[1].append(i['overall_match_score'])
sc[2].append('('+str(i['skills_keywords_score'])+' out of 40) '+i['skills_keywords_explanation'])
sc[3].append('('+str(i['experience_score'])+' out of 30) '+i['experience_explanation'])
sc[4].append('('+str(i['education_certifications_score'])+' out of 20) '+i['education_certifications_explanation'])
sc[5].append('('+str(i['preferred_qualifications_score'])+' out of 10) '+i['preferred_qualifications_explanation'])
sc[6].append(i['score_interpretation'])
cols=['Candidate Name','Match Score','Skills & Keywords (40%)','Experience & Responsibilities (30%)','Education & Certifications (20%)','Preferred Qualifications (10%)','Score Interpretation']
for i in range(len(sc)):
d[cols[i]]=sc[i]
df = pd.DataFrame(d)
return df
def expand(ext_res):
formatted_resp=f"""
**Candidate:** {ext_res['candidate_name']}
**Match Score**: {ext_res['overall_match_score']}%
**Skills & Keywords** ({ext_res['skills_keywords_score']}% out of 40%):
{ext_res['skills_keywords_explanation']}
**Experience & Responsibilities** ({ext_res['experience_score']}% out of 30%):
{ext_res['experience_explanation']}
**Education & Certifications** ({ext_res['education_certifications_score']}% out of 20%):
{ext_res['education_certifications_explanation']}
**Preferred Qualifications** ({ext_res['preferred_qualifications_score']}% out of 10%):
{ext_res['preferred_qualifications_explanation']}
**Score Interpretation**: {ext_res['score_interpretation']}
"""
return formatted_resp
def concise_resp(ext_res):
formatted_resp=f"""
**Candidate:** {ext_res['candidate_name']}
**Match Score**: {ext_res['overall_match_score']}%
**Skills & Keywords**: {ext_res['skills_keywords_score']}% out of 40%
**Experience**: {ext_res['experience_score']}% out of 30%
**Education & Certifications**: {ext_res['education_certifications_score']}% out of 20%
**Preferred Qualifications**: {ext_res['preferred_qualifications_score']}% out of 10%
**Score Interpretation**: {ext_res['score_interpretation']}
"""
return formatted_resp
def filecheck(resume_file):
if len(resume_file)==1 and resume_file is not None:
resume_text = parse_resume(resume_file[0])
return resume_text
def filecheck_error(resume_file):
if len(resume_file)==0:
st.warning("Please upload a Resume.")
else:
st.warning("Please upload only one Resume.")
def filescheck(resume_file):
if len(resume_file)>1 and resume_file is not None:
resume_text = parse_resumes(resume_file)
return resume_text
def filescheck_error(resume_file):
if len(resume_file)==0:
st.warning("Please upload Resumes.")
else:
st.warning("Please upload more than 1 Resume for selection.")
def main():
if 'analysis' not in st.session_state:
st.session_state.analysis = None
if 'jobadv' not in st.session_state:
st.session_state.jobadv = None
if 'analysis_mc' not in st.session_state:
st.session_state.analysis_mc = None
if 'analysis' not in st.session_state:
st.session_state.analysis = None
if 'input_hash' not in st.session_state:
st.session_state.input_hash = None
if 'analysis_mc_s' not in st.session_state:
st.session_state.analysis_mc_s = None
if 'analysis_s' not in st.session_state:
st.session_state.analysis_s = None
if 'input_hash_sel' not in st.session_state:
st.session_state.input_hash_sel = None
if 'analysis_mc_s_exp' not in st.session_state:
st.session_state.analysis_mc_s_exp = None
st.title("SmartHire-Assistant")
# Select Task
st.sidebar.header("Select Task")
selection = st.sidebar.radio("Select option", ("Generate Job Adverstisment", "Resume Analysis","Resume Selection"))
# Generate Cover Letter
if selection == "Generate Job Adverstisment":
st.header("Job Details")
st.subheader('Job Title')
job_title_text = st.text_input("Enter job title here",max_chars=30)
st.subheader('Job Requirement')
job_requirement = st.text_area("Enter job requirement here")
if st.button("Generate Job Adverstisment"):
if job_requirement is not None:
prompt_template = prompts.prompt_template_classic
jobadv = generate_adv(job_requirement,job_title_text, prompt_template)
st.subheader("Job Adverstisment:")
st.markdown(jobadv)
st.session_state.jobadv = jobadv
#copytoclipboard()
else:
st.warning("Please provide a job requirement.")
else:
st.sidebar.header("Resume Analysis Criteria")
scoretext='''**80-100**: Good match
**50-79**: Medium match
**0-49**: Poor match '''
criteriatext='''**40%**: Skills and Keywords
**30%**: Experience & Responsibilities
**20%**: Education & Certifications
**10%**: Preferred Qualifications '''
#st.session_state.dropdown_open= False # Close the dropdown on click
#Match Score Range
# st.sidebar.button("Match Score Range",icon=":material/arrow_drop_down:")
#st.session_state.dropdown_open= False
#st.sidebar.button("Match Score Range",icon=":material/arrow_drop_up:")
st.sidebar.subheader("Match Score Range")
scorecontainer=st.sidebar.container(height=130)
scorecontainer.markdown(scoretext)
#Criteria weight
st.sidebar.subheader("Criteria weight")
criteriacontainer=st.sidebar.container(height=130)
criteriacontainer.markdown(criteriatext)
st.subheader("Upload Resume")
resume_file = st.file_uploader("Choose a file or drag and drop", type=["pdf"],accept_multiple_files=True)
if resume_file:
# Calculate a hash of the new file selection
new_file_hash = hash_inputs(str(resume_file), '', '', '')
if 'last_file_hash' not in st.session_state or st.session_state.last_file_hash != new_file_hash:
# Clear cached responses because a new file is uploaded
st.session_state.analysis = None
st.session_state.analysis_mc = None
st.session_state.input_hash = None
st.session_state.analysis_s = None
st.session_state.input_hash_sel = None
st.session_state.analysis_mc_s = None
st.session_state.analysis_mc_s_exp = None
# Update last file hash
st.session_state.last_file_hash = new_file_hash
#st.header("Job Details")
st.subheader('Job Title')
job_title_text = st.text_input("Enter job title here", "",max_chars=30)
st.subheader('Job Requirements')
must_have = st.text_area("Enter job must-have requirements here", "")
st.subheader('Preferred Qualification')
job_pref = st.text_area("Enter any preferred skills or qualifications here", "")
resume_text = None
if selection == "Resume Analysis":
btn1=st.button("Generate Resume Analysis")
if btn1:
#Only show Scores
#if st.button("Match Score"):
resume_text=filecheck(resume_file)
if resume_text is not None:
if job_pref is not None and must_have is not None :
current_input_hash = hash_inputs(resume_text, job_title_text, must_have, job_pref)
# Check if the inputs have changed
if st.session_state.input_hash != current_input_hash:
# Inputs have changed, generate new analysis
st.session_state.input_hash = current_input_hash
#prompt_template = prompts.prompt_template_modern
prompt_template = prompts.prompt_template_new
response = generate_analysis_new(resume_text, job_pref, job_title_text, must_have, prompt_template)
#generate_analysis(resume_text, job_pref, job_title_text, must_have, prompt_template)
# Cache the result
st.session_state.analysis = expand(response)
st.session_state.analysis_mc = concise_resp(response)
# Display the cached response based on the button clicked
# Match Score button clicked
st.subheader("Resume Analysis (Match Score)")
st.markdown(st.session_state.analysis_mc)
with st.expander("Detailed Analysis"):
st.markdown(st.session_state.analysis)
else:
st.warning("Please provide all job details.")
else:
filecheck_error(resume_file)
else:
btn1=st.button("Generate Match Score")
btn2=st.button("Generate Analysis")
if btn1 or btn2:
#Only show Scores
#if st.button("Match Score"):
resume_text=filescheck(resume_file)
if resume_text is not None:
if job_pref is not None and must_have is not None :
current_input_hash = hash_sel_inputs(resume_text, job_title_text, must_have, job_pref)
# Check if the inputs have changed
if st.session_state.input_hash_sel != current_input_hash:
# Inputs have changed, generate new analysis
st.session_state.input_hash_sel = current_input_hash
#prompt_template = prompts.prompt_template_resumes_
prompt_template = prompts.prompt_template_new
response = generate_individual_analysis(resume_text, job_pref, job_title_text, must_have, prompt_template)
#generate_sel_analysis(resume_text, job_pref, job_title_text, must_have, prompt_template)
print('response:',response)
#response_anal=max(response, key=lambda x: x['overall_match_score'])
## Prioritize by overall_match_score, then education_certifications_score, and finally skills_keywords_score
response_anal = max(
response,
key=lambda x: (
x.get('overall_match_score', 0),
x.get('education_certifications_score', 0), # Secondary criterion
x.get('skills_keywords_score', 0) # Tertiary criterion
)
)
# Cache the result
st.session_state.analysis_s = expand(response_anal)
st.session_state.analysis_mc_s = table_resp(response)
st.session_state.analysis_mc_s_exp = table_resp_exp(response)
# Display the cached response based on the button clicked
if btn1:
# Match Score button clicked
st.subheader("Match Scores")
st.dataframe(st.session_state.analysis_mc_s,hide_index=True)
elif btn2:
# Generate Analysis button clicked
print("expands")
st.subheader("Resume Analysis (Top Scored)")
# Candidate selection
st.markdown(st.session_state.analysis_s)
with st.expander("Detailed Analysis - All Candidates"):
st.dataframe(st.session_state.analysis_mc_s_exp,hide_index=True)
else:
st.warning("Please provide all job details.")
else:
filescheck_error(resume_file)
if __name__ == "__main__":
main()