AI 逻辑调整

This commit is contained in:
2026-01-21 00:13:30 +08:00
parent 17f99f229d
commit 474a71c4db
12 changed files with 235 additions and 14 deletions

View File

@@ -187,19 +187,19 @@ public class HotakeAiCommonToolsController extends BaseController {
*/
@ApiOperation("候选人AI面试分析")
@PostMapping(value = "/candidateAiInterviewAnalysis")
public R<?> candidateAiInterviewAnalysis(@RequestBody HotakeCandidateAiInterviewAnalysisVo analysisVo)
public R<HotakeCandidateAiInterviewAnalysisDto> candidateAiInterviewAnalysis(@RequestBody HotakeCandidateAiInterviewAnalysisVo analysisVo)
{
return R.ok(hotakeAiCommonToolsService.handleCandidateAiInterviewAnalysis(analysisVo));
}
/**
* 招聘者AI简历评分和排名系统
* 招聘者 AI简历评分和排名系统
*/
@ApiOperation("招聘者AI简历评分和排名系统")
@ApiOperation("招聘者 AI简历评分和排名系统")
@PostMapping(value = "/aiCvScoringRanking")
public R<?> aiCvScoringRanking(@RequestBody HotakeAiCvScoringRankingVo scoringRankingVo)
public R<?> aiCvScoringRanking(@RequestBody HotakeAiCvScoringRankingRoleApplyVo roleApplyVo)
{
return R.ok(hotakeAiCommonToolsService.handleAiCvScoringRanking(scoringRankingVo));
return R.ok(hotakeAiCommonToolsService.handleAiCvScoringRanking(roleApplyVo));
}
/**

View File

@@ -109,4 +109,6 @@ public class HotakeRolesApplyInfoController extends BaseController
hotakeRolesApplyInfoService.updateBatchEditStage(stageVoList);
return R.ok();
}
}

View File

@@ -17,6 +17,9 @@ import java.util.List;
@Accessors(chain = true)
public class HotakeAiInterviewScoringVo {
@ApiModelProperty("岗位申请ID")
private Long roleApplyId;
@ApiModelProperty("AI 面试问题记录 数据集合")
private List<HotakeAiInterviewQuestionRecordVo> aiInterviewQuestionRecordVoList;
}

View File

@@ -187,6 +187,9 @@ chatGpt:
modelPpg: gpt-4o-mini
modelRLinkAl: gpt-4o-mini
modelRLinkAl_1: gpt-4o-mini
modelAiIntPf: gpt-4o-mini
modelAiCvSr: gpt-4o-mini
modelAiCac: gpt-4o-mini
role: system
http:

View File

@@ -130,4 +130,7 @@ public class HotakeRolesApplyInfo extends BaseEntity
@ApiModelProperty("岗位申请操作记录数据集合")
private List<HotakeRolesApplyOperRecord> applyOperRecords;
@ApiModelProperty("岗位申请ID数据集合")
private List<Long> applyRoleIdList;
}

View File

@@ -0,0 +1,26 @@
package com.vetti.hotake.domain.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 候选人AI面试分析-优势点列表以及改进列表 返回对象
*
* @author ID
* @date 2025-09-06
*/
@Data
@Accessors(chain = true)
public class HotakeCandidateAiInterviewAnalysisAnalysisDto {
@ApiModelProperty("优势点列表")
private List<String> strengths;
@ApiModelProperty("改进建议列表")
private List<String> improvements;
}

View File

@@ -1,8 +1,12 @@
package com.vetti.hotake.domain.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
/**
* 候选人AI面试分析 返回对象
*
@@ -13,6 +17,25 @@ import lombok.experimental.Accessors;
@Accessors(chain = true)
public class HotakeCandidateAiInterviewAnalysisDto {
@ApiModelProperty("技术能力评分")
private BigDecimal technical;
@ApiModelProperty("沟通能力评分")
private BigDecimal communication;
@ApiModelProperty("文化契合评分")
private BigDecimal cultural;
@ApiModelProperty("技术能力-优势点列表以及改进列表")
private HotakeCandidateAiInterviewAnalysisAnalysisDto technicalDto;
@ApiModelProperty("沟通能力-优势点列表以及改进列表")
private HotakeCandidateAiInterviewAnalysisAnalysisDto communicationDto;
@ApiModelProperty("文化契合-优势点列表以及改进列表")
private HotakeCandidateAiInterviewAnalysisAnalysisDto culturalDto;
@ApiModelProperty("具体描述列表")
private List<HotakeCandidateAiInterviewAnalysisNotesDto> notesDtoList;
}

View File

@@ -0,0 +1,23 @@
package com.vetti.hotake.domain.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 候选人AI面试分析-具体描述 返回对象
*
* @author ID
* @date 2025-09-06
*/
@Data
@Accessors(chain = true)
public class HotakeCandidateAiInterviewAnalysisNotesDto {
@ApiModelProperty("笔记类型")
private String type;
@ApiModelProperty("笔记内容 ")
private String content;
}

View File

@@ -0,0 +1,21 @@
package com.vetti.hotake.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 招聘者AI简历评分和排名系统-岗位申请 请求对象
*
* @author wangxiangshun
* @date 2026-01-17
*/
@Data
@Accessors(chain = true)
public class HotakeAiCvScoringRankingRoleApplyVo {
@ApiModelProperty("岗位申请ID集合")
private List<Long> roleApplyIds;
}

View File

@@ -16,6 +16,9 @@ import java.util.List;
@Accessors(chain = true)
public class HotakeCandidateAiInterviewAnalysisVo {
@ApiModelProperty("岗位申请ID")
private Long roleApplyId;
@ApiModelProperty("面试岗位")
private String position;

View File

@@ -133,15 +133,15 @@ public interface IHotakeAiCommonToolsService {
* @param analysisVo 候选人AI面试分析信息
* @return
*/
public String handleCandidateAiInterviewAnalysis(HotakeCandidateAiInterviewAnalysisVo analysisVo);
public HotakeCandidateAiInterviewAnalysisDto handleCandidateAiInterviewAnalysis(HotakeCandidateAiInterviewAnalysisVo analysisVo);
/**
* 招聘者AI简历评分和排名系统
* @param scoringRankingVo 招聘者AI简历评分和排名系统输入信息
* @param roleApplyVo 岗位申请数据对象
* @return
*/
public String handleAiCvScoringRanking(HotakeAiCvScoringRankingVo scoringRankingVo);
public String handleAiCvScoringRanking(HotakeAiCvScoringRankingRoleApplyVo roleApplyVo);
/**

View File

@@ -2,6 +2,7 @@ package com.vetti.hotake.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.vetti.common.ai.gpt.ChatGPTClient;
import com.vetti.common.constant.AiCommonPromptConstants;
@@ -9,10 +10,12 @@ import com.vetti.common.core.domain.entity.SysUser;
import com.vetti.common.core.service.BaseServiceImpl;
import com.vetti.common.enums.FillTypeEnum;
import com.vetti.common.enums.RoleBenefitsEnum;
import com.vetti.common.exception.ServiceException;
import com.vetti.common.utils.SecurityUtils;
import com.vetti.common.utils.html.ReadHtmlByOkHttp;
import com.vetti.hotake.domain.HotakeInitScreQuestionsReplyRecordInfo;
import com.vetti.hotake.domain.HotakeInitialScreeningQuestionsInfo;
import com.vetti.hotake.domain.HotakeRolesApplyInfo;
import com.vetti.hotake.domain.HotakeRolesInfo;
import com.vetti.hotake.domain.dto.*;
import com.vetti.hotake.domain.dto.VcDto.*;
@@ -30,6 +33,7 @@ import org.springframework.stereotype.Service;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/**
* AI共通工具 信息Service业务层处理
@@ -994,10 +998,9 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
* @return
*/
@Override
public String handleCandidateAiInterviewAnalysis(HotakeCandidateAiInterviewAnalysisVo analysisVo) {
public HotakeCandidateAiInterviewAnalysisDto handleCandidateAiInterviewAnalysis(HotakeCandidateAiInterviewAnalysisVo analysisVo) {
HotakeCandidateAiInterviewAnalysisDto analysisDto = new HotakeCandidateAiInterviewAnalysisDto();
String prompt = AiCommonPromptConstants.initializationCandidateAiInterviewAnalysisPrompt();
String qa = "";
if(CollectionUtil.isNotEmpty(analysisVo.getAiInterviewQuestionRecordVoList())){
for(HotakeAiInterviewQuestionRecordVo recordVo : analysisVo.getAiInterviewQuestionRecordVoList()){
@@ -1009,7 +1012,6 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
}
}
}
String userPrompt_1 = "Please conduct an interview analysis based on the questions answered by the following candidates\n" +
"\n" +
"**Job Information**\n" +
@@ -1032,8 +1034,57 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
String resultStrOne = chatGPTClient.handleAiChat(promptJsonOne,"AIINTPF");
String resultJsonOne = resultStrOne.replaceAll("```json","").replaceAll("```","");
log.info("候选人AI面试分析结果:{}",resultJsonOne);
if(StrUtil.isNotEmpty(resultJsonOne)){
try {
Map dataMap = JSONUtil.toBean(resultJsonOne,Map.class);
Map scoresMap = (Map)dataMap.get("scores");
analysisDto.setTechnical(new BigDecimal(scoresMap.get("technical").toString()));
analysisDto.setCommunication(new BigDecimal(scoresMap.get("communication").toString()));
analysisDto.setCultural(new BigDecimal(scoresMap.get("cultural").toString()));
return resultJsonOne;
Map analysisMap = (Map)dataMap.get("analysis");
Map technicalMap = (Map)analysisMap.get("technical");
HotakeCandidateAiInterviewAnalysisAnalysisDto technicalDto = new HotakeCandidateAiInterviewAnalysisAnalysisDto();
List<String> improvements = (List<String>)technicalMap.get("improvements");
List<String> strengths = (List<String>)technicalMap.get("strengths");
technicalDto.setImprovements(improvements);
technicalDto.setStrengths(strengths);
analysisDto.setTechnicalDto(technicalDto);
Map communicationMap = (Map)analysisMap.get("communication");
HotakeCandidateAiInterviewAnalysisAnalysisDto communicationDto = new HotakeCandidateAiInterviewAnalysisAnalysisDto();
List<String> improvements1 = (List<String>)communicationMap.get("improvements");
List<String> strengths1 = (List<String>)communicationMap.get("strengths");
communicationDto.setImprovements(improvements1);
communicationDto.setStrengths(strengths1);
analysisDto.setCommunicationDto(communicationDto);
Map culturalMap = (Map)analysisMap.get("cultural");
HotakeCandidateAiInterviewAnalysisAnalysisDto culturalDto = new HotakeCandidateAiInterviewAnalysisAnalysisDto();
List<String> improvements2 = (List<String>)culturalMap.get("improvements");
List<String> strengths2 = (List<String>)culturalMap.get("strengths");
culturalDto.setImprovements(improvements2);
culturalDto.setStrengths(strengths2);
analysisDto.setCulturalDto(culturalDto);
List<HotakeCandidateAiInterviewAnalysisNotesDto> notesDtoList = new ArrayList<>();
List<Map> notesMapList = (List<Map>)dataMap.get("notes");
if(CollectionUtil.isNotEmpty(notesMapList)){
for(Map noteMap : notesMapList){
HotakeCandidateAiInterviewAnalysisNotesDto analysisNotesDto = new HotakeCandidateAiInterviewAnalysisNotesDto();
analysisNotesDto.setType(noteMap.get("type").toString());
analysisNotesDto.setContent(noteMap.get("content").toString());
notesDtoList.add(analysisNotesDto);
}
}
analysisDto.setNotesDtoList(notesDtoList);
}catch (Exception e){
throw new ServiceException("No rating");
}
}
//todo 把面试结果分析保存到记录表中
return analysisDto;
}
/**
@@ -1042,7 +1093,68 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
* @return
*/
@Override
public String handleAiCvScoringRanking(HotakeAiCvScoringRankingVo scoringRankingVo) {
public String handleAiCvScoringRanking(HotakeAiCvScoringRankingRoleApplyVo roleApplyVo) {
if(CollectionUtil.isEmpty(roleApplyVo.getRoleApplyIds()) || roleApplyVo.getRoleApplyIds().size() < 2){
throw new ServiceException("Please select at least two pieces of data");
}
//根据岗位申请Id查询岗位申请数据信息列表
HotakeRolesApplyInfo queryApplyInfo = new HotakeRolesApplyInfo();
queryApplyInfo.setApplyRoleIdList(roleApplyVo.getRoleApplyIds());
List<HotakeRolesApplyInfo> applyInfoList = hotakeRolesApplyInfoMapper.selectHotakeRolesApplyInfoList(queryApplyInfo);
List<Long> roleIds = applyInfoList.stream().map(HotakeRolesApplyInfo::getRoleId).collect(Collectors.toList());;
Set<Long> setDatas = new HashSet<>();
setDatas.addAll(roleIds);
if(setDatas.size() > 1){
throw new ServiceException("Only data from the same position can be selected");
}
HotakeRolesInfo rolesInfo = hotakeRolesInfoMapper.selectHotakeRolesInfoById(roleIds.get(0));
HotakeAiCvScoringRankingVo scoringRankingVo = new HotakeAiCvScoringRankingVo();
scoringRankingVo.setTitle(rolesInfo.getRoleName());
scoringRankingVo.setDescription(rolesInfo.getAboutRole());
List<RequiredSkillsDto> requiredSkillsList = JSONUtil.toList(rolesInfo.getRequiredSkillsJson(),RequiredSkillsDto.class);
List<String> requiredSkills = new ArrayList<>();
if(CollectionUtil.isNotEmpty(requiredSkillsList)){
for (RequiredSkillsDto requiredSkillsDto : requiredSkillsList) {
requiredSkills.add(requiredSkillsDto.getKeyValue());
}
}
List<NiceToHaveSkillsDto> niceToHaveSkillsList = JSONUtil.toList(rolesInfo.getNiceToHaveSkillsJson(),NiceToHaveSkillsDto.class);
List<String> niceToHaveSkills = new ArrayList<>();
if(CollectionUtil.isNotEmpty(niceToHaveSkillsList)){
for (NiceToHaveSkillsDto haveSkillsDto : niceToHaveSkillsList) {
niceToHaveSkills.add(haveSkillsDto.getKeyValue());
}
}
scoringRankingVo.setRequiredSkills(requiredSkills);
scoringRankingVo.setNiceToHaveSkills(niceToHaveSkills);
scoringRankingVo.setExperienceRequired(rolesInfo.getJobExperience());
EducationRequirementsDto educationRequirements = JSONUtil.toBean(rolesInfo.getEducationRequirementsJson(),EducationRequirementsDto.class);
scoringRankingVo.setEducationRequired(educationRequirements.getDegree()+","+educationRequirements.getAcademicMajor());
List<HotakeCandidateVcInfoVo> candidates = new ArrayList<>();
for(HotakeRolesApplyInfo applyInfo : applyInfoList){
HotakeCvInfoDto cvInfoDto = JSONUtil.toBean(applyInfo.getCvTemplateJson(), HotakeCvInfoDto.class);
HotakeCandidateVcInfoVo infoVo = new HotakeCandidateVcInfoVo();
infoVo.setName(cvInfoDto.getName());
infoVo.setCurrentPosition(cvInfoDto.getPosition());
infoVo.setWorkExperience(JSONUtil.toJsonStr(cvInfoDto.getExperience()));
infoVo.setEducation(JSONUtil.toJsonStr(cvInfoDto.getEducation()));
List<String> skills = new ArrayList<>();
if(CollectionUtil.isNotEmpty(cvInfoDto.getSkillsTools())){
for (VcSkillsToolsDto skillsToolsDto : cvInfoDto.getSkillsTools()) {
skills.add(skillsToolsDto.getContent());
}
}
infoVo.setSkills(skills);
infoVo.setSummary(cvInfoDto.getAbout());
candidates.add(infoVo);
}
scoringRankingVo.setCandidates(candidates);
String prompt = AiCommonPromptConstants.initializationAiCvScoringRankingPrompt();
String userPrompt_1 = JSONUtil.toJsonStr(scoringRankingVo);
@@ -1061,6 +1173,8 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
String resultJsonOne = resultStrOne.replaceAll("```json","").replaceAll("```","");
log.info("招聘者AI简历评分和排名系统结果:{}",resultJsonOne);
return resultJsonOne;
}