diff --git a/vetti-admin/src/main/java/com/vetti/web/controller/ai/HotakeAiCommonToolsController.java b/vetti-admin/src/main/java/com/vetti/web/controller/ai/HotakeAiCommonToolsController.java index b650f81..2244a44 100644 --- a/vetti-admin/src/main/java/com/vetti/web/controller/ai/HotakeAiCommonToolsController.java +++ b/vetti-admin/src/main/java/com/vetti/web/controller/ai/HotakeAiCommonToolsController.java @@ -218,7 +218,7 @@ public class HotakeAiCommonToolsController extends BaseController { */ @ApiOperation("候选人面试综合评估") @PostMapping(value = "/candidateInterviewEvaluation") - public R candidateInterviewEvaluation(@RequestBody HotakeCandidateInterviewEvaluationVo evaluationVo) + public R candidateInterviewEvaluation(@RequestBody HotakeCandidateInterviewEvaluationVo evaluationVo) { return R.ok(hotakeAiCommonToolsService.getCandidateInterviewEvaluation(evaluationVo)); } diff --git a/vetti-admin/src/main/resources/application-druid.yml b/vetti-admin/src/main/resources/application-druid.yml index feb4f08..cd48dc4 100644 --- a/vetti-admin/src/main/resources/application-druid.yml +++ b/vetti-admin/src/main/resources/application-druid.yml @@ -191,6 +191,7 @@ chatGpt: modelAiIntPf: gpt-4o-mini modelAiCvSr: gpt-4o-mini modelAiCac: gpt-4o-mini + modelAiCiv: gpt-4o-mini role: system http: diff --git a/vetti-admin/target/classes/application-druid.yml b/vetti-admin/target/classes/application-druid.yml index 1463f6f..feb4f08 100644 --- a/vetti-admin/target/classes/application-druid.yml +++ b/vetti-admin/target/classes/application-druid.yml @@ -138,6 +138,7 @@ twilio: reply-to-em7941: noreply@em7941.routez.app template-ids: routez-verification-code: d-18475c5d41e349e2bc3a35f2b4992182 + interview-template-code: d-c377f1e7f5e04cb794e2753af9d2e0c8 accountSID: 1111 authToken: 22222 sendPhoneNumber: 33333 diff --git a/vetti-common/src/main/java/com/vetti/common/ai/gpt/ChatGPTClient.java b/vetti-common/src/main/java/com/vetti/common/ai/gpt/ChatGPTClient.java index 264004e..bb6ec3b 100644 --- a/vetti-common/src/main/java/com/vetti/common/ai/gpt/ChatGPTClient.java +++ b/vetti-common/src/main/java/com/vetti/common/ai/gpt/ChatGPTClient.java @@ -88,6 +88,9 @@ public class ChatGPTClient { @Value("${chatGpt.modelAiCac}") private String modelAiCac; + @Value("${chatGpt.modelAiCiv}") + private String modelAiCiv; + @Value("${chatGpt.role}") private String role; @@ -158,6 +161,9 @@ public class ChatGPTClient { }else if("AICAC".equals(type)){ //招聘者查看候选人匹配度 resultText = sendMessage(promptText, modelAiCac,objectMapper,client,role); + }else if("AICIV".equals(type)){ + //候选人面试综合评估 + resultText = sendMessage(promptText, modelAiCiv,objectMapper,client,role); }else { resultText = sendMessage(promptText, modelQuestion,objectMapper,client,role); } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesApplyInfo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesApplyInfo.java index 0ccd297..11673a9 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesApplyInfo.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesApplyInfo.java @@ -6,6 +6,7 @@ import java.util.List; import com.vetti.common.core.domain.entity.SysUser; import com.vetti.hotake.domain.dto.HotakeAiCvScoringRankingDto; import com.vetti.hotake.domain.dto.HotakeCandidateCompatibilityDto; +import com.vetti.hotake.domain.dto.HotakeCandidateInterviewEvaluationDto; import com.vetti.hotake.domain.dto.HotakeCvInfoDto; import lombok.Data; import lombok.experimental.Accessors; @@ -136,6 +137,18 @@ public class HotakeRolesApplyInfo extends BaseEntity @ApiModelProperty("候选人匹配度最终得分") private BigDecimal candidateCompatibilityScore; + @ApiModelProperty("候选人面试综合评估JSON") + private String evaluationJson; + + @ApiModelProperty("候选人面试综合评估最终得分") + private BigDecimal evaluationScore; + + @ApiModelProperty("AI面试分析JSON 数据") + private String aiInterviewAnalysisJson; + + @ApiModelProperty("AI面试问答数据记录JSON") + private String aiInterviewAnalysisQaJson; + @ApiModelProperty("岗位信息") private HotakeRolesInfo rolesInfo; @@ -154,6 +167,9 @@ public class HotakeRolesApplyInfo extends BaseEntity @ApiModelProperty("招聘者查看候选人匹配度数据对象") private HotakeCandidateCompatibilityDto compatibilityDto; + @ApiModelProperty("候选人面试综合评估数据对象") + private HotakeCandidateInterviewEvaluationDto evaluationDto; + @ApiModelProperty("岗位申请ID数据集合") private List applyRoleIdList; diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesInfo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesInfo.java index 38f26e3..2e5de8d 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesInfo.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/HotakeRolesInfo.java @@ -1,6 +1,8 @@ package com.vetti.hotake.domain; import java.math.BigDecimal; +import java.util.List; + import lombok.Data; import lombok.experimental.Accessors; import io.swagger.annotations.ApiModelProperty; @@ -175,5 +177,8 @@ public class HotakeRolesInfo extends BaseEntity @ApiModelProperty("当前岗位状态(pause:暂停,archived:关闭/归档,open:发布,editing:编辑中)") private String status; + @ApiModelProperty("岗位申请数据集合") + private List rolesApplyInfoList; + } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeCandidateInterviewEvaluationDto.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeCandidateInterviewEvaluationDto.java new file mode 100644 index 0000000..1fbe056 --- /dev/null +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/dto/HotakeCandidateInterviewEvaluationDto.java @@ -0,0 +1,51 @@ +package com.vetti.hotake.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * 候选人面试综合评估 返回对象 + * + * @author ID + * @date 2025-09-06 + */ +@Data +@Accessors(chain = true) +public class HotakeCandidateInterviewEvaluationDto { + + @ApiModelProperty("评估分数") + private String assessmentScore; + + @ApiModelProperty("评估等级") + private String assessmentLevel; + + @ApiModelProperty("评估明细说明") + private List assessmentDetails; + + @ApiModelProperty("评分分数") + private String ratingScore; + + @ApiModelProperty("评分等级") + private String ratingLevel; + + @ApiModelProperty("评分明细说明") + private List ratingDetails; + + @ApiModelProperty("问答分数") + private String questionsScore; + + @ApiModelProperty("问答等级") + private String questionsLevel; + + @ApiModelProperty("问答明细说明") + private List questionsDetails; + + @ApiModelProperty("综合分数") + private String overallScore; + + @ApiModelProperty("推荐说明") + private String recommendation; +} diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeCandidateInterviewEvaluationVo.java b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeCandidateInterviewEvaluationVo.java index cb703f0..ca538a3 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeCandidateInterviewEvaluationVo.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/domain/vo/HotakeCandidateInterviewEvaluationVo.java @@ -50,6 +50,9 @@ public class HotakeCandidateInterviewEvaluationVo { @ApiModelProperty("证书") private String certifications; + @ApiModelProperty("面试时间") + private String interviewData; + @ApiModelProperty("问题") private String questions; diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeAiCommonToolsService.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeAiCommonToolsService.java index d4478c7..90c6150 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeAiCommonToolsService.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/IHotakeAiCommonToolsService.java @@ -156,6 +156,6 @@ public interface IHotakeAiCommonToolsService { * @param evaluationVo 候选人面试综合评估 输入信息 * @return */ - public HotakeCandidateCompatibilityDto getCandidateInterviewEvaluation(HotakeCandidateInterviewEvaluationVo evaluationVo); + public HotakeCandidateInterviewEvaluationDto getCandidateInterviewEvaluation(HotakeCandidateInterviewEvaluationVo evaluationVo); } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeAiCommonToolsServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeAiCommonToolsServiceImpl.java index e5473f4..3de37c6 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeAiCommonToolsServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeAiCommonToolsServiceImpl.java @@ -1,6 +1,7 @@ package com.vetti.hotake.service.impl; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; @@ -589,12 +590,12 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I @Override public String handleWebInfoExtract(HotakeWebInfoExtractVo webInfoExtractVo) { //获取 - if(StrUtil.isEmpty(webInfoExtractVo.getWebUrl())){ + if (StrUtil.isEmpty(webInfoExtractVo.getWebUrl())) { throw new ServiceException(""); } String webUrl = webInfoExtractVo.getWebUrl(); - if(!webInfoExtractVo.getWebUrl().toLowerCase().contains("https")){ - webUrl = webUrl.replaceAll("http","https"); + if (!webInfoExtractVo.getWebUrl().toLowerCase().contains("https")) { + webUrl = webUrl.replaceAll("http", "https"); } String webContent = handleWebContentScraping(webUrl); @@ -1013,10 +1014,10 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I String resultJsonOne = resultStrOne.replaceAll("```json", "").replaceAll("```", ""); log.info("AI面试问题生成结果:{}", resultJsonOne); - try{ - Map mapData = JSONUtil.toBean(resultJsonOne,Map.class); - List questionMapList = (List)mapData.get("interview_questions"); - if(CollectionUtil.isNotEmpty(questionMapList)){ + try { + Map mapData = JSONUtil.toBean(resultJsonOne, Map.class); + List questionMapList = (List) mapData.get("interview_questions"); + if (CollectionUtil.isNotEmpty(questionMapList)) { HotakeAiInterviewQuestionsInfo questionsInfo = new HotakeAiInterviewQuestionsInfo(); questionsInfo.setQuestionTitle("General Questions"); questionsInfo.setFocusType("Personality & Culture"); @@ -1026,7 +1027,7 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I BigDecimal times = BigDecimal.ZERO; List questionDtoList = new ArrayList<>(); - for(Map map : questionMapList){ + for (Map map : questionMapList) { AiQuestionDto questionDto = new AiQuestionDto(); questionDto.setQuestions(map.get("question_text").toString()); questionDtoList.add(questionDto); @@ -1041,7 +1042,7 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I hotakeAiInterviewQuestionsInfoMapper.insertHotakeAiInterviewQuestionsInfo(questionsInfo); return questionsInfo; } - }catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); } return new HotakeAiInterviewQuestionsInfo(); @@ -1058,13 +1059,17 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I HotakeCandidateAiInterviewAnalysisDto analysisDto = new HotakeCandidateAiInterviewAnalysisDto(); String prompt = AiCommonPromptConstants.initializationCandidateAiInterviewAnalysisPrompt(); String qa = ""; + String qStr = ""; + String aStr = ""; if (CollectionUtil.isNotEmpty(analysisVo.getAiInterviewQuestionRecordVoList())) { for (HotakeAiInterviewQuestionRecordVo recordVo : analysisVo.getAiInterviewQuestionRecordVoList()) { if ("assistant".equals(recordVo.getUserType())) { qa = qa + "Question:" + recordVo.getContentText(); + qStr = qStr + ";" + recordVo.getContentText(); } if ("user".equals(recordVo.getUserType())) { qa = qa + "Answer:" + recordVo.getContentText(); + aStr = aStr + ";" + recordVo.getContentText(); } } } @@ -1138,8 +1143,48 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I throw new ServiceException("No rating"); } } - //todo 把面试结果分析保存到记录表中 + //把面试结果分析和问答Qa保存到记录表中 + if (analysisVo.getRoleApplyId() != null) { + HotakeRolesApplyInfo applyInfo = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoById(analysisVo.getRoleApplyId()); + applyInfo.setAiInterviewAnalysisJson(JSONUtil.toJsonStr(analysisVo)); + 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); + } return analysisDto; } @@ -1216,36 +1261,36 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I try { Map dataMap = JSONUtil.toBean(resultJsonOne, Map.class); 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())); - }else{ + } else { dto.setSkills(BigDecimal.ZERO); } - if(ObjectUtil.isNotEmpty(scoresMap.get("experience"))){ + if (ObjectUtil.isNotEmpty(scoresMap.get("experience"))) { dto.setExperience(new BigDecimal(scoresMap.get("experience").toString())); - }else{ + } else { dto.setExperience(BigDecimal.ZERO); } - if(ObjectUtil.isNotEmpty(scoresMap.get("education"))){ + if (ObjectUtil.isNotEmpty(scoresMap.get("education"))) { dto.setEducation(new BigDecimal(scoresMap.get("education").toString())); - }else{ + } else { dto.setEducation(BigDecimal.ZERO); } - if(ObjectUtil.isNotEmpty(scoresMap.get("cultural"))){ + if (ObjectUtil.isNotEmpty(scoresMap.get("cultural"))) { dto.setCultural(new BigDecimal(scoresMap.get("cultural").toString())); - }else{ + } else { dto.setCultural(BigDecimal.ZERO); } - if(ObjectUtil.isNotEmpty(scoresMap.get("potential"))){ + if (ObjectUtil.isNotEmpty(scoresMap.get("potential"))) { dto.setPotential(new BigDecimal(scoresMap.get("potential").toString())); - }else{ + } else { dto.setPotential(BigDecimal.ZERO); } - List strengths = (List)dataMap.get("strengths"); + List strengths = (List) dataMap.get("strengths"); dto.setStrengths(strengths); - List weaknesses = (List)dataMap.get("weaknesses"); + List weaknesses = (List) dataMap.get("weaknesses"); dto.setWeaknesses(weaknesses); dto.setReason(dataMap.get("reason").toString()); @@ -1257,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))))); dto.setOverallScore(overallScore); - }catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } return dto; @@ -1300,29 +1345,29 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I String resultJsonOne = resultStrOne.replaceAll("```json", "").replaceAll("```", ""); log.info("招聘者查看候选人匹配度结果:{}", resultJsonOne); 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())); - }else{ + } else { 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())); - }else{ + } else { 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())); - }else{ + } else { dto.setCulturalScore(BigDecimal.ZERO); } - List strengths = (List)dataMap.get("key_strengths"); + List strengths = (List) dataMap.get("key_strengths"); dto.setKeyStrengths(strengths); - List differences = (List)dataMap.get("key_differences"); + List differences = (List) dataMap.get("key_differences"); dto.setKeyDifferences(differences); - List fitDetails = (List)dataMap.get("cultural_fit_details"); + List fitDetails = (List) dataMap.get("cultural_fit_details"); dto.setCulturalFitDetails(fitDetails); BigDecimal overallScore = dto.getStrengthsScore().multiply(new BigDecimal(0.4)). @@ -1340,30 +1385,30 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I * @return */ @Override - public HotakeCandidateCompatibilityDto getCandidateInterviewEvaluation(HotakeCandidateInterviewEvaluationVo evaluationVo) { - HotakeCandidateCompatibilityDto dto = new HotakeCandidateCompatibilityDto(); + public HotakeCandidateInterviewEvaluationDto getCandidateInterviewEvaluation(HotakeCandidateInterviewEvaluationVo evaluationVo) { + HotakeCandidateInterviewEvaluationDto dto = new HotakeCandidateInterviewEvaluationDto(); String prompt = AiCommonPromptConstants.initializationCandidateInterviewEvaluationPrompt(); String userPrompt_1 = "Job Posting:\n" + - "Title: "+evaluationVo.getTitle()+"\n" + - "Description: "+evaluationVo.getDescription()+"\n" + - "Required Skills: ${jobPosting.required_skills.join(', ')}\n" + - "Preferred Skills: ${jobPosting.preferred_skills.join(', ')}\n" + - "Experience Required: ${jobPosting.experience_required}\n" + + "Title: " + evaluationVo.getTitle() + "\n" + + "Description: " + evaluationVo.getDescription() + "\n" + + "Required Skills: " + evaluationVo.getRequiredSkills() + "\n" + + "Preferred Skills: " + evaluationVo.getPreferredSkills() + "\n" + + "Experience Required: " + evaluationVo.getExperienceRequired() + "\n" + "\n" + "Candidate Information:\n" + - "Name: ${candidate.name}\n" + - "Current Position: ${candidate.current_position}\n" + - "Email: ${candidate.email}\n" + - "Work Experience: ${candidate.work_experience}\n" + - "Skills: ${candidate.skills.join(', ')}\n" + - "Education: ${candidate.education}\n" + - "Certifications: ${candidate.certifications.join(', ')}\n" + + "Name: " + evaluationVo.getName() + "\n" + + "Current Position: " + evaluationVo.getCurrentPosition() + "\n" + + "Email: " + evaluationVo.getEmail() + "\n" + + "Work Experience: " + evaluationVo.getWorkExperience() + "\n" + + "Skills: " + evaluationVo.getSkills() + "\n" + + "Education: " + evaluationVo.getEducation() + "\n" + + "Certifications: " + evaluationVo.getCertifications() + "\n" + "\n" + - "${interviewData ? `Interview Data:\n" + - "Questions: ${interviewData.questions.join('; ')}\n" + - "Answers: ${interviewData.answers.join('; ')}\n" + - "Scores: Technical=${interviewData.scores.technical}, Communication=${interviewData.scores.communication}, Safety Awareness=${interviewData.scores.safety_awareness}, Problem Solving=${interviewData.scores.problem_solving}` : ''}\n" + + "Interview Data:" + evaluationVo.getInterviewData() + "\n" + + "Questions: " + evaluationVo.getQuestions() + "\n" + + "Answers: " + evaluationVo.getAnswers() + "\n" + + "Scores: Technical=" + evaluationVo.getTechnical() + ", Communication=" + evaluationVo.getCommunication() + ", Safety Awareness=" + evaluationVo.getSafetyAwareness() + ", Problem Solving=" + evaluationVo.getProblemSolving() + "}\n" + "\n" + "Please analyze this candidate and provide a comprehensive overview with Assessment, Rating, and Questions scores."; @@ -1378,38 +1423,37 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I mapUserEntityOne.put("content", userPrompt_1); listOne.add(mapUserEntityOne); String promptJsonOne = JSONUtil.toJsonStr(listOne); - String resultStrOne = chatGPTClient.handleAiChat(promptJsonOne, "AICAC"); + String resultStrOne = chatGPTClient.handleAiChat(promptJsonOne, "AICIV"); String resultJsonOne = resultStrOne.replaceAll("```json", "").replaceAll("```", ""); log.info("候选人面试综合评估:{}", resultJsonOne); Map dataMap = JSONUtil.toBean(resultJsonOne, Map.class); - if(ObjectUtil.isNotEmpty(dataMap.get("strengths_score"))){ - dto.setStrengthsScore(new BigDecimal(dataMap.get("strengths_score").toString())); - }else{ - dto.setStrengthsScore(BigDecimal.ZERO); - } - if(ObjectUtil.isNotEmpty(dataMap.get("differences_score"))){ - dto.setDifferencesScore(new BigDecimal(dataMap.get("differences_score").toString())); - }else{ - dto.setDifferencesScore(BigDecimal.ZERO); - } - if(ObjectUtil.isNotEmpty(dataMap.get("cultural_score"))){ - dto.setCulturalScore(new BigDecimal(dataMap.get("cultural_score").toString())); - }else{ - dto.setCulturalScore(BigDecimal.ZERO); + Map scoreBreakdownMap = (Map) dataMap.get("score_breakdown"); + if (scoreBreakdownMap != null) { + Map assessmentMap = (Map) scoreBreakdownMap.get("assessment"); + if (assessmentMap != null) { + dto.setAssessmentScore(assessmentMap.get("score").toString()); + dto.setAssessmentLevel(assessmentMap.get("score").toString()); + List details = (List) assessmentMap.get("details"); + dto.setAssessmentDetails(details); + } + Map ratingMap = (Map) scoreBreakdownMap.get("rating"); + if (ratingMap != null) { + dto.setRatingScore(ratingMap.get("score").toString()); + dto.setRatingLevel(ratingMap.get("score").toString()); + List details = (List) ratingMap.get("details"); + dto.setRatingDetails(details); + } + Map questionsMap = (Map) scoreBreakdownMap.get("questions"); + if (questionsMap != null) { + dto.setQuestionsScore(questionsMap.get("score").toString()); + dto.setQuestionsLevel(questionsMap.get("score").toString()); + List details = (List) questionsMap.get("details"); + dto.setQuestionsDetails(details); + } } - List strengths = (List)dataMap.get("key_strengths"); - dto.setKeyStrengths(strengths); - - List differences = (List)dataMap.get("key_differences"); - dto.setKeyDifferences(differences); - - List fitDetails = (List)dataMap.get("cultural_fit_details"); - dto.setCulturalFitDetails(fitDetails); - - BigDecimal overallScore = dto.getStrengthsScore().multiply(new BigDecimal(0.4)). - add(dto.getDifferencesScore().multiply(new BigDecimal(0.3)).add(dto.getCulturalScore().multiply(new BigDecimal(0.3)))); - dto.setOverallScore(overallScore); + dto.setOverallScore(dataMap.get("overall_score").toString()); + dto.setRecommendation(dataMap.get("recommendation").toString()); return dto; } diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitScreQuestionsReplyRecordInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitScreQuestionsReplyRecordInfoServiceImpl.java index af73e8d..fc4e346 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitScreQuestionsReplyRecordInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeInitScreQuestionsReplyRecordInfoServiceImpl.java @@ -18,15 +18,9 @@ import com.vetti.common.utils.DateUtils; import com.vetti.common.utils.SecurityUtils; import com.vetti.common.utils.readFile.FileContentUtil; import com.vetti.hotake.domain.*; -import com.vetti.hotake.domain.dto.HotakeAiCvScoringRankingDto; -import com.vetti.hotake.domain.dto.HotakeCandidateCompatibilityDto; -import com.vetti.hotake.domain.dto.HotakeCvInfoDto; -import com.vetti.hotake.domain.dto.HotakeInitialQuestionEliminationScoreDto; +import com.vetti.hotake.domain.dto.*; import com.vetti.hotake.domain.dto.VcDto.*; -import com.vetti.hotake.domain.vo.HotakeAiCvScoringRankingRoleApplyVo; -import com.vetti.hotake.domain.vo.HotakeCandidateCompatibilityVo; -import com.vetti.hotake.domain.vo.HotakeInitScreQuestionsReplyRecordInfoVo; -import com.vetti.hotake.domain.vo.HotakeInitialQuestionEliminationScoreVo; +import com.vetti.hotake.domain.vo.*; import com.vetti.hotake.mapper.HotakeCvInfoMapper; import com.vetti.hotake.mapper.HotakeRolesApplyInfoMapper; import com.vetti.hotake.mapper.HotakeRolesInfoMapper; @@ -264,22 +258,53 @@ public class HotakeInitScreQuestionsReplyRecordInfoServiceImpl extends BaseServi applyInfo.setAiCvScore(scoringRankingDto.getOverallScore()); //招聘者查看候选人匹配度 - HotakeCandidateCompatibilityVo compatibilityVo = new HotakeCandidateCompatibilityVo(); - compatibilityVo.setPosition(rolesInf.getRoleName()); +// HotakeCandidateCompatibilityVo compatibilityVo = new HotakeCandidateCompatibilityVo(); +// compatibilityVo.setPosition(rolesInf.getRoleName()); +// HotakeCvInfoDto cvInfoDto = JSONUtil.toBean(applyInfo.getCvTemplateJson(), HotakeCvInfoDto.class); +// compatibilityVo.setCurrentPosition(cvInfoDto.getPosition()); +// compatibilityVo.setOverallRating(scoringRankingDto.getOverallScore().toString()); +// compatibilityVo.setWorkExperience(cvInfoDto.getExperienceYear()); +// List skills = new ArrayList<>(); +// if(CollectionUtil.isNotEmpty(cvInfoDto.getSkillsTools())){ +// for (VcSkillsToolsDto toolsDto : cvInfoDto.getSkillsTools()){ +// skills.add(toolsDto.getContent()); +// } +// } +// compatibilityVo.setSkills(skills); +// +// +// +// HotakeCandidateCompatibilityDto compatibilityDto = aiCommonToolsService.handleCandidateCompatibility(compatibilityVo); +// applyInfo.setCandidateCompatibilityJson(JSONUtil.toJsonStr(compatibilityDto)); +// applyInfo.setCandidateCompatibilityScore(compatibilityDto.getOverallScore()); + + //候选人面试综合评估 + 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); - compatibilityVo.setCurrentPosition(cvInfoDto.getPosition()); - compatibilityVo.setOverallRating(scoringRankingDto.getOverallScore().toString()); - compatibilityVo.setWorkExperience(cvInfoDto.getExperienceYear()); - List skills = new ArrayList<>(); - if(CollectionUtil.isNotEmpty(cvInfoDto.getSkillsTools())){ - for (VcSkillsToolsDto toolsDto : cvInfoDto.getSkillsTools()){ - skills.add(toolsDto.getContent()); - } - } - compatibilityVo.setSkills(skills); - HotakeCandidateCompatibilityDto compatibilityDto = aiCommonToolsService.handleCandidateCompatibility(compatibilityVo); - applyInfo.setCandidateCompatibilityJson(JSONUtil.toJsonStr(compatibilityDto)); - applyInfo.setCandidateCompatibilityScore(compatibilityDto.getOverallScore()); + 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(""); + evaluationVo.setQuestions(""); + evaluationVo.setAnswers(""); + evaluationVo.setTechnical(""); + evaluationVo.setCommunication(""); + evaluationVo.setSafetyAwareness(""); + evaluationVo.setProblemSolving(""); + + HotakeCandidateInterviewEvaluationDto evaluationDto = aiCommonToolsService.getCandidateInterviewEvaluation(evaluationVo); + applyInfo.setEvaluationJson(JSONUtil.toJsonStr(evaluationDto)); + applyInfo.setEvaluationScore(new BigDecimal(evaluationDto.getOverallScore())); applyInfo.setRecruiterId(rolesInf.getRecruiterId()); applyInfo.setStage(StageEnum.APPLIED.getCode()); diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java index 4def05e..f15fa88 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesApplyInfoServiceImpl.java @@ -105,6 +105,7 @@ public class HotakeRolesApplyInfoServiceImpl extends BaseServiceImpl implements List applyInfoList = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoList(hotakeRolesApplyInfo); if(CollectionUtil.isNotEmpty(applyInfoList)) { + List sysUserList = userService.selectUserList(new SysUser()); List screQuestionsReplyRecordInfoList = initScreQuestionsReplyRecordInfoMapper.selectHotakeInitScreQuestionsReplyRecordInfoList(new HotakeInitScreQuestionsReplyRecordInfo()); @@ -149,6 +150,12 @@ public class HotakeRolesApplyInfoServiceImpl extends BaseServiceImpl implements } applyInfo.setScreQuestionsReplyRecordInfoList(screQuestionsReplyRecordInfos); } + if(applyInfo.getCandidateId() != null){ + List userList = sysUserList.stream().filter(e->e.getUserId().longValue() == applyInfo.getCandidateId().longValue()).toList(); + if(CollectionUtil.isNotEmpty(userList)) { + applyInfo.setCandidateUSer(userList.get(0)); + } + } } } return applyInfoList; diff --git a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java index dd2283d..75fdd94 100644 --- a/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java +++ b/vetti-hotakes/src/main/java/com/vetti/hotake/service/impl/HotakeRolesInfoServiceImpl.java @@ -16,10 +16,12 @@ import com.vetti.common.utils.SecurityUtils; import com.vetti.common.utils.uuid.IdUtils; import com.vetti.hotake.domain.HotakeAiInterviewQuestionsInfo; import com.vetti.hotake.domain.HotakeInitialScreeningQuestionsInfo; +import com.vetti.hotake.domain.HotakeRolesApplyInfo; import com.vetti.hotake.domain.HotakeRolesInfo; import com.vetti.hotake.domain.dto.AiQuestionDto; import com.vetti.hotake.domain.dto.HotakeRolesInfoDto; import com.vetti.hotake.domain.dto.roleDto.*; +import com.vetti.hotake.mapper.HotakeRolesApplyInfoMapper; import com.vetti.hotake.mapper.HotakeRolesInfoMapper; import com.vetti.hotake.service.IHotakeAiInterviewQuestionsInfoService; import com.vetti.hotake.service.IHotakeInitialScreeningQuestionsInfoService; @@ -48,6 +50,9 @@ public class HotakeRolesInfoServiceImpl extends BaseServiceImpl implements IHota @Autowired private SysUserMapper sysUserMapper; + @Autowired + private HotakeRolesApplyInfoMapper hotakeRolesApplyInfoMapper; + @Autowired private IHotakeInitialScreeningQuestionsInfoService hotakeInitialScreeningQuestionsInfoService; @@ -144,13 +149,30 @@ public class HotakeRolesInfoServiceImpl extends BaseServiceImpl implements IHota @Override public List selectHotakeRolesInfoList(HotakeRolesInfo hotakeRolesInfo) { - List rolesInfoList = hotakeRolesInfoMapper.selectHotakeRolesInfoList(hotakeRolesInfo); //计算一个发布日期 if(CollectionUtil.isNotEmpty(rolesInfoList)){ + List applyInfoList = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoList(new HotakeRolesApplyInfo()); + + List sysUserList = sysUserMapper.selectUserList(new SysUser()); for (HotakeRolesInfo rolesInfo : rolesInfoList) { String posted = DateUtils.getTimeAgo(rolesInfo.getCreateTime()); rolesInfo.setPosted(posted); + + if(CollectionUtil.isNotEmpty(applyInfoList)){ + List applyInfos = applyInfoList.stream().filter(e->e.getRoleId().longValue() == rolesInfo.getId().longValue()).toList(); + if(CollectionUtil.isNotEmpty(applyInfos)){ + for (HotakeRolesApplyInfo applyInfo : applyInfos) { + if(applyInfo.getCandidateId() != null){ + List userList = sysUserList.stream().filter(e->e.getUserId().longValue() == applyInfo.getCandidateId().longValue()).toList(); + if(CollectionUtil.isNotEmpty(userList)) { + applyInfo.setCandidateUSer(userList.get(0)); + } + } + } + rolesInfo.setRolesApplyInfoList(applyInfos); + } + } } } return rolesInfoList; diff --git a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml index ed73873..9ca90a7 100644 --- a/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml +++ b/vetti-hotakes/src/main/resources/mapper/hotake/HotakeRolesApplyInfoMapper.xml @@ -32,6 +32,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + + + + + @@ -44,7 +51,8 @@ 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, 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,candidate_compatibility_score, + ai_match_score_percentage,status, ai_cv_scoring_ranking_json,ai_cv_score,candidate_compatibility_json, + candidate_compatibility_score,evaluation_json,evaluation_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 @@ -178,6 +186,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" candidate_compatibility_json, candidate_compatibility_score, + evaluation_json, + evaluation_score, + + ai_interview_analysis_json, + ai_interview_analysis_qa_json, + del_flag, create_by, create_time, @@ -212,6 +226,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{candidateCompatibilityJson}, #{candidateCompatibilityScore}, + #{evaluationJson}, + #{evaluationScore}, + + #{aiInterviewAnalysisJson}, + #{aiInterviewAnalysisQaJson}, + #{delFlag}, #{createBy}, #{createTime}, @@ -250,6 +270,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" candidate_compatibility_json = #{candidateCompatibilityJson}, candidate_compatibility_score = #{candidateCompatibilityScore}, + evaluation_json = #{evaluationJson}, + evaluation_score = #{evaluationScore}, + + ai_interview_analysis_json = #{aiInterviewAnalysisJson}, + ai_interview_analysis_qa_json = #{aiInterviewAnalysisQaJson}, + del_flag = #{delFlag}, create_by = #{createBy}, create_time = #{createTime},