AI 候选人面试综合评估

This commit is contained in:
2026-01-26 23:59:11 +08:00
parent 1000944268
commit 6d531c1b99
2 changed files with 100 additions and 62 deletions

View File

@@ -1,6 +1,7 @@
package com.vetti.hotake.service.impl; package com.vetti.hotake.service.impl;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
@@ -589,12 +590,12 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
@Override @Override
public String handleWebInfoExtract(HotakeWebInfoExtractVo webInfoExtractVo) { public String handleWebInfoExtract(HotakeWebInfoExtractVo webInfoExtractVo) {
//获取 //获取
if(StrUtil.isEmpty(webInfoExtractVo.getWebUrl())){ if (StrUtil.isEmpty(webInfoExtractVo.getWebUrl())) {
throw new ServiceException(""); throw new ServiceException("");
} }
String webUrl = webInfoExtractVo.getWebUrl(); String webUrl = webInfoExtractVo.getWebUrl();
if(!webInfoExtractVo.getWebUrl().toLowerCase().contains("https")){ if (!webInfoExtractVo.getWebUrl().toLowerCase().contains("https")) {
webUrl = webUrl.replaceAll("http","https"); webUrl = webUrl.replaceAll("http", "https");
} }
String webContent = handleWebContentScraping(webUrl); String webContent = handleWebContentScraping(webUrl);
@@ -1013,10 +1014,10 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
String resultJsonOne = resultStrOne.replaceAll("```json", "").replaceAll("```", ""); String resultJsonOne = resultStrOne.replaceAll("```json", "").replaceAll("```", "");
log.info("AI面试问题生成结果:{}", resultJsonOne); log.info("AI面试问题生成结果:{}", resultJsonOne);
try{ try {
Map mapData = JSONUtil.toBean(resultJsonOne,Map.class); Map mapData = JSONUtil.toBean(resultJsonOne, Map.class);
List<Map> questionMapList = (List<Map>)mapData.get("interview_questions"); List<Map> questionMapList = (List<Map>) mapData.get("interview_questions");
if(CollectionUtil.isNotEmpty(questionMapList)){ if (CollectionUtil.isNotEmpty(questionMapList)) {
HotakeAiInterviewQuestionsInfo questionsInfo = new HotakeAiInterviewQuestionsInfo(); HotakeAiInterviewQuestionsInfo questionsInfo = new HotakeAiInterviewQuestionsInfo();
questionsInfo.setQuestionTitle("General Questions"); questionsInfo.setQuestionTitle("General Questions");
questionsInfo.setFocusType("Personality & Culture"); questionsInfo.setFocusType("Personality & Culture");
@@ -1026,7 +1027,7 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
BigDecimal times = BigDecimal.ZERO; BigDecimal times = BigDecimal.ZERO;
List<AiQuestionDto> questionDtoList = new ArrayList<>(); List<AiQuestionDto> questionDtoList = new ArrayList<>();
for(Map map : questionMapList){ for (Map map : questionMapList) {
AiQuestionDto questionDto = new AiQuestionDto(); AiQuestionDto questionDto = new AiQuestionDto();
questionDto.setQuestions(map.get("question_text").toString()); questionDto.setQuestions(map.get("question_text").toString());
questionDtoList.add(questionDto); questionDtoList.add(questionDto);
@@ -1041,7 +1042,7 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
hotakeAiInterviewQuestionsInfoMapper.insertHotakeAiInterviewQuestionsInfo(questionsInfo); hotakeAiInterviewQuestionsInfoMapper.insertHotakeAiInterviewQuestionsInfo(questionsInfo);
return questionsInfo; return questionsInfo;
} }
}catch (Exception e){ } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
return new HotakeAiInterviewQuestionsInfo(); return new HotakeAiInterviewQuestionsInfo();
@@ -1058,13 +1059,17 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
HotakeCandidateAiInterviewAnalysisDto analysisDto = new HotakeCandidateAiInterviewAnalysisDto(); HotakeCandidateAiInterviewAnalysisDto analysisDto = new HotakeCandidateAiInterviewAnalysisDto();
String prompt = AiCommonPromptConstants.initializationCandidateAiInterviewAnalysisPrompt(); String prompt = AiCommonPromptConstants.initializationCandidateAiInterviewAnalysisPrompt();
String qa = ""; String qa = "";
String qStr = "";
String aStr = "";
if (CollectionUtil.isNotEmpty(analysisVo.getAiInterviewQuestionRecordVoList())) { if (CollectionUtil.isNotEmpty(analysisVo.getAiInterviewQuestionRecordVoList())) {
for (HotakeAiInterviewQuestionRecordVo recordVo : analysisVo.getAiInterviewQuestionRecordVoList()) { for (HotakeAiInterviewQuestionRecordVo recordVo : analysisVo.getAiInterviewQuestionRecordVoList()) {
if ("assistant".equals(recordVo.getUserType())) { if ("assistant".equals(recordVo.getUserType())) {
qa = qa + "Question:" + recordVo.getContentText(); qa = qa + "Question:" + recordVo.getContentText();
qStr = qStr + ";" + recordVo.getContentText();
} }
if ("user".equals(recordVo.getUserType())) { if ("user".equals(recordVo.getUserType())) {
qa = qa + "Answer:" + recordVo.getContentText(); qa = qa + "Answer:" + recordVo.getContentText();
aStr = aStr + ";" + recordVo.getContentText();
} }
} }
} }
@@ -1139,10 +1144,45 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
} }
} }
//把面试结果分析和问答Qa保存到记录表中 //把面试结果分析和问答Qa保存到记录表中
if(analysisVo.getRoleApplyId() != null){ if (analysisVo.getRoleApplyId() != null) {
HotakeRolesApplyInfo applyInfo = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoById(analysisVo.getRoleApplyId()); HotakeRolesApplyInfo applyInfo = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoById(analysisVo.getRoleApplyId());
applyInfo.setAiInterviewAnalysisJson(JSONUtil.toJsonStr(analysisVo)); applyInfo.setAiInterviewAnalysisJson(JSONUtil.toJsonStr(analysisVo));
applyInfo.setAiInterviewAnalysisQaJson(JSONUtil.toJsonStr(analysisVo.getAiInterviewQuestionRecordVoList())); applyInfo.setAiInterviewAnalysisQaJson(JSONUtil.toJsonStr(analysisVo.getAiInterviewQuestionRecordVoList()));
HotakeRolesInfo rolesInf = hotakeRolesInfoMapper.selectHotakeRolesInfoById(applyInfo.getRoleId());
try {
//候选人面试综合评估
HotakeCandidateInterviewEvaluationVo evaluationVo = new HotakeCandidateInterviewEvaluationVo();
evaluationVo.setTitle(rolesInf.getRoleName());
evaluationVo.setDescription(rolesInf.getAboutRole());
evaluationVo.setRequiredSkills(rolesInf.getRequiredSkillsJson());
evaluationVo.setPreferredSkills(rolesInf.getNiceToHaveSkillsJson());
evaluationVo.setExperienceRequired(rolesInf.getJobExperience());
HotakeCvInfoDto cvInfoDto = JSONUtil.toBean(applyInfo.getCvTemplateJson(), HotakeCvInfoDto.class);
evaluationVo.setName(cvInfoDto.getName());
evaluationVo.setCurrentPosition(cvInfoDto.getPosition());
evaluationVo.setEmail(cvInfoDto.getEmail());
evaluationVo.setWorkExperience(JSONUtil.toJsonStr(cvInfoDto.getExperience()));
evaluationVo.setSkills(JSONUtil.toJsonStr(cvInfoDto.getSkillsTools()));
evaluationVo.setEducation(JSONUtil.toJsonStr(cvInfoDto.getEducation()));
evaluationVo.setCertifications("");
evaluationVo.setInterviewData(DateUtil.now());
evaluationVo.setQuestions(qStr);
evaluationVo.setAnswers(aStr);
evaluationVo.setTechnical(analysisDto.getTechnical().toString());
evaluationVo.setCommunication(analysisDto.getCommunication().toString());
evaluationVo.setSafetyAwareness("");
evaluationVo.setProblemSolving("");
HotakeCandidateInterviewEvaluationDto evaluationDto = getCandidateInterviewEvaluation(evaluationVo);
applyInfo.setEvaluationJson(JSONUtil.toJsonStr(evaluationDto));
applyInfo.setEvaluationScore(new BigDecimal(evaluationDto.getOverallScore()));
} catch (Exception e) {
e.printStackTrace();
}
hotakeRolesApplyInfoMapper.updateHotakeRolesApplyInfo(applyInfo); hotakeRolesApplyInfoMapper.updateHotakeRolesApplyInfo(applyInfo);
} }
return analysisDto; return analysisDto;
@@ -1221,36 +1261,36 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
try { try {
Map dataMap = JSONUtil.toBean(resultJsonOne, Map.class); Map dataMap = JSONUtil.toBean(resultJsonOne, Map.class);
Map scoresMap = (Map) dataMap.get("scores"); Map scoresMap = (Map) dataMap.get("scores");
if(ObjectUtil.isNotEmpty(scoresMap.get("skills"))){ if (ObjectUtil.isNotEmpty(scoresMap.get("skills"))) {
dto.setSkills(new BigDecimal(scoresMap.get("skills").toString())); dto.setSkills(new BigDecimal(scoresMap.get("skills").toString()));
}else{ } else {
dto.setSkills(BigDecimal.ZERO); dto.setSkills(BigDecimal.ZERO);
} }
if(ObjectUtil.isNotEmpty(scoresMap.get("experience"))){ if (ObjectUtil.isNotEmpty(scoresMap.get("experience"))) {
dto.setExperience(new BigDecimal(scoresMap.get("experience").toString())); dto.setExperience(new BigDecimal(scoresMap.get("experience").toString()));
}else{ } else {
dto.setExperience(BigDecimal.ZERO); dto.setExperience(BigDecimal.ZERO);
} }
if(ObjectUtil.isNotEmpty(scoresMap.get("education"))){ if (ObjectUtil.isNotEmpty(scoresMap.get("education"))) {
dto.setEducation(new BigDecimal(scoresMap.get("education").toString())); dto.setEducation(new BigDecimal(scoresMap.get("education").toString()));
}else{ } else {
dto.setEducation(BigDecimal.ZERO); dto.setEducation(BigDecimal.ZERO);
} }
if(ObjectUtil.isNotEmpty(scoresMap.get("cultural"))){ if (ObjectUtil.isNotEmpty(scoresMap.get("cultural"))) {
dto.setCultural(new BigDecimal(scoresMap.get("cultural").toString())); dto.setCultural(new BigDecimal(scoresMap.get("cultural").toString()));
}else{ } else {
dto.setCultural(BigDecimal.ZERO); dto.setCultural(BigDecimal.ZERO);
} }
if(ObjectUtil.isNotEmpty(scoresMap.get("potential"))){ if (ObjectUtil.isNotEmpty(scoresMap.get("potential"))) {
dto.setPotential(new BigDecimal(scoresMap.get("potential").toString())); dto.setPotential(new BigDecimal(scoresMap.get("potential").toString()));
}else{ } else {
dto.setPotential(BigDecimal.ZERO); dto.setPotential(BigDecimal.ZERO);
} }
List<String> strengths = (List<String>)dataMap.get("strengths"); List<String> strengths = (List<String>) dataMap.get("strengths");
dto.setStrengths(strengths); dto.setStrengths(strengths);
List<String> weaknesses = (List<String>)dataMap.get("weaknesses"); List<String> weaknesses = (List<String>) dataMap.get("weaknesses");
dto.setWeaknesses(weaknesses); dto.setWeaknesses(weaknesses);
dto.setReason(dataMap.get("reason").toString()); dto.setReason(dataMap.get("reason").toString());
@@ -1262,7 +1302,7 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
add(dto.getCultural().multiply(new BigDecimal(0.15)).add(dto.getPotential().multiply(new BigDecimal(0.15))))); add(dto.getCultural().multiply(new BigDecimal(0.15)).add(dto.getPotential().multiply(new BigDecimal(0.15)))));
dto.setOverallScore(overallScore); dto.setOverallScore(overallScore);
}catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
return dto; return dto;
@@ -1305,29 +1345,29 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
String resultJsonOne = resultStrOne.replaceAll("```json", "").replaceAll("```", ""); String resultJsonOne = resultStrOne.replaceAll("```json", "").replaceAll("```", "");
log.info("招聘者查看候选人匹配度结果:{}", resultJsonOne); log.info("招聘者查看候选人匹配度结果:{}", resultJsonOne);
Map dataMap = JSONUtil.toBean(resultJsonOne, Map.class); Map dataMap = JSONUtil.toBean(resultJsonOne, Map.class);
if(ObjectUtil.isNotEmpty(dataMap.get("strengths_score"))){ if (ObjectUtil.isNotEmpty(dataMap.get("strengths_score"))) {
dto.setStrengthsScore(new BigDecimal(dataMap.get("strengths_score").toString())); dto.setStrengthsScore(new BigDecimal(dataMap.get("strengths_score").toString()));
}else{ } else {
dto.setStrengthsScore(BigDecimal.ZERO); dto.setStrengthsScore(BigDecimal.ZERO);
} }
if(ObjectUtil.isNotEmpty(dataMap.get("differences_score"))){ if (ObjectUtil.isNotEmpty(dataMap.get("differences_score"))) {
dto.setDifferencesScore(new BigDecimal(dataMap.get("differences_score").toString())); dto.setDifferencesScore(new BigDecimal(dataMap.get("differences_score").toString()));
}else{ } else {
dto.setDifferencesScore(BigDecimal.ZERO); dto.setDifferencesScore(BigDecimal.ZERO);
} }
if(ObjectUtil.isNotEmpty(dataMap.get("cultural_score"))){ if (ObjectUtil.isNotEmpty(dataMap.get("cultural_score"))) {
dto.setCulturalScore(new BigDecimal(dataMap.get("cultural_score").toString())); dto.setCulturalScore(new BigDecimal(dataMap.get("cultural_score").toString()));
}else{ } else {
dto.setCulturalScore(BigDecimal.ZERO); dto.setCulturalScore(BigDecimal.ZERO);
} }
List<String> strengths = (List<String>)dataMap.get("key_strengths"); List<String> strengths = (List<String>) dataMap.get("key_strengths");
dto.setKeyStrengths(strengths); dto.setKeyStrengths(strengths);
List<String> differences = (List<String>)dataMap.get("key_differences"); List<String> differences = (List<String>) dataMap.get("key_differences");
dto.setKeyDifferences(differences); dto.setKeyDifferences(differences);
List<String> fitDetails = (List<String>)dataMap.get("cultural_fit_details"); List<String> fitDetails = (List<String>) dataMap.get("cultural_fit_details");
dto.setCulturalFitDetails(fitDetails); dto.setCulturalFitDetails(fitDetails);
BigDecimal overallScore = dto.getStrengthsScore().multiply(new BigDecimal(0.4)). BigDecimal overallScore = dto.getStrengthsScore().multiply(new BigDecimal(0.4)).
@@ -1350,25 +1390,25 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
String prompt = AiCommonPromptConstants.initializationCandidateInterviewEvaluationPrompt(); String prompt = AiCommonPromptConstants.initializationCandidateInterviewEvaluationPrompt();
String userPrompt_1 = "Job Posting:\n" + String userPrompt_1 = "Job Posting:\n" +
"Title: "+evaluationVo.getTitle()+"\n" + "Title: " + evaluationVo.getTitle() + "\n" +
"Description: "+evaluationVo.getDescription()+"\n" + "Description: " + evaluationVo.getDescription() + "\n" +
"Required Skills: "+evaluationVo.getRequiredSkills()+"\n" + "Required Skills: " + evaluationVo.getRequiredSkills() + "\n" +
"Preferred Skills: "+evaluationVo.getPreferredSkills()+"\n" + "Preferred Skills: " + evaluationVo.getPreferredSkills() + "\n" +
"Experience Required: "+evaluationVo.getExperienceRequired()+"\n" + "Experience Required: " + evaluationVo.getExperienceRequired() + "\n" +
"\n" + "\n" +
"Candidate Information:\n" + "Candidate Information:\n" +
"Name: "+evaluationVo.getName()+"\n" + "Name: " + evaluationVo.getName() + "\n" +
"Current Position: "+evaluationVo.getCurrentPosition()+"\n" + "Current Position: " + evaluationVo.getCurrentPosition() + "\n" +
"Email: "+evaluationVo.getEmail()+"\n" + "Email: " + evaluationVo.getEmail() + "\n" +
"Work Experience: "+evaluationVo.getWorkExperience()+"\n" + "Work Experience: " + evaluationVo.getWorkExperience() + "\n" +
"Skills: "+evaluationVo.getSkills()+"\n" + "Skills: " + evaluationVo.getSkills() + "\n" +
"Education: "+evaluationVo.getEducation()+"\n" + "Education: " + evaluationVo.getEducation() + "\n" +
"Certifications: "+evaluationVo.getCertifications()+"\n" + "Certifications: " + evaluationVo.getCertifications() + "\n" +
"\n" + "\n" +
"Interview Data:"+evaluationVo.getInterviewData()+"\n" + "Interview Data:" + evaluationVo.getInterviewData() + "\n" +
"Questions: "+evaluationVo.getQuestions()+"\n" + "Questions: " + evaluationVo.getQuestions() + "\n" +
"Answers: "+evaluationVo.getAnswers()+"\n" + "Answers: " + evaluationVo.getAnswers() + "\n" +
"Scores: Technical="+evaluationVo.getTechnical()+", Communication="+evaluationVo.getCommunication()+", Safety Awareness="+evaluationVo.getSafetyAwareness()+", Problem Solving="+evaluationVo.getProblemSolving()+"}\n" + "Scores: Technical=" + evaluationVo.getTechnical() + ", Communication=" + evaluationVo.getCommunication() + ", Safety Awareness=" + evaluationVo.getSafetyAwareness() + ", Problem Solving=" + evaluationVo.getProblemSolving() + "}\n" +
"\n" + "\n" +
"Please analyze this candidate and provide a comprehensive overview with Assessment, Rating, and Questions scores."; "Please analyze this candidate and provide a comprehensive overview with Assessment, Rating, and Questions scores.";
@@ -1387,27 +1427,27 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
String resultJsonOne = resultStrOne.replaceAll("```json", "").replaceAll("```", ""); String resultJsonOne = resultStrOne.replaceAll("```json", "").replaceAll("```", "");
log.info("候选人面试综合评估:{}", resultJsonOne); log.info("候选人面试综合评估:{}", resultJsonOne);
Map dataMap = JSONUtil.toBean(resultJsonOne, Map.class); Map dataMap = JSONUtil.toBean(resultJsonOne, Map.class);
Map scoreBreakdownMap = (Map)dataMap.get("score_breakdown"); Map scoreBreakdownMap = (Map) dataMap.get("score_breakdown");
if(scoreBreakdownMap != null){ if (scoreBreakdownMap != null) {
Map assessmentMap = (Map)scoreBreakdownMap.get("assessment"); Map assessmentMap = (Map) scoreBreakdownMap.get("assessment");
if(assessmentMap != null){ if (assessmentMap != null) {
dto.setAssessmentScore(assessmentMap.get("score").toString()); dto.setAssessmentScore(assessmentMap.get("score").toString());
dto.setAssessmentLevel(assessmentMap.get("score").toString()); dto.setAssessmentLevel(assessmentMap.get("score").toString());
List<String> details = (List<String>)assessmentMap.get("details"); List<String> details = (List<String>) assessmentMap.get("details");
dto.setAssessmentDetails(details); dto.setAssessmentDetails(details);
} }
Map ratingMap = (Map)scoreBreakdownMap.get("rating"); Map ratingMap = (Map) scoreBreakdownMap.get("rating");
if(ratingMap != null){ if (ratingMap != null) {
dto.setRatingScore(ratingMap.get("score").toString()); dto.setRatingScore(ratingMap.get("score").toString());
dto.setRatingLevel(ratingMap.get("score").toString()); dto.setRatingLevel(ratingMap.get("score").toString());
List<String> details = (List<String>)ratingMap.get("details"); List<String> details = (List<String>) ratingMap.get("details");
dto.setRatingDetails(details); dto.setRatingDetails(details);
} }
Map questionsMap = (Map)scoreBreakdownMap.get("questions"); Map questionsMap = (Map) scoreBreakdownMap.get("questions");
if(questionsMap != null){ if (questionsMap != null) {
dto.setQuestionsScore(questionsMap.get("score").toString()); dto.setQuestionsScore(questionsMap.get("score").toString());
dto.setQuestionsLevel(questionsMap.get("score").toString()); dto.setQuestionsLevel(questionsMap.get("score").toString());
List<String> details = (List<String>)questionsMap.get("details"); List<String> details = (List<String>) questionsMap.get("details");
dto.setQuestionsDetails(details); dto.setQuestionsDetails(details);
} }
} }

View File

@@ -52,9 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select id, candidate_id,recruiter_id, role_id, full_name, email, phone_number, cv_file, cv_file_suffix,file_size_show, select id, candidate_id,recruiter_id, role_id, full_name, email, phone_number, cv_file, cv_file_suffix,file_size_show,
cover_letter, candidate_status, stage, last_contact, cv_template_json, cv_score, cv_md5, experience, ai_match_score, cover_letter, candidate_status, stage, last_contact, cv_template_json, cv_score, cv_md5, experience, ai_match_score,
ai_match_score_percentage,status, ai_cv_scoring_ranking_json,ai_cv_score,candidate_compatibility_json, ai_match_score_percentage,status, ai_cv_scoring_ranking_json,ai_cv_score,candidate_compatibility_json,
candidate_compatibility_score,evaluation_json,evaluation_score, candidate_compatibility_score,evaluation_json,evaluation_score,ai_interview_analysis_json,ai_interview_analysis_qa_json,
ai_match_score_percentage,status, ai_cv_scoring_ranking_json,ai_cv_score,candidate_compatibility_json,
candidate_compatibility_score,ai_interview_analysis_json,ai_interview_analysis_qa_json,
del_flag, create_by, create_time, update_by, update_time, remark from hotake_roles_apply_info del_flag, create_by, create_time, update_by, update_time, remark from hotake_roles_apply_info
</sql> </sql>