候选人AI面试分析

This commit is contained in:
2026-01-19 22:28:47 +08:00
parent 62de85c6e0
commit 2f76084d98
18 changed files with 410 additions and 16 deletions

View File

@@ -74,11 +74,11 @@ public class HotakeRolesApplyInfo extends BaseEntity
private String coverLetter;
/** 候选人状态Hot、Warm、Cold、Pending */
@ApiModelProperty("候选人状态(Hot、Warm、Cold、Pending")
@ApiModelProperty("候选人状态(hot、warm、cold、pending")
private String candidateStatus;
/** 当前阶段 */
@ApiModelProperty("当前阶段(Applied:已申请,Shortlisted:入围,Interview:面试,Offer邀约Hired受雇,refuseOffer:拒绝邀约,InterviewFail面试失败)")
@ApiModelProperty("当前阶段(applied:已申请,shortlisted:入围,interview:面试,offer邀约hired受雇,refuseOffer:拒绝邀约,interviewFail面试失败)")
@Excel(name = "当前阶段")
private String stage;
@@ -118,7 +118,7 @@ public class HotakeRolesApplyInfo extends BaseEntity
private BigDecimal aiMatchScorePercentage;
/** 申请状态pending:进行中complete已完成Canceled取消 */
@ApiModelProperty("申请状态pending:进行中complete已完成Canceled取消")
@ApiModelProperty("申请状态pending:进行中complete已完成canceled取消")
private String status;
@ApiModelProperty("岗位信息")

View File

@@ -35,8 +35,8 @@ public class HotakeRolesApplyOperRecord extends BaseEntity
private Long roleApplyId;
/** 当前阶段 */
@ApiModelProperty("当前阶段")
@Excel(name = "当前阶段")
@ApiModelProperty("阶段")
@Excel(name = "阶段")
private String applyStage;
@ApiModelProperty("岗位申请Id数据集合")

View File

@@ -0,0 +1,18 @@
package com.vetti.hotake.domain.dto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 候选人AI面试分析 返回对象
*
* @author ID
* @date 2025-09-06
*/
@Data
@Accessors(chain = true)
public class HotakeCandidateAiInterviewAnalysisDto {
}

View File

@@ -0,0 +1,22 @@
package com.vetti.hotake.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* AI 面试问题记录 信息对象
*
* @author wangxiangshun
* @date 2026-01-17
*/
@Data
@Accessors(chain = true)
public class HotakeAiInterviewQuestionRecordVo {
@ApiModelProperty("用户类型(user:候选者,assistant:面试者AI)")
private String userType;
@ApiModelProperty("语音转义内容")
private String contentText;
}

View File

@@ -0,0 +1,25 @@
package com.vetti.hotake.domain.vo;
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 HotakeCandidateAiInterviewAnalysisVo {
@ApiModelProperty("面试岗位")
private String position;
@ApiModelProperty("AI 面试问题记录 数据集合")
private List<HotakeAiInterviewQuestionRecordVo> aiInterviewQuestionRecordVoList;
}

View File

@@ -0,0 +1,23 @@
package com.vetti.hotake.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 岗位申请阶段处理 请求对象
*
* @author ID
* @date 2025-09-06
*/
@Data
@Accessors(chain = true)
public class HotakeRolesApplyStageVo {
@ApiModelProperty("岗位申请Id")
private Long roleApplyId;
@ApiModelProperty("当前阶段")
private String stage;
}

View File

@@ -128,5 +128,11 @@ public interface IHotakeAiCommonToolsService {
public String getAiInterviewQuestions(HotakeRolesInfo rolesInfo);
/**
* 候选人AI面试分析
* @param analysisVo 候选人AI面试分析信息
* @return
*/
public String handleCandidateAiInterviewAnalysis(HotakeCandidateAiInterviewAnalysisVo analysisVo);
}

View File

@@ -2,6 +2,7 @@ package com.vetti.hotake.service;
import java.util.List;
import com.vetti.hotake.domain.HotakeRolesApplyInfo;
import com.vetti.hotake.domain.vo.HotakeRolesApplyStageVo;
/**
* 候选人岗位申请信息Service接口
@@ -67,4 +68,13 @@ public interface IHotakeRolesApplyInfoService
*/
public int batchInsertHotakeRolesApplyInfo(List<HotakeRolesApplyInfo> hotakeRolesApplyInfoList);
/**
* 修改候选人岗位申请信息
*
* @param stageVoList 候选人岗位申请信息
* @return 结果
*/
public int updateBatchEditStage(List<HotakeRolesApplyStageVo> stageVoList);
}

View File

@@ -988,4 +988,52 @@ public class HotakeAiCommonToolsServiceImpl extends BaseServiceImpl implements I
return resultJsonOne;
}
/**
* 候选人AI面试分析
* @param rolesInfo 候选人AI面试分析信息
* @return
*/
@Override
public String handleCandidateAiInterviewAnalysis(HotakeCandidateAiInterviewAnalysisVo analysisVo) {
String prompt = AiCommonPromptConstants.initializationCandidateAiInterviewAnalysisPrompt();
String qa = "";
if(CollectionUtil.isNotEmpty(analysisVo.getAiInterviewQuestionRecordVoList())){
for(HotakeAiInterviewQuestionRecordVo recordVo : analysisVo.getAiInterviewQuestionRecordVoList()){
if("assistant".equals(recordVo.getUserType())){
qa = qa + "Question:"+recordVo.getContentText();
}
if("user".equals(recordVo.getUserType())){
qa = qa + "Answer:"+recordVo.getContentText();
}
}
}
String userPrompt_1 = "Please conduct an interview analysis based on the questions answered by the following candidates\n" +
"\n" +
"**Job Information**\n" +
"Position"+analysisVo.getPosition()+"\n" +
"Question And Answer"+qa+"\n"+
"Please return the analysis results in the required JSON format.";
log.info("AI面试问题生成:{}",userPrompt_1);
//处理岗位信息补充
List<Map<String, String>> listOne = new LinkedList();
Map<String, String> mapEntityOne = new HashMap<>();
mapEntityOne.put("role", "system");
mapEntityOne.put("content",prompt);
listOne.add(mapEntityOne);
Map<String, String> mapUserEntityOne = new HashMap<>();
mapUserEntityOne.put("role", "user");
mapUserEntityOne.put("content",userPrompt_1);
listOne.add(mapUserEntityOne);
String promptJsonOne = JSONUtil.toJsonStr(listOne);
String resultStrOne = chatGPTClient.handleAiChat(promptJsonOne,"AIINTPF");
String resultJsonOne = resultStrOne.replaceAll("```json","").replaceAll("```","");
log.info("候选人AI面试分析结果:{}",resultJsonOne);
return resultJsonOne;
}
}

View File

@@ -13,6 +13,7 @@ import com.vetti.hotake.domain.HotakeRolesApplyOperRecord;
import com.vetti.hotake.domain.HotakeRolesInfo;
import com.vetti.hotake.domain.dto.HotakeCvInfoDto;
import com.vetti.hotake.domain.dto.VcDto.*;
import com.vetti.hotake.domain.vo.HotakeRolesApplyStageVo;
import com.vetti.hotake.mapper.HotakeRolesApplyInfoMapper;
import com.vetti.hotake.mapper.HotakeRolesInfoMapper;
import com.vetti.hotake.service.IHotakeRolesApplyInfoService;
@@ -334,4 +335,40 @@ public class HotakeRolesApplyInfoServiceImpl extends BaseServiceImpl implements
return new HotakeCvInfoDto();
}
/**
* 修改候选人岗位申请信息
*
* @param hotakeRolesApplyInfo 候选人岗位申请信息
* @return 结果
*/
@Transactional(rollbackFor=Exception.class)
@Override
public int updateBatchEditStage(List<HotakeRolesApplyStageVo> stageVoList)
{
int resultNum = 0;
if(CollectionUtil.isNotEmpty(stageVoList)){
for(HotakeRolesApplyStageVo stageVo : stageVoList){
HotakeRolesApplyInfo hotakeRolesApplyInfo = new HotakeRolesApplyInfo();
hotakeRolesApplyInfo.setId(stageVo.getRoleApplyId());
hotakeRolesApplyInfo.setStage(stageVo.getStage());
fill(FillTypeEnum.UPDATE.getCode(), hotakeRolesApplyInfo);
resultNum = hotakeRolesApplyInfoMapper.updateHotakeRolesApplyInfo(hotakeRolesApplyInfo);
HotakeRolesApplyOperRecord query = new HotakeRolesApplyOperRecord();
query.setRoleApplyId(hotakeRolesApplyInfo.getId()).setApplyStage(hotakeRolesApplyInfo.getStage());
List<HotakeRolesApplyOperRecord> applyOperRecords = rolesApplyOperRecordService.selectHotakeRolesApplyOperRecordList(query);
if(CollectionUtil.isEmpty(applyOperRecords)) {
StageEnum stageEnum = StageEnum.getByInfo(hotakeRolesApplyInfo.getStage());
if(stageEnum != null){
HotakeRolesApplyOperRecord hotakeRolesApplyOperRecord = new HotakeRolesApplyOperRecord();
hotakeRolesApplyOperRecord.setApplyStage(hotakeRolesApplyInfo.getStage());
hotakeRolesApplyOperRecord.setRoleApplyId(hotakeRolesApplyInfo.getId());
hotakeRolesApplyOperRecord.setRoleId(hotakeRolesApplyInfo.getRoleId());
rolesApplyOperRecordService.insertHotakeRolesApplyOperRecord(hotakeRolesApplyOperRecord);
}
}
}
}
return resultNum;
}
}