File size: 11,954 Bytes
cc6dcbe
bbd5462
1ab43b3
cc6dcbe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bbd5462
cc6dcbe
 
 
 
 
 
 
 
 
 
 
 
 
bbd5462
cc6dcbe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bbd5462
cc6dcbe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bbd5462
cc6dcbe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
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 copytoclipboard():
     if st.button("Copy to Clipboard"):
            pyperclip.copy(st.session_state.analysis)
            st.success("Cover letter copied to clipboard!")

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("Job Hiring 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)

        #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
                        response = 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_
                    response = 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'])
                    # 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()