EnigmaOfTheWorld commited on
Commit
a101471
·
1 Parent(s): 5c6c5b0

Upload 7 files

Browse files
Files changed (7) hide show
  1. app.py +34 -0
  2. application_dev.db +0 -0
  3. llm.py +68 -0
  4. models.py +86 -0
  5. pages/Careers.py +259 -0
  6. pages/Employee.py +324 -0
  7. requirements.txt +6 -0
app.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from sqlalchemy.orm import Session
3
+ from sqlalchemy import select
4
+
5
+ from models import Job, ENGINE
6
+
7
+
8
+ def post_jobs() -> None:
9
+ with Session(ENGINE) as session:
10
+ stmt = select(Job)
11
+ jobs = session.scalars(stmt).all()
12
+ if jobs:
13
+ st.markdown("""<h1 style="font-family: Garamond;text-indent: 20px;color:#008DFE;">Submit your job applications today!</h1>""",unsafe_allow_html=True)
14
+ st.caption(f"""<p style="color:red;">Create your profile and start applying for jobs today. We eagerly anticipate the opportunity to collaborate with you!<p>""",unsafe_allow_html=True)
15
+ else:
16
+ st.caption(f"""<p style="color:red;">There are currently no available job vacancies. Please check back later. We are eagerly anticipating the opportunity to begin working together.<p>""",unsafe_allow_html=True)
17
+
18
+ for job in jobs:
19
+ with st.expander(f"{job.job_id}: {job.post_name}"):
20
+ st.markdown(f"""<p style="font-family:'Garamond'"><b>Description</b>:
21
+ <br>{job.description}<br><br>
22
+ <b>Experience</b>:
23
+ <br>{job.min_experience} - {job.max_experience} year(s)<br><br>
24
+ <b>Responsibilities</b>:
25
+ <br>{job.responsibilities}<br><br>
26
+ <b>Primary Skills</b>:<br>
27
+ {job.primary_skills}</p>""",unsafe_allow_html=True)
28
+ if job.secondary_skills:
29
+ st.markdown(f"""<p style="font-family:'Garamond'"><b>Secondary Skills</b>:
30
+ <br>{job.secondary_skills}</p>""",unsafe_allow_html=True)
31
+ st.markdown(f"""<p style="font-family:'Garamond'"><b>Apply before</b>:
32
+ <br>{job.expires_at}</p>""",unsafe_allow_html=True)
33
+
34
+ post_jobs()
application_dev.db ADDED
Binary file (41 kB). View file
 
llm.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pathlib
2
+ import ast
3
+ import os
4
+ from pypdf import PdfReader
5
+ import docx2txt
6
+ from sqlalchemy import select
7
+ from sqlalchemy.orm import Session
8
+ import openai
9
+ import cohere
10
+ from models import Job, ENGINE
11
+ openai.api_key = os.environ["OPEN_API_KEY"]
12
+ co = cohere.Client(os.environ["COHERE_API_KEY"])
13
+ def gpt(user_query):
14
+ response = openai.Completion.create(
15
+ engine="text-davinci-003",
16
+ prompt = user_query,
17
+ max_tokens=1024,
18
+ n=1,
19
+ stop=None,
20
+ temperature=0.5,
21
+ )
22
+ return response['choices'][0]['text']
23
+
24
+
25
+ def parse_pdf(file_name):
26
+ reader = PdfReader(file_name)
27
+ page = reader.pages[0]
28
+ resume_text = page.extract_text()
29
+
30
+
31
+
32
+ return resume_text
33
+
34
+
35
+ def parse_docx(file_name):
36
+ file_text = docx2txt.process(file_name)
37
+ return file_text
38
+
39
+ # def get_dict(resume_text):
40
+ # resume_dict = ast.literal_eval(gpt(f"""parse the resume and convert it into a Python string with the headings as "experience," "skills," "certifications," and "education".
41
+
42
+ # resume: "{resume_text}"
43
+ # resume_dict: """).strip())
44
+ # return resume_dict
45
+
46
+ def parse(filename):
47
+ resume_file = pathlib.Path(filename)
48
+ text = parse_pdf(resume_file) if resume_file.suffix == ".pdf" else parse_docx(resume_file)
49
+ print("parse"+"~"*10,text)
50
+ # dct = get_dict(text)
51
+ # print(dct)
52
+ return text
53
+
54
+ def rerank(job_id,docs,top_n):
55
+ with Session(ENGINE) as session:
56
+ stmt = select(Job).where(Job.job_id == job_id)
57
+ job = session.scalars(stmt).one()
58
+
59
+ post = job.post_name
60
+
61
+ response = co.rerank(
62
+ model = 'rerank-english-v2.0',
63
+ query = f'Which profile suits most for the role of {post}?',
64
+ documents = docs,
65
+ top_n = top_n,
66
+ )
67
+ print(response)
68
+ return response
models.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List
2
+ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
3
+ from sqlalchemy import ForeignKey, create_engine
4
+
5
+
6
+ ENGINE = create_engine('sqlite:///application_dev.db')
7
+
8
+ class Base(DeclarativeBase):
9
+ pass
10
+
11
+ class Employee(Base):
12
+ __tablename__ = 'employees'
13
+ employee_id: Mapped[str] = mapped_column(primary_key = True)
14
+ email_id: Mapped[str] = mapped_column(unique = True,nullable = False)
15
+ first_name: Mapped[str] = mapped_column(nullable = True)
16
+ last_name: Mapped[str] = mapped_column(nullable = True)
17
+ password: Mapped[str]
18
+ department: Mapped[str]
19
+ # jobs_posted: Mapped[list["Job"]] = relationship(back_populates="jobs")
20
+
21
+ def __repr__(self):
22
+ return f'Employee({self.employee_id!r},{self.email_id!r},{self.first_name!r},{self.department!r})'
23
+
24
+ @property
25
+ def full_name(self):
26
+ return f'{self.first_name.title()} {self.last_name.title()}'
27
+
28
+
29
+ class Job(Base):
30
+ __tablename__ = 'jobs'
31
+ job_id :Mapped[str] = mapped_column(primary_key = True)
32
+ employee_id :Mapped[str] #= mapped_column(ForeignKey('employees.employee_id'))
33
+ post_name: Mapped[str] = mapped_column(nullable = False)
34
+ description: Mapped[str] = mapped_column(nullable= False)
35
+ responsibilities: Mapped[str]
36
+ min_experience: Mapped[int] = mapped_column(nullable = False)
37
+ max_experience: Mapped[int] = mapped_column(nullable = False)
38
+ primary_skills: Mapped[str] = mapped_column(nullable = False)
39
+ secondary_skills: Mapped[str] = mapped_column(nullable = True)
40
+ vacancies: Mapped[int] = mapped_column(nullable=False)
41
+ # employee: Mapped["Employee"] = relationship(back_populates="employee")
42
+ # users_applied: Mapped[list["User"]] = relationship(back_populates="users")
43
+ created_at: Mapped[str] = mapped_column(nullable=False)
44
+ expires_at: Mapped[str] = mapped_column(nullable = False)
45
+
46
+ def __repr__(self):
47
+ return f"Job({self.job_id!r},{self.post_name!r},{self.min_experience},{self.max_experience})"
48
+
49
+
50
+ class User(Base):
51
+ __tablename__ = "users"
52
+ email_id: Mapped[str] = mapped_column(primary_key=True)
53
+ password: Mapped[str] = mapped_column(nullable=False)
54
+ first_name: Mapped[str] = mapped_column(nullable = False)
55
+ last_name: Mapped[str] = mapped_column(nullable = False)
56
+
57
+ def __repr__(self):
58
+ return f'User({self.email_id!r},{self.first_name!r},{self.last_name!r})'
59
+
60
+ @property
61
+ def full_name(self):
62
+ return f'{self.first_name.title()} {self.last_name.title()}'
63
+
64
+
65
+
66
+ class JobsApplied(Base):
67
+ __tablename__ = 'jobs_applied'
68
+ email_id: Mapped[str] = mapped_column(primary_key=True)
69
+ job_id: Mapped[str] = mapped_column(ForeignKey('jobs.job_id'))
70
+ rank: Mapped[int] = mapped_column(nullable=False)
71
+ experience: Mapped[int] = mapped_column(nullable=False)
72
+ round_number: Mapped[int] = mapped_column(nullable=False)
73
+ primary_skills: Mapped[int]
74
+ secondary_skills: Mapped[int]
75
+
76
+
77
+ def __repr__(self):
78
+ return f'JobsApplied({self.email_id!r},{self.job_id!r},{self.rank},{self.experience},{self.round_number})'
79
+
80
+
81
+
82
+
83
+ def __create_tables():
84
+ Base.metadata.create_all(bind = ENGINE)
85
+
86
+
pages/Careers.py ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pathlib
2
+ import re
3
+ from typing import Union
4
+ import os
5
+ import ast
6
+
7
+ import streamlit as st
8
+ import sqlalchemy
9
+ from sqlalchemy.orm import Session
10
+ from sqlalchemy import select
11
+ import openai
12
+
13
+ from models import User, Job, JobsApplied, ENGINE
14
+ from llm import gpt
15
+
16
+ openai.api_key = os.environ['OPEN_API_KEY']
17
+ def clear_cache():
18
+ for k in st.session_state:
19
+ del st.session_state[k]
20
+
21
+ def add_user_to_db():
22
+ col1, col2 = st.columns(2)
23
+ with col1:
24
+ first_name = st.text_input(label = "First Name", placeholder="First Name").title().strip()
25
+ with col2:
26
+ last_name = st.text_input(label = "Last Name", placeholder="last Name").title().strip()
27
+ email_id = st.text_input(label = "Email ID", placeholder = "Enter Email ID").strip()
28
+ new_password = st.text_input(label = "New Password",placeholder="New Password", type = "password").strip()
29
+ confirm_password = st.text_input(label = "Password",placeholder="New Password", type = "password").strip()
30
+ col1, col2, col3 = st.columns(3)
31
+ with col3:
32
+ if st.button("Back", key="Mistake"):
33
+ clear_cache()
34
+ with col1:
35
+
36
+ if st.button("Create Profile"):
37
+ if new_password != confirm_password:
38
+ st.error("Passwords do not match")
39
+ return
40
+
41
+ if not(first_name and last_name and email_id and new_password):
42
+ st.error("No text fields must be blank!")
43
+ return
44
+
45
+
46
+
47
+ if re.search('^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$',email_id) is None:
48
+ st.error("Invalid Email ID")
49
+ return
50
+
51
+ with Session(ENGINE) as session:
52
+ stmt = select(User).where(User.email_id == email_id)
53
+ result = session.scalars(stmt).one_or_none()
54
+ if result is not None:
55
+ st.error("User already exists!")
56
+ else:
57
+ user_object = User(email_id = email_id, password = new_password,
58
+ first_name = first_name, last_name = last_name)
59
+ session.add_all([user_object])
60
+ session.commit()
61
+ st.success("Successfully Created!")
62
+ clear_cache()
63
+ return
64
+
65
+
66
+
67
+
68
+
69
+
70
+ def login() -> None:
71
+
72
+ login_container = st.empty()
73
+ with login_container.container():
74
+ email_id = st.text_input(label=":email: Email ID", placeholder = "Email ID").lower().strip()
75
+ password = st.text_input(label = ":lock: Password", placeholder = "Password", type = "password")
76
+ col1, col2,col3,col4, = st.columns(4)
77
+ with col4:
78
+ if st.button("Sign Up"):
79
+ st.session_state['sign_up_clicked'] = True
80
+
81
+ with col1:
82
+ sign_in = st.button("Sign In")
83
+ if sign_in:
84
+
85
+ with Session(ENGINE) as session:
86
+ stmt = select(User).where(User.email_id == email_id).where(User.password == password)
87
+ user = session.scalars(stmt).one_or_none()
88
+ if user is None:
89
+ st.error("Invalid email ID/password")
90
+ else:
91
+ st.session_state['user_logged'] = True
92
+ st.session_state['user'] = user
93
+
94
+ if st.session_state['sign_up_clicked']:
95
+ login_container.empty()
96
+ add_user_to_db()
97
+ return
98
+
99
+
100
+ if st.session_state['user'] is not None:
101
+ login_container.empty()
102
+
103
+
104
+ def add_to_db(**job_applied):
105
+ with Session(ENGINE) as session:
106
+ obj = JobsApplied(**job_applied)
107
+ session.add_all([obj])
108
+
109
+ session.commit()
110
+
111
+ def apply_for_jobs():
112
+
113
+ with Session(ENGINE) as session:
114
+ stmt = select(Job)
115
+ jobs = session.scalars(stmt).all()
116
+ job_container = st.empty()
117
+ with job_container.container():
118
+ col1, col2 = st.columns(2)
119
+ with col1:
120
+ job_id = st.selectbox(label="Job ID", options = [job.job_id for job in jobs])
121
+ with col2:
122
+ post_name = st.text_input(label="Post",value = [job.post_name for job in jobs if job.job_id == job_id][-1], disabled=True)
123
+ experience = st.number_input(label = 'Expereince',min_value=0)
124
+ col1, col2 = st.columns(2)
125
+ with col1:
126
+ primary_skills = st.text_input(label="Primary Skills",placeholder="Primary Skills", help="Input your skills delimited by a comma").lower().strip()
127
+ with col2:
128
+ secondary_skills = st.text_input(label="Secondary Skills",placeholder="Secondary Skills", help="Input your skills delimited by a comma").lower().strip()
129
+
130
+ uploded_file = st.file_uploader(label = "Resume Upload", type = ["pdf","docx"])
131
+
132
+ col1, col2 = st.columns(2)
133
+ with col2:
134
+
135
+ if st.button("Apply"):
136
+ st.session_state['applied_for_job'] = True
137
+
138
+ if st.session_state['applied_for_job']:
139
+ if uploded_file is None:
140
+ st.error("No Resume Uploaded")
141
+ return False
142
+
143
+ with Session(ENGINE) as session:
144
+ stmt = select(JobsApplied).where(JobsApplied.email_id == st.session_state['user'].email_id)
145
+ res = session.scalars(stmt).one_or_none()
146
+ if res is not None:
147
+ st.info("You have already applied for job")
148
+ return False
149
+ stmt = select(Job).where(Job.job_id == job_id)
150
+ selected_job = session.scalars(stmt).one()
151
+
152
+ if st.session_state['applied_for_job'] and not(selected_job.min_experience <= experience <= selected_job.max_experience):
153
+ return False
154
+
155
+
156
+ resumes_dir = pathlib.Path(f'resumes/{job_id}')
157
+ resumes_dir.mkdir(exist_ok = True)
158
+ resume = resumes_dir / f"{st.session_state['user'].email_id} - {st.session_state['user'].full_name}"
159
+ resume.touch()
160
+ resume.write_bytes(uploded_file.read())
161
+
162
+
163
+ add_to_db(**{"email_id": st.session_state["user"].email_id,
164
+ "job_id": job_id, 'experience': experience,
165
+ 'primary_skills': primary_skills,
166
+ 'secondary_skills':secondary_skills,
167
+ 'round_number': 0, 'rank': -1})
168
+ return True
169
+
170
+
171
+
172
+ def jobs_applied():
173
+ with Session(ENGINE) as session:
174
+ stmt = select(JobsApplied).where(JobsApplied.email_id == st.session_state['user'].email_id)
175
+ jobs_applied = session.scalars(stmt).all()
176
+
177
+ if jobs_applied:
178
+ for job_applied in jobs_applied:
179
+ with st.expander(f'Job ID: {job_applied.job_id} Round Number: {job_applied.round_number}'):
180
+ if job_applied.round_number > 0:
181
+ temporary = st.empty()
182
+ with temporary.container():
183
+ get_interview_questions(job_applied.job_id)
184
+ temporary.empty()
185
+ st.markdown(f'<p style="font-family:Garamond">You will be notified about the result</p>',unsafe_allow_html=True)
186
+
187
+ if not(st.session_state['rank']) >= 7:
188
+ with Session(ENGINE) as session:
189
+ session.delete(job_applied)
190
+
191
+
192
+
193
+
194
+
195
+
196
+ def get_interview_questions(job_id):
197
+ with Session(ENGINE) as session:
198
+ stmt = select(Job).where(Job.job_id == job_id.strip())
199
+ job = session.scalars(stmt).one_or_none()
200
+
201
+ if job is not None:
202
+ lst = gpt(f"Generate a set of 10 multiple-choice questions (MCQs) based on the subject of {job.post_name} with experience between {job.min_experience} - {job.max_experience} years.Return it as a list of dictionaries with question as key and optionaand correct answer as kets")
203
+ st.write(f"{lst!r}")
204
+ mcqs = ast.literal_eval(lst.strip())
205
+ rank = 0
206
+ for index, mcq in enumerate(mcqs,start=1):
207
+ question = mcq["question"] if 'question' in mcq.keys() else mcq["Question"]
208
+ options = mcq["options"] if 'options' in mcq.keys() else mcq["Options"]
209
+ correct_answer = mcq["correct_answer"] if 'correct_answer' in mcq.keys() else mcq["Correct Answer"]
210
+ answer = st.radio(f'Q{index} {question}',key=mcq,options=answer)
211
+ if answer.strip() == correct_answer.strip():
212
+ rank += 1
213
+ if st.button('Submit'):
214
+ st.session_state['rank'] = rank
215
+ return st.session_state['rank']
216
+
217
+
218
+
219
+
220
+
221
+
222
+
223
+
224
+
225
+
226
+
227
+
228
+
229
+
230
+
231
+
232
+
233
+
234
+
235
+
236
+ if 'sign_up_clicked' not in st.session_state:
237
+ st.session_state['sign_up_clicked'] = False
238
+ if 'user_logged' not in st.session_state:
239
+ st.session_state['user_logged'] = False
240
+ if 'user' not in st.session_state:
241
+ st.session_state['user'] = None
242
+ if 'applied_for_job' not in st.session_state:
243
+ st.session_state['applied_for_job'] = False
244
+
245
+ if 'rank' not in st.session_state:
246
+ st.session_state['rank'] = False
247
+
248
+
249
+
250
+ login()
251
+ if st.session_state['user_logged']:
252
+ col1, col2 = st.columns(2)
253
+ with col2:
254
+ st.button('Log Out',on_click=clear_cache)
255
+ tab1, tab2= st.tabs(["Apply Jobs","Place Holder"])
256
+ with tab1:
257
+ apply_for_jobs()
258
+ with tab2:
259
+ jobs_applied()
pages/Employee.py ADDED
@@ -0,0 +1,324 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import random
3
+ from datetime import datetime, timedelta
4
+ from typing import Union
5
+ import pathlib
6
+ import smtplib
7
+ from email.message import EmailMessage
8
+ import streamlit as st
9
+ from sqlalchemy.orm import Session
10
+ from sqlalchemy import select
11
+
12
+ from models import Employee, Job , JobsApplied,User, ENGINE
13
+ from llm import parse, rerank
14
+
15
+
16
+
17
+ st.markdown("""-
18
+ <style>
19
+
20
+ .stButton > button{
21
+ border: black;
22
+ box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19);
23
+ }
24
+ </style>""",unsafe_allow_html=True)
25
+
26
+ def clear_cache():
27
+ for k in st.session_state:
28
+ del st.session_state[k]
29
+
30
+ def login() -> Union[Employee,None]:
31
+ login_container = st.empty()
32
+ with login_container.container():
33
+ employee_id = st.text_input(label=":email: User ID", placeholder = "User ID").upper().strip()
34
+ password = st.text_input(label = ":lock: Password", placeholder = "Password", type = "password")
35
+ button = st.button('Login', type = "secondary")
36
+
37
+ if button:
38
+ if employee_id and password:
39
+ with Session(ENGINE) as session:
40
+ stmt = select(Employee).where(Employee.employee_id == employee_id).\
41
+ where(Employee.password == password)
42
+ employee = session.scalars(stmt).one_or_none()
43
+ print(employee)
44
+
45
+ if employee is None:
46
+ st.error('Invalid UserID/password')
47
+ return
48
+
49
+ st.session_state['employee_logged'] = True
50
+ st.session_state['employee'] = employee
51
+ login_container.empty()
52
+
53
+ return employee
54
+ else:
55
+ st.error('Empty UserID/Password')
56
+
57
+
58
+ def add_to_db(**job) -> None:
59
+
60
+ job_id = ''.join(chr(random.randint(65,90)) for i in range(5))+f'{random.randint(100,1000)}'
61
+ job['job_id'] = job_id
62
+ job['employee_id'] = st.session_state["employee"].employee_id
63
+ job['created_at'] = datetime.now().strftime("%d-%m-%Y %H:%M:%S")
64
+ job['primary_skills'] = ', '.join(job['primary_skills'])
65
+ job['secondary_skills'] = ', '.join(job['secondary_skills'])
66
+
67
+
68
+ with Session(ENGINE) as session:
69
+ job_object = Job(**job)
70
+ session.add_all([job_object])
71
+ session.commit()
72
+ st.success(f"Successfully posted job {job['post_name']}!")
73
+
74
+
75
+ def add_job() -> None:
76
+ post_name = st.text_input(label = 'Post Name').strip().title()
77
+ description = st.text_area(label = 'Job Description').strip()
78
+ responsibilities = st.text_area(label = "Responsibility").strip()
79
+ vacancies = st.number_input(label="Number Vacancies",min_value=1)
80
+ col1, col2 = st.columns(2)
81
+ with col1:
82
+ min_experience = st.number_input(label = "Minimum Experience",min_value = 0, )
83
+ with col2:
84
+ max_experience = st.number_input(label = "Maximum Experience",min_value = 1, )
85
+ number_of_primary_skills = st.number_input(label = "How many primary skills?",min_value = 1, )
86
+ primary_skills = [st.text_input(label = f'Primary Skill {i}',key=f'Primary Skill {i}').strip() for i in range(1,number_of_primary_skills+1)]
87
+ number_of_secondary_skills = st.number_input(label = "How many secondary skills?",min_value = 0, )
88
+ secondary_skills = [st.text_input(label = f'Secondary Skill {i}',key=f'Secondary Skill {i}').strip() for i in range(1,number_of_secondary_skills+1)]
89
+ st.markdown("Expires at")
90
+ col1, col2 = st.columns(2)
91
+ with col1:
92
+ expires_date = st.date_input(label = "expries date",value =datetime.now() + timedelta(days = 1), min_value = datetime.now() + timedelta(days = 1), max_value=None, label_visibility="collapsed")
93
+ print(expires_date )
94
+ with col2:
95
+ expires_time = st.time_input(label = "Time Input", label_visibility="collapsed")
96
+ print(expires_time)
97
+ expires_at = f'{expires_date.strftime("%d-%m-%Y")} {expires_time.strftime("%H:%M:%S")}'
98
+ st.markdown("<p style='color: red'>⚠️ Check before you submit once submitted you cannot make changes</p>", unsafe_allow_html=True)
99
+ if st.button("Post"):
100
+ if (post_name and description and responsibilities and primary_skills):
101
+ if min_experience <= max_experience:
102
+ job = {
103
+ "post_name" : post_name, 'description': description,'min_experience': min_experience,'max_experience': max_experience,
104
+ 'primary_skills': primary_skills, 'secondary_skills': secondary_skills,'responsibilities':responsibilities,
105
+ 'expires_at': expires_at, 'vacancies': vacancies
106
+
107
+ }
108
+
109
+
110
+ add_to_db(**job)
111
+ return True
112
+ st.error("Minimum Experience must be less than maximum experience")
113
+ return
114
+ st.error("Post Name/Description/Responsibility/Primary SKills are required")
115
+
116
+
117
+
118
+ def post_job():
119
+ st.session_state['employee']
120
+ st.session_state['employee_logged']
121
+ if st.session_state['employee_logged']:
122
+ col1, col2 = st.columns([0.001, 0.01])
123
+ with col2:
124
+ st.markdown(f'Would you like to include a job vacancy listing. {st.session_state["employee"].full_name}?')
125
+ with col1:
126
+ if st.button(':heavy_plus_sign:'):
127
+ st.session_state['add_job'] = True
128
+
129
+ if st.session_state['add_job']:
130
+ add_job_container = st.empty()
131
+ with add_job_container.container():
132
+ is_job_posted = add_job()
133
+ if is_job_posted:
134
+ add_job_container.empty()
135
+
136
+
137
+ def get_jobs_posted() -> None:
138
+ with Session(ENGINE) as session:
139
+ stmt = select(Job).where(Job.employee_id == st.session_state["employee"].employee_id)
140
+ jobs = session.scalars(stmt).all()
141
+ print(jobs)
142
+ for job in jobs:
143
+ with st.expander(f"{job.job_id}: {job.post_name} posted at: {job.created_at}"):
144
+ pass
145
+
146
+
147
+
148
+ def get_users_who_applied_for_jobs():
149
+
150
+ #Get Jobs Posted
151
+ with Session(ENGINE) as session:
152
+ stmt = select(Job).where(Job.employee_id == st.session_state["employee"].employee_id)
153
+ jobs = session.scalars(stmt).all()
154
+
155
+ if not jobs:
156
+ st.info("No jobs posted!")
157
+ return
158
+
159
+ job_id = st.selectbox("Filter by job_id",options=[job.job_id for job in jobs])
160
+
161
+
162
+
163
+ with Session(ENGINE) as session:
164
+ stmt = select(JobsApplied).where(JobsApplied.job_id == job_id)
165
+ users_applied_for_jobs = session.scalars(stmt).all()
166
+
167
+ if not users_applied_for_jobs:
168
+ st.info('No users have applied for job')
169
+ return False
170
+
171
+ re_rank_resumes_container = st.empty()
172
+ with re_rank_resumes_container.container():
173
+ st.markdown("""<p style="font-family:Garamond;text-indent: 45vh;font-size:25px">Jobs Application Details</p>""",unsafe_allow_html=True)
174
+ col1, col2 = st.columns([0.001, 0.01])
175
+ with col1:
176
+ round_number = users_applied_for_jobs[0].round_number
177
+ st.markdown(f"""<p style="font-size:20px"><span style = "font-family:Garamond;">Round</span><span style="font-family:monospace;padding: 10px 20px">{round_number}</span></p>""", unsafe_allow_html=True)
178
+ with col2:
179
+ num_docs = st.number_input(label="Top Resumes",min_value=1, max_value=len(users_applied_for_jobs))
180
+ for jobs_application in users_applied_for_jobs:
181
+ st.markdown(f"""<p style="border: 2px solid black;padding: 10px 20px; box-shadow: 10px 10px 5px #aaaaaa"><span style="font-family:Garamond;">User Email ID</span>: <span style="font-family:monospace">{jobs_application.email_id}</span><br><span style="font-family:Garamond">Current Rank: <span style="font-family:monospace">{jobs_application.rank}</span></p>""",unsafe_allow_html=True)
182
+ col1,col2, col3 = st.columns(3)
183
+ with col2:
184
+ if st.button("Rank Resumes"):
185
+ st.session_state['rank_resumes'] = True
186
+
187
+ #Ranking Resumes
188
+ if st.session_state['rank_resumes']:
189
+ re_rank_resumes_container.empty()
190
+ docs = get_docs(users_applied_for_jobs,job_id)
191
+ re_ranked = rerank(job_id,docs,num_docs)
192
+ candidates = [r.document['text'].split('-'*50)[0].strip() for r in re_ranked.results]
193
+ st.markdown(f"<p style='font-family:Garamond;text-indent: 45vh;font-size:25px'>Resumes re-ranked:</p>",unsafe_allow_html=True)
194
+ for candidate in candidates:
195
+ st.markdown(f"""<p style="border: 2px solid black;padding: 10px 20px; box-shadow: 10px 10px 5px #aaaaaa"><span style="font-family:Garamond;">User Email ID</span>: <span style="font-family:monospace">{candidate}</span></p>""",unsafe_allow_html=True)
196
+ col1,col2, col3 = st.columns(3)
197
+ with col2:
198
+ if st.button("Send Emails"):
199
+ st.session_state['send_resumes'] = True
200
+ if st.session_state['send_resumes']:
201
+ add_job_aplication_details(job_id,round_number,candidates)
202
+
203
+
204
+ def add_job_aplication_details(job_id,round_number,candidates):
205
+ def update(job_application):
206
+ print('----------------------------------------4')
207
+ job_application.round_number += 1
208
+ job_application.rank = job_application.round_number
209
+ return job_application
210
+
211
+
212
+
213
+ with Session(ENGINE) as session:
214
+ stmt = select(JobsApplied).where(JobsApplied.job_id == job_id).where(JobsApplied.email_id.not_in(candidates))
215
+ jobs = session.scalars(stmt).all()
216
+ for job in jobs:
217
+ session.delete(job)
218
+ session.commit()
219
+ print('deleted')
220
+ with Session(ENGINE) as session:
221
+ stmt = select(JobsApplied).where(JobsApplied.job_id == job_id).where(JobsApplied.email_id.in_(candidates))
222
+ jobs = session.scalars(stmt).all()
223
+ for job in jobs:
224
+ update(job)
225
+ session.commit()
226
+ print('updated')
227
+ sending_emails(job_id, candidates)
228
+
229
+ def sending_emails(job_id, candidates):
230
+ email_message = EmailMessage()
231
+ email_message['From'] = st.session_state['employee'].email_id
232
+ email_message['To'] = candidates
233
+ email_message['Subject'] = f'You are selected for Job ID: {job_id}.'
234
+ email_message.set_content('Hello,\nYou are selected to attend the interview. Please login to your profile and attend.')
235
+ with smtplib.SMTP_SSL('smtp.gmail.com',465) as smtp:
236
+ # st.write(os.environ['EMAIL'])
237
+ smtp.login(st.session_state['employee'].email_id, os.environ['EMAIL'])
238
+ smtp.send_message(email_message)
239
+ st.success(f'⚠️Email Sent SUccessfully')
240
+
241
+
242
+
243
+
244
+ def get_docs(jobs_applications,job_id):
245
+ docs = []
246
+ print(f'resumes/{job_id}')
247
+ resumes_dir = pathlib.Path(f'resumes/{job_id}')
248
+
249
+
250
+ for resume in resumes_dir.iterdir():
251
+ print(resume)
252
+ parsed_text = parse(resume)
253
+ print(parsed_text)
254
+ print('---------------------------------------------------------------------------')
255
+ email_id = resume.stem.split('-')[0]
256
+ text = f"{email_id}"+'-'*50+parsed_text
257
+ docs.append(text)
258
+ return docs
259
+
260
+
261
+
262
+
263
+
264
+
265
+
266
+
267
+
268
+
269
+ print('Before settings')
270
+
271
+ # Setting Session states
272
+ if 'employee_logged' not in st.session_state:
273
+ st.session_state['employee_logged'] = False
274
+ if 'employee' not in st.session_state:
275
+ st.session_state['employee'] = None
276
+ if 'add_job' not in st.session_state:
277
+ st.session_state['add_job'] = False
278
+
279
+ if 'add_new_skill' not in st.session_state:
280
+ st.session_state['add_new_skill'] = False
281
+
282
+ if 'rank_resumes' not in st.session_state:
283
+ st.session_state['rank_resumes'] = False
284
+
285
+ if 'rank_resumes' not in st.session_state:
286
+ st.session_state['rank_resumes'] = False
287
+
288
+ if 'send_resumes' not in st.session_state:
289
+ st.session_state['send_resumes'] = False
290
+
291
+
292
+
293
+
294
+
295
+
296
+
297
+
298
+
299
+
300
+
301
+ print('script start')
302
+
303
+ #Login
304
+
305
+
306
+ if not st.session_state['employee_logged']:
307
+ employee = login()
308
+
309
+
310
+ if st.session_state['employee_logged']:
311
+ col1, col2 = st.columns(2)
312
+ with col2:
313
+ st.button('Log Out',on_click=clear_cache)
314
+
315
+
316
+ tab1, tab2, tab3 = st.tabs(["Post Jobs","Jobs Posted","Get Job Applied Details"])
317
+ with tab1:
318
+ post_job()
319
+ with tab2:
320
+ get_jobs_posted()
321
+ with tab3:
322
+ get_users_who_applied_for_jobs()
323
+
324
+
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ streamlit==1.25.0
2
+ sqlalchemy==2.0.19
3
+ cohere
4
+ openai
5
+ pypdf
6
+ docx2txt