Vincent Claes commited on
Commit
f6dc197
1 Parent(s): 9a7dcc3

inital code

Browse files
Files changed (3) hide show
  1. Makefile +2 -0
  2. app.py +101 -0
  3. recruiting_assistant.py +170 -0
Makefile ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ deps:
2
+ pipenv requirements > requirements.txt
app.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import gradio as gr
4
+ import requests
5
+ import recruiting_assistant
6
+
7
+
8
+ def search_resume(input_text):
9
+ url = f"https://n970resrb9.execute-api.eu-west-1.amazonaws.com/dev/prediction" # replace with your API endpoint
10
+ headers = {
11
+ "Content-Type": "application/json",
12
+ "x-api-key": os.environ["API_KEY"],
13
+ } # adjust headers as needed
14
+ response = requests.post(
15
+ url, headers=headers, data=json.dumps({"text": input_text})
16
+ )
17
+ response_data = response.json()
18
+
19
+ if "prediction" in response_data:
20
+ prediction = response_data["prediction"]
21
+ if isinstance(prediction, list):
22
+ # Insert a newline after each '.'
23
+ # Insert a newline after each '.' and add "Candidate <follow up number>:\n" before each item
24
+ updated_prediction = [
25
+ f"Candidate {i + 1}:\n=============================\n{s}"
26
+ for i, s in enumerate(prediction)
27
+ ]
28
+ updated_prediction = [s.replace(". ", ".\n") for s in updated_prediction]
29
+ updated_prediction = [s.replace("•", "\n - ") for s in updated_prediction]
30
+ return "\n\n".join(updated_prediction)
31
+ return "No 'prediction' key found in the response or the 'body' is not a list."
32
+
33
+ demo = gr.Blocks()
34
+
35
+ with demo:
36
+ with gr.Group():
37
+ with gr.Box():
38
+ with gr.Row(elem_id="prompt-container").style(
39
+ mobile_collapse=False, equal_height=True
40
+ ):
41
+ with gr.Column():
42
+ gr.Markdown(
43
+ """
44
+
45
+ ## 1. Provide a vacancy and get back relevant resumes from an entire database of resumes for various roles.
46
+ """
47
+ )
48
+ text_vacancy = gr.Textbox(
49
+ hint="Paste here a Vacancy...",
50
+ lines=7,
51
+ label="Copy/paste here a vacancy",
52
+ )
53
+ b1 = gr.Button("Search Resume").style(
54
+ margin=False,
55
+ rounded=(False, True, True, False),
56
+ full_width=False,
57
+ )
58
+ text_search_result = gr.Textbox(
59
+ hint="Top resumes will appear here ...",
60
+ label="Top resumes found in the database",
61
+ )
62
+ b1.click(
63
+ search_resume, inputs=text_vacancy, outputs=text_search_result
64
+ )
65
+ gr.Markdown(
66
+ """
67
+
68
+ ## 2. Select an appropriate resume for this vacancy, paste it in the textfield and get a relevant introduction email.
69
+ """
70
+ )
71
+ text_resume = gr.Textbox(
72
+ hint="Paste here a Resume...",
73
+ label="Copy / Paste here your prefered resume from above and click the button to write an intro ",
74
+ )
75
+ b2 = gr.Button("Write a relevant intro").style(
76
+ margin=False,
77
+ rounded=(False, True, True, False),
78
+ full_width=False,
79
+ )
80
+ gr.Markdown(
81
+ """
82
+
83
+ ## 3. You have a relevant introduction email to send to the customer.
84
+ """
85
+ )
86
+ text_intro = gr.Textbox(label="Intro Email")
87
+ evaluation = gr.Textbox(label="Evaluation of the skills")
88
+ b2.click(
89
+ recruiting_assistant.create_intro,
90
+ inputs=[text_vacancy, text_resume],
91
+ outputs=[text_intro, evaluation],
92
+ )
93
+
94
+ gr.Examples(
95
+ fn=search_resume,
96
+ inputs=text_vacancy,
97
+ outputs=text_search_result,
98
+ cache_examples=False,
99
+ )
100
+
101
+ demo.launch()
recruiting_assistant.py ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from langchain.chat_models import ChatOpenAI
4
+ from langchain.prompts import ChatPromptTemplate
5
+ from langchain.chains import LLMChain, SequentialChain
6
+
7
+ llm = ChatOpenAI(temperature=0.0, openai_api_key=os.environ["OPENAI"])
8
+
9
+
10
+ def create_intro(vacancy, resume):
11
+
12
+ template_vacancy_get_skills = """
13
+ Can you generate me a list of the skills that a candidate is supposed to have for the below vacancy delimited by three backticks.
14
+ If you do not know if skills are available mention that you do not know and do not make up an answer.
15
+ Mention the skills in 1 to maximum three words for each skill. Return the skills as a JSON list.
16
+
17
+ ```
18
+ {vacancy}
19
+ ```
20
+ """
21
+
22
+ prompt_vacancy_get_skills = ChatPromptTemplate.from_template(
23
+ template=template_vacancy_get_skills
24
+ )
25
+ vacancy_skills = LLMChain(
26
+ llm=llm, prompt=prompt_vacancy_get_skills, output_key="vacancy_skills"
27
+ )
28
+
29
+ template_resume_check_skills = """
30
+ ```
31
+ {vacancy_skills}
32
+ ```
33
+
34
+ Based on the above list of skills required by a vacancy delimited by backticks,
35
+ Can you create a JSON object based on the below keys each starting with '-', with respect to the resume below delimited by three backticks?
36
+
37
+ - "skills_present": <list the skills present. If no skills are present return an empty list, do not make up an answer. >
38
+ - "skills_not_present": <list the skills not present. If all skills are present return an empty list, do not make up an answer.>
39
+ - "score": <calculate a percentage of the number of skills present with respect to the total skills requested>
40
+
41
+ ```
42
+ {resume}
43
+ ```
44
+ """
45
+
46
+ prompt_resume_check_skills = ChatPromptTemplate.from_template(
47
+ template=template_resume_check_skills
48
+ )
49
+ resume_skills = LLMChain(
50
+ llm=llm, prompt=prompt_resume_check_skills, output_key="resume_skills"
51
+ )
52
+
53
+ template_resume_past_experiences = """
54
+ Can you generate me a list of the past work experiences that the candidate has based on the resume below enclosed by three backticks.
55
+ Mention the experiences in one sentence of medium length. Return the experiences as a JSON list.
56
+
57
+ ```
58
+ {resume}
59
+ ```
60
+ """
61
+
62
+ prompt_resume_past_experiences = ChatPromptTemplate.from_template(
63
+ template=template_resume_past_experiences
64
+ )
65
+ past_experiences = LLMChain(
66
+ llm=llm, prompt=prompt_resume_past_experiences, output_key="past_experiences"
67
+ )
68
+
69
+ template_vacancy_check_past_experiences = """
70
+ ```
71
+ {past_experiences}
72
+ ```
73
+
74
+ Based on the above list of past experiences by a vacancy delimited by backticks,
75
+ Can you create a JSON object based on the below keys each starting with '-', with respect to the vacancy below delimited by three backticks?
76
+
77
+ - "relevant_experiences": <list the relevant experiences. If no experiences are relevant return an empty list, do not make up an answer. >
78
+ - "irrelevant_experiences": <list the irrelevant experiences. If all experiences are relevant return an empty list, do not make up an answer.>
79
+ - "score": <calculate a percentage of the number of skills present with respect to the total skills requested>
80
+
81
+ ```
82
+ {resume}
83
+ ```
84
+ """
85
+
86
+ prompt_vacancy_check_past_experiences = ChatPromptTemplate.from_template(
87
+ template=template_vacancy_check_past_experiences
88
+ )
89
+ check_past_experiences = LLMChain(
90
+ llm=llm,
91
+ prompt=prompt_vacancy_check_past_experiences,
92
+ output_key="check_past_experiences",
93
+ )
94
+
95
+ template_introduction_email = """
96
+ You are a recruitment specialist that tries to place the right profiles for the right job.
97
+ I have a vacancy below the delimiter <VACANCY> and ends with </VACANCY>
98
+ and I have a candidate its resume below the delimiter <RESUME> and it ends with </RESUME>.
99
+
100
+ <VACANCY>
101
+ {vacancy}
102
+ </VACANCY>
103
+
104
+ <RESUME>
105
+ {resume}
106
+ </RESUME>
107
+
108
+ Can you fill in the introduction below and only return as answer this introduction?
109
+
110
+ - Role: < the role of the vacancy >
111
+ - Candidate: < name of the candidate >
112
+ - Education: < name the education of the candidate >
113
+ - Experience: < name the 2 most relevant experiences from the candidate for this vacancy. Get them from the "relevant_experiences" key of the JSON object {past_experiences}. If there us no relevant experience, leave this empty. Do not make up an answer or get them from the irrelevant experiences. >
114
+ - Skills: print here a comma seperated list of the "skills_present" key of the JSON object {resume_skills}
115
+ """
116
+
117
+ prompt_introduction_email = ChatPromptTemplate.from_template(
118
+ template=template_introduction_email
119
+ )
120
+ introduction_email = LLMChain(
121
+ llm=llm, prompt=prompt_introduction_email, output_key="introduction_email"
122
+ )
123
+
124
+ match_resume_vacancy_skills_chain = SequentialChain(
125
+ chains=[
126
+ vacancy_skills,
127
+ resume_skills,
128
+ past_experiences,
129
+ check_past_experiences,
130
+ introduction_email,
131
+ ],
132
+ input_variables=["vacancy", "resume"],
133
+ output_variables=[
134
+ "vacancy_skills",
135
+ "resume_skills",
136
+ "past_experiences",
137
+ "check_past_experiences",
138
+ "introduction_email",
139
+ ],
140
+ verbose=False,
141
+ )
142
+
143
+ result = match_resume_vacancy_skills_chain({"vacancy": vacancy, "resume": resume})
144
+ print(result)
145
+
146
+ resume_skills = json.loads(result["resume_skills"])
147
+ relevant_skills = len(resume_skills["skills_present"])
148
+ total_skills = len(
149
+ resume_skills["skills_present"] + resume_skills["skills_not_present"]
150
+ )
151
+ score_skills = round(100.0 * (relevant_skills / total_skills), 2)
152
+
153
+ check_past_experiences = json.loads(result["check_past_experiences"])
154
+ relevant_experiences = len(check_past_experiences["relevant_experiences"])
155
+ total_experiences = len(
156
+ check_past_experiences["relevant_experiences"]
157
+ + check_past_experiences["irrelevant_experiences"]
158
+ )
159
+ score_experiences = round(100.0 * (relevant_experiences / total_experiences), 2)
160
+
161
+ new_line = "\n"
162
+
163
+ score = f"""
164
+ Skills (Score: {score_skills}%)
165
+ Relevant Skills: {",".join(resume_skills["skills_present"])}
166
+ Not Relevant Skills: {",".join(resume_skills["skills_not_present"])}
167
+ """
168
+ return result["introduction_email"], score
169
+
170
+