File size: 21,717 Bytes
3741806
 
 
 
 
38b4374
 
e944dc7
 
1563988
3741806
e944dc7
1563988
 
 
 
3741806
fcaf14a
 
3741806
1563988
49470f9
 
1563988
 
49470f9
 
 
3741806
1563988
3741806
 
 
 
 
49470f9
3741806
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5d45a78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3741806
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0eddb80
 
 
3741806
 
 
 
 
 
 
1563988
3741806
 
95e832d
 
 
3741806
 
 
 
1563988
3741806
 
1563988
3741806
 
 
 
 
49cc82e
0afa2a7
49cc82e
3fbff0b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95e832d
3fbff0b
 
 
 
 
 
 
 
 
 
 
 
 
5d45a78
3fbff0b
 
 
 
49cc82e
 
 
 
 
 
95e832d
 
3741806
 
 
 
 
3fbff0b
3741806
 
afd1d0b
3741806
 
 
 
 
 
 
 
 
afd1d0b
3741806
 
1563988
 
95e832d
 
 
3741806
 
 
 
1563988
 
3741806
 
1563988
 
3741806
 
1563988
 
3741806
1563988
3741806
afd1d0b
3741806
 
 
 
 
95e832d
 
 
 
 
3741806
 
 
 
 
 
 
 
 
134dbf5
 
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
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
from utils import draw_radar_chart
import json
import gradio as gr
from pydantic import BaseModel
import openai
import os

openai.api_base = "https://api.wzunjh.top/v1"


def ask_gpt(prompt):
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",  # here we use `gpt-3.5-turbo` model, while Stanford-Alpaca uses `text-davinci-003`
        messages=[
            {"role": "user", "content": prompt},
        ]
    )
    print(response)
    return response.choices[0].message.content.strip()


def ask_gpt_with_history(history):
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",  # here we use `gpt-3.5-turbo` model, while Stanford-Alpaca uses `text-davinci-003`
        messages=history
    )
    print(response)
    return response.choices[0].message.content.strip()


async def predict(input, history):
    """
    Predict the response of the chatbot and complete a running list of chat history.
    """
    history.append({"role": "user", "content": input})
    response = ask_gpt_with_history(history)
    history.append({"role": "assistant", "content": response})
    messages = [(history[i]["content"], history[i + 1]["content"]) for i in range(0, len(history) - 1, 2)]
    return messages, history


class Message(BaseModel):
    role: str
    content: str


def parse_file(file):
    print(file.name)
    with open(file.name, encoding="utf8") as in_file:
        txt = in_file.read()
    return txt, gr.update(visible=True), gr.update(visible=True), gr.update(visible=True)


# 生成人才画像
def generate_talent_portrait(resume):
    prompt = f"你现在是HR招聘专家,下面是候选人的简历:\n\"\"\"\"{resume}\"\"\"\"\n请你分析候选人的教育背景、工作经验、技能等方面的特点,给出候选人的人才画像,并概括性的分析候选人的优点和不足。"
    return ask_gpt(prompt)


# 人岗匹配度
def person_job_fit_gene(resume, jd):
    # prompt = f"你现在是HR招聘专家,某职位要求是:{{{jd}}}\n某候选人简历如下:{{{get_talent_outline(resume)}}}" + "。岗位与候选人之间的匹配度可以用0-1之间的数字表示,0表示完全不匹配,1表示完全匹配。请你评估应聘岗位与候选人的匹配度,并给出理由。"
    prompt = '''你现在是HR招聘专家,某职位要求是:
    {}
    某候选人简历信息如下:{}。
    针对候选人的简历与职位要求进行匹配度评估,采取以下规则:1. 教育背景匹配度评估:
   - 完全匹配:候选人的教育背景与职位要求完全符合。
   - 较为匹配:候选人的教育背景与职位要求有一定的相关性,但不完全符合。
   - 较不匹配:候选人的教育背景与职位要求有一些不相关的情况。
   - 完全不匹配:候选人的教育背景与职位要求完全不符合。

2. 工作经验匹配度评估:
   - 完全匹配:候选人的工作经验与职位要求完全符合。
   - 较为匹配:候选人的工作经验与职位要求具备相应的技能和经验,但可能缺少某些方面的经验。
   - 较不匹配:候选人的工作经验与职位要求相差较大,缺乏相关的技能和经验。
   - 完全不匹配:候选人的工作经验与职位要求完全不符合。

3. 技能与能力匹配度评估:
   - 完全匹配:候选人具备职位要求的所有必备技能和能力。
   - 较为匹配:候选人具备部分职位要求的技能和能力,但可能缺少某些方面的能力。
   - 较不匹配:候选人缺乏职位要求的关键技能和能力。
   - 完全不匹配:候选人的技能和能力与职位要求完全不符合。

4. 其他因素综合考虑:
   - 完全匹配:候选人除了教育背景、工作经验和技能与能力外,还具备其他与职位要求相关的因素,如培训经历、认证证书等。
   - 较为匹配:候选人除了教育背景、工作经验和技能与能力外,可能还具备一些与职位要求相关的因素。
   - 较不匹配:候选人缺乏与职位要求相关的其他因素。
   - 完全不匹配:候选人的其他因素与职位要求完全不符合。

5. 整体的人岗匹配度:
   综合考量候选人的教育背景、工作经验、技能与能力以及其他因素得到整体的岗位匹配度。
根据以上规则,对简历与职位要求之间的匹配度进行评估,并划分为完全匹配、较为匹配、较不匹配和完全不匹配四个档次。
评估结果请以json格式返回给我,下面是返回结果的示例:

  "教育背景匹配度":{
    "结果":"",
    "评估说明":""
  },
  "工作经验匹配度":{
    "结果":"",
    "评估说明":""
  },
  "技能与能力匹配度":{
    "结果":"",
    "评估说明":""
  },
  "其他因素匹配度":{
    "结果":"",
    "评估说明":""
  },
  "整体匹配度":{
    "结果":"",
    "评估说明":""


    '''.format(jd, resume)
    data = json.loads(ask_gpt(prompt))
    edu_matching = data['教育背景匹配度']['结果']
    edu_description = data['教育背景匹配度']['评估说明']

    work_exp_matching = data['工作经验匹配度']['结果']
    work_exp_description = data['工作经验匹配度']['评估说明']

    skill_matching = data['技能与能力匹配度']['结果']
    skill_description = data['技能与能力匹配度']['评估说明']

    other_matching = data['其他因素匹配度']['结果']
    other_description = data['其他因素匹配度']['评估说明']

    overall_matching = data['整体匹配度']['结果']
    overall_description = data['整体匹配度']['评估说明']
    return gr.update(value=edu_matching), gr.update(value=work_exp_matching, ), gr.update(
        value=skill_matching, ), gr.update(value=other_matching, ), gr.update(
        value=overall_matching, ), edu_description, work_exp_description, skill_description, other_description, overall_description


# interview_questions
def generate_interview_questions(work_experience):
    prompt = f"你现在是HR招聘专家,下面是候选人A的工作经历:{work_experience}\n我可以问哪些问题来判断该候选人的能力水平?"
    return ask_gpt(prompt)


# interview_questions
def generate_interview_questions_new(resume, jd):
    prompt = f"你现在是HR高级面试官,某职位要求是:{{{jd}}}\n下面是候选人A简历的:\n{resume}\n请你生成一些面试问题来判断该候选人的能力水平。注意,请把面试问题以python列表格式返回给我,不要返回任何额外内容。"
    print(prompt)
    res = ask_gpt(prompt)
    print(res)
    print(eval(res))
    return gr.update(choices=eval(res), value=eval(res), interactive=True), gr.update(visible=True)


def generate_jd(jobTitle, eduLevel, workYearArr):
    prompt = "你现在是HR招聘专家,你需要发布一个名称为\"" + jobTitle + "\"的职位,请你撰写一份该职位的JD,内容包括工作职责和任职要求。"
    if eduLevel != "":
        prompt += "该岗位的最低学历要求为" + eduLevel + "。"
    if workYearArr != "":
        prompt += "该岗位的工作年限要求为" + workYearArr + "。"
    prompt += "注意:非必要情况不要使用英文,内容不要包含薪酬福利等敏感信息。"
    return ask_gpt(prompt)


def generate_test_resume(target_job, item_list):
    resume_gene_prompt = f"你现在是HR测试数据生成器,请帮我生成一份求职目标为{target_job}的候选人简历,需要包含以下关键信息:\n{item_list}。\n注意,结果请以markdown格式返回给我,并且不要返回额外信息。"
    print(resume_gene_prompt)
    return ask_gpt(resume_gene_prompt)


def generate_interview_feedback(commu_skills, pro_skills, tech_skills, solve_skills, team_skills, pressure_resistance,
                                if_ok):
    prompt = f"""
    你现在是HR招聘专家,下面是某候选人的面试评估结果:
    ***
    沟通能力:{commu_skills}
    专业知识:{pro_skills}
    技术能力:{tech_skills}
    解决问题的能力:{solve_skills}
    团队合作能力:{team_skills}
    抗压能力:{pressure_resistance}
    是否录用:{if_ok}
    ***
    请你根据是否录用结果和其他各项能力的表现生成一份面试评价。
    """
    print(prompt)
    return ask_gpt(prompt)


def gene_ability_score(resume, jd):
    prompt = f"""你现在是HR招聘专家.
    某候选人简历如下:
    {{{resume}}}
    请你从[教育背景、工作经验、技能特长、项目经历和成果、领导力和管理能力、自我学习和发展能力、沟通和协作能力、岗位匹配度]这八个维度对候选人进行打分,分数范围是0-100,并针对每个维度的分数给出相应的打分理由。
    教育背景:
    评价规则:80-100表示教育背景优秀,毕业于985、211大学;70-80表示教育背景良好、毕业于普通重点大学;70分以下表示毕业于普通大学。
    工作经验:
    评价规则:80-100表示候选人具有丰富的相关工作经验,曾承担重要职责并取得显著的成绩;60-79表示候选人有一定的工作经验,能够胜任职务,但成绩一般;60分以下表示候选人工作经验较少或表现普通。
    技能特长:
    评价规则:80-100表示候选人在相关技能方面突出,掌握了多项技能,具备深厚的专业知识;60-79表示候选人具备一些相关技能,能够熟练运用;60分以下表示候选人技能较少或掌握程度一般。
    项目经历和成果:
    评价规则:80-100表示候选人在项目中表现出色,取得了显著的项目成果,具备解决问题和团队合作能力;60-79表示候选人在项目中有一些成绩,能够参与并完成任务;60分以下表示候选人在项目中表现一般或成绩较少。
    领导力和管理能力:
    评价规则:80-100表示候选人具备优秀的领导力和管理能力,曾成功承担过领导职责或项目管理职务;60-79表示候选人具备一定的领导力和管理能力,曾有一定的领导经验;60分以下表示候选人领导能力较弱或未有相关经验。
    自我学习和发展能力:
    评价规则:80-100表示候选人具有积极主动地学习和扩充知识的意愿和能力,持续学习并不断提升自己;60-79表示候选人有一些学习和发展的意愿和能力,但不够积极主动;60分以下表示候选人学习和发展能力较弱或缺乏积极性。
    沟通和协作能力:
    评价规则:80-100表示候选人具备良好的沟通和协作能力,能够与他人有效地进行交流和合作;60-79表示候选人具备一定的沟通和协作能力,能够与他人合作完成任务;60分以下表示候选人沟通和协作能力较弱或简历中描述有限。
    注意,结果参考下面的JSON字符串,以json格式返回给我,不要返回任何额外信息。
    返回结果参考:

    "教育背景": "81",
    "工作经验":"68",
    "技能特长":"69",
    "项目经历和成果":"85",
    "领导力和管理能力":"96",
    "自我学习和发展能力":"100",
    "沟通和协作能力":"56",
    "打分理由":"理性评估"

    """
    print(prompt)
    return ask_gpt(prompt)


def gene_talent_radar(resume, jd):
    res = gene_ability_score(resume, jd)
    json_res = json.loads(res)
    print(json_res)
    score_list = []
    cat_list = []
    for key, value in json_res.items():
        if key != "打分理由":
            cat_list.append(key)
            score_list.append(int(value))
    print(score_list)
    print(cat_list)
    return draw_radar_chart(score_list, cat_list), json_res["打分理由"]


with gr.Blocks(title="HRMaster", theme="soft") as demo:
    gr.Markdown("# HRMaster")
    gr.Markdown("HRMaster usage demo.")
    with gr.Tab("岗位JD生成器"):
        with gr.Row():
            with gr.Column():
                jobTitle_input = gr.Textbox(label="岗位名称")
                eduLevel_input = gr.Textbox(label="最低学历要求")
                workYearArr_input = gr.Textbox(label="工作年限要求")
            with gr.Column():
                jd_output_text = gr.Textbox(label="生成的岗位JD")
                jd_button = gr.Button(value="岗位JD生成")
                jd_button.click(generate_jd, [jobTitle_input, eduLevel_input, workYearArr_input], jd_output_text)
            with gr.Column():
                gr.Examples([["java开发工程师", "本科", "三年以上"], ["算法工程师", "研究生", "一年以上"]],
                            [jobTitle_input, eduLevel_input, workYearArr_input], [jd_output_text], fn=generate_jd,)

    with gr.Tab("简历筛选辅助"):
        with gr.Row():
            resume_file = gr.File(label="请上传简历(目前仅支持上传txt格式简历)", file_types=["text"])
            text_output = gr.Textbox(label="简历信息")
        talent_row = gr.Row(visible=False)
        with talent_row:
            resume_text = gr.Textbox(label="人才画像")
            hua_button = gr.Button(value="生成人才画像", )
            hua_button.click(generate_talent_portrait, text_output, resume_text)

        jd_row = gr.Row(visible=False)
        with jd_row:
            with gr.Column():
                jd = gr.Textbox(label="岗位JD", lines=20)
                test_jd = '''
职位名称:Java开发工程师

工作职责:
1. 根据业务需求,参与需求分析、系统设计和架构设计。
2. 开发和维护基于Java技术的Web应用程序、服务端组件和工具。
3. 编写高质量的可维护、可扩展的代码,并进行单元测试和代码审查。
4. 对现有系统进行优化和性能调优,确保系统的高可用性和稳定性。
5. 与产品经理、设计师和测试人员紧密合作,确保产品质量和用户体验。
6. 持续学习和研究新的技术和开发工具,提出并实施技术创新和改进。

任职要求:
1. 精通Java编程语言,熟悉Java相关的开发框架和工具,如Spring、Hibernate等。
2. 具备扎实的计算机基础知识,熟悉面向对象设计和设计模式。
3. 具备良好的数据结构和算法基础,对系统性能优化有一定的经验。
4. 熟悉Web开发相关的技术,如HTML、CSS、JavaScript等。
5. 具备良好的沟通能力和团队协作能力,能够与团队成员和其他相关岗位进行有效的沟通和合作。
6. 具备良好的问题解决能力和学习能力,能够快速地理解和解决技术问题。
7. 具备良好的代码风格和规范意识,注重代码质量和可维护性。
'''
                gr.Examples([test_jd], [jd])
            with gr.Column():
                # person_job_fit = gr.Textbox(label="人岗匹配度")
                edu_matching = gr.CheckboxGroup(["完全匹配", "较为匹配", "较不匹配", "完全不匹配"], label="教育背景匹配度", info="")
                edu_description = gr.Textbox(label="评估说明",)
                work_exp_matching = gr.CheckboxGroup(["完全匹配", "较为匹配", "较不匹配", "完全不匹配"], label="工作经验匹配度", info="")
                work_exp_description = gr.Textbox(label="评估说明")
                skill_matching = gr.CheckboxGroup(["完全匹配", "较为匹配", "较不匹配", "完全不匹配"], label="技能与能力匹配度", info="")
                skill_description = gr.Textbox(label="评估说明")
                other_matching = gr.CheckboxGroup(["完全匹配", "较为匹配", "较不匹配", "完全不匹配"], label="其他因素匹配度", info="")
                other_description = gr.Textbox(label="评估说明")
                overall_matching = gr.CheckboxGroup(["完全匹配", "较为匹配", "较不匹配", "完全不匹配"], label="整体匹配度", info="")
                overall_description = gr.Textbox(label="评估说明")
            fit_button = gr.Button(value="计算人岗匹配度", )
            fit_button.click(person_job_fit_gene, [text_output, jd],
                                 [edu_matching, work_exp_matching, skill_matching, other_matching, overall_matching,
                                  edu_description, work_exp_description, skill_description, other_description,
                                  overall_description])

        radar_row = gr.Row(visible=False)
        with radar_row:
            radar_outputs = gr.Plot(label="能力雷达图")
            radar_reasons = gr.Textbox(label="打分理由")
            radar_button = gr.Button(value="生成能力雷达图")
            radar_button.click(gene_talent_radar, [text_output, jd], [radar_outputs, radar_reasons])
        gr.Examples([os.path.join(os.path.dirname(__file__), "test_resume.txt")], resume_file,
                    [text_output, talent_row, jd_row, radar_row], fn=parse_file, cache_examples=True)
        resume_file.change(parse_file, resume_file, [text_output, talent_row, jd_row, radar_row])

    with gr.Tab("面试过程辅助"):
        interview_row = gr.Row(visible=True)
        with interview_row:
            interview_questions_text = gr.Checkboxgroup(label="面试问题", show_copy_button=True)
            interview_questions_generator_button = gr.Button(value="面试问题生成")
            interview_questions_generator_button.click(generate_interview_questions_new, [text_output, jd],
                                                       [interview_questions_text])

    with gr.Tab("测试数据生成"):
        with gr.Row():
            targrt_job = gr.Textbox(label="求职目标")
            resume_item_list = gr.Dropdown(
                ["个人信息", "教育背景", "工作经历", "实习经历", "技能专长", "项目经验", "获奖与荣誉", "自我评价"],
                value=["个人信息", "教育背景", "工作经历", "技能专长", "项目经验", "自我评价"], multiselect=True, label="简历维度",
                info="测试简历维度信息"
            )
            test_resume_text = gr.Textbox(label="生成的测试简历信息", show_copy_button=True)
            resume_gene_button = gr.Button("测试数据生成")
            resume_gene_button.click(generate_test_resume, [targrt_job, resume_item_list], test_resume_text)
            test_targrt_job = "java开发工程师"
            test_resume_item_list = ["个人信息", "教育背景", "工作经历", "实习经历", "技能专长", "项目经验", "获奖与荣誉", "自我评价"]
            gr.Examples([[test_targrt_job, test_resume_item_list]], targrt_job, resume_item_list,
                        fn=generate_test_resume,
                        )

    with gr.Tab("面试评价生成器"):
        with gr.Row():
            with gr.Column():
                commu_skills = gr.Radio(["强", "中", "弱"], label="沟通能力",
                                        info="评估候选人的口头表达能力、听取并理解问题的能力、回答问题的清晰度和逻辑性等。")
                pro_skills = gr.Radio(["强", "中", "弱"], label="专业知识", info="评估候选人在岗位所需的专业知识的掌握程度。")
                tech_skills = gr.Radio(["强", "中", "弱"], label="技术能力", info="评估候选人在岗位所需的专业技能方面的掌握程度。")
                solve_skills = gr.Radio(["强", "中", "弱"], label="解决问题的能力",
                                        info="评估候选人在面对问题时的分析能力、创新思维、解决问题的方法和结果。")
                team_skills = gr.Radio(["强", "中", "弱"], label="团队合作能力",
                                       info="评估候选人在与他人合作、协调和沟通方面的能力,包括与面试官的互动、参与小组讨论等。")
                pressure_resistance = gr.Radio(["强", "中", "弱"], label="抗压能力",
                                               info="评估候选人在应对压力、处理复杂情境以及适应变化上的能力。")
                if_ok = gr.Radio(["是", "否"], label="是否录用", info="最终结果")

            with gr.Column():
                interview_feedback_text = gr.Textbox(label="面试评价", show_copy_button=True)
                result_button = gr.Button(value="面试评价生成")
                result_button.click(generate_interview_feedback,
                                    inputs=[commu_skills, pro_skills, tech_skills, solve_skills, team_skills,
                                            pressure_resistance, if_ok],
                                    outputs=interview_feedback_text)
            gr.Examples([["强", "中", "弱", "强", "中", "弱", "是"], ["弱", "中", "弱", "强", "中", "弱", "否"]],
                        [commu_skills, pro_skills, tech_skills, solve_skills, team_skills,
                         pressure_resistance, if_ok], interview_feedback_text,
                        fn=generate_interview_feedback,
                        )
    with gr.Tab("HRChat"):
        with gr.Column():
            chatbot = gr.Chatbot(label="HRChat")
            state = gr.State([])
            clear = gr.Button("Clear")
            txt = gr.Textbox(show_label=False, placeholder="Enter text and press enter").style(container=False)
            txt.submit(predict, [txt, state], [chatbot, state])
            clear.click(lambda: None, None, chatbot, queue=False)

if __name__ == "__main__":
    demo.launch(debug=True)